Anapher / Hurricane

The music player with style
GNU General Public License v3.0
130 stars 56 forks source link

Import playlists (m3u, cue sheet) #3

Closed mikekov closed 9 years ago

mikekov commented 9 years ago

I have implemented import of m3u and cue sheet playlists, but I had to hack LocalTrack. Before I fork the repo I'd like to find out if you are interested in playlist import feature. M3u import is easy enough, but for a cue sheet I need LocalTrack changes (offset to play from and the way track info is refreshed). There are different ways to do that, so I'd like to coordinate this effort, if there's interest. Thanks!

Anapher commented 9 years ago

I think that playlist import would be a nice feature (was already asked by some users) and if you've already implemented that, feel free to make a pull request ;)

mikekov commented 9 years ago

OK, I'll fork the repo and implement this feature. For cue sheets support I introduced LocalTrackFragment class, but I'm not happy with this approach. I need to rethink it. If you have any ideas how to support local tracks that start playback from given offset and have limited duration, let me know.

Anapher commented 9 years ago

Hi, I have a solution for that. The creator of the audio library, filoe, helped me a little bit and I created this class:

    class CutSource : WaveAggregatorBase
    {
        public CutSource(IWaveSource source, TimeSpan startPosition, TimeSpan trackLength)
            : base(source)
        {
            StartPosition = startPosition;
            TrackLength = trackLength;
        }

        public TimeSpan StartPosition { get; set; }
        public TimeSpan TrackLength { get; set; }

        public override int Read(byte[] buffer, int offset, int count)
        {
            var position = TimeSpan.FromMilliseconds(this.GetMilliseconds(base.Position));
            if (position.Seconds < StartPosition.Seconds) Position = 0;
            if (position.Seconds > StartPosition.Seconds + TrackLength.Seconds) return 0;

            return base.Read(buffer, offset, count);
        }

        public override long Length
        {
            get { return this.GetBytes(TrackLength); }
        }

        public override long Position
        {
            get { return base.Position - this.GetBytes(StartPosition); }
            set { base.Position = value + this.GetBytes(StartPosition); }
        }
    }

It defines which range from the track should be played. Because a track have to return the SoundSource, we can just make a new class called PlaylistTrack which inherits from LocalTrack and add TrackStartTime (int, secounds) and TrackLength (int, secounds) (for example). Than override GetSoundSource() to:

        public override Task<IWaveSource> GetSoundSource()
        {
            return Task.Run(() => (IWaveSource)CodecFactory.Instance.GetCodec(Path).AppendSource(x => new CutSource(x, TimeSpan.FromSeconds(TrackStart), TimeSpan.FromSeconds(TrackLength))));
        }

and everything is awesome! :)

mikekov commented 9 years ago

Thank you, I'll incorporate this change in my fork.