public SampleChannelBass(Sample sample, Action <SampleChannel> onPlay) : base(sample, onPlay) { relativeFrequencyHandler = new BassRelativeFrequencyHandler { FrequencyChangedToZero = () => Bass.ChannelPause(channel), FrequencyChangedFromZero = () => Bass.ChannelPlay(channel), }; }
public SampleChannelBass(SampleBass sample) { this.sample = sample; relativeFrequencyHandler = new BassRelativeFrequencyHandler { FrequencyChangedToZero = stopChannel, FrequencyChangedFromZero = () => { // Only unpause if the channel has been played by the user. if (userRequestedPlay) { playChannel(); } }, }; ensureChannel(); }
public TrackBass(Stream data, bool quick = false) { if (data == null) { throw new ArgumentNullException(nameof(data)); } relativeFrequencyHandler = new BassRelativeFrequencyHandler { FrequencyChangedToZero = () => stopInternal(), FrequencyChangedFromZero = () => { // Do not resume the track if a play wasn't requested at all or has been paused via Stop(). if (!isPlayed) { return; } startInternal(); } }; // todo: support this internally to match the underlying Track implementation (which can support this). const float tempo_minimum_supported = 0.05f; AggregateTempo.ValueChanged += t => { if (t.NewValue < tempo_minimum_supported) { throw new ArgumentException($"{nameof(TrackBass)} does not support {nameof(Tempo)} specifications below {tempo_minimum_supported}. Use {nameof(Frequency)} instead."); } }; EnqueueAction(() => { Preview = quick; activeStream = prepareStream(data, quick); long byteLength = Bass.ChannelGetLength(activeStream); // will be -1 in case of an error double seconds = Bass.ChannelBytes2Seconds(activeStream, byteLength); bool success = seconds >= 0; if (success) { Length = seconds * 1000; // Bass does not allow seeking to the end of the track, so the last available position is 1 sample before. lastSeekablePosition = Bass.ChannelBytes2Seconds(activeStream, byteLength - BYTES_PER_SAMPLE) * 1000; isLoaded = true; relativeFrequencyHandler.SetChannel(activeStream); } }); InvalidateState(); }
/// <summary> /// Constructs a new <see cref="TrackBass"/> from provided audio data. /// </summary> /// <param name="data">The sample data stream.</param> /// <param name="quick">If true, the track will not be fully loaded, and should only be used for preview purposes. Defaults to false.</param> public TrackBass(Stream data, bool quick = false) { if (data == null) { throw new ArgumentNullException(nameof(data)); } relativeFrequencyHandler = new BassRelativeFrequencyHandler { FrequencyChangedToZero = () => stopInternal(), FrequencyChangedFromZero = () => { // Do not resume the track if a play wasn't requested at all or has been paused via Stop(). if (!isPlayed) { return; } startInternal(); } }; // todo: support this internally to match the underlying Track implementation (which can support this). const float tempo_minimum_supported = 0.05f; AggregateTempo.ValueChanged += t => { if (t.NewValue < tempo_minimum_supported) { throw new ArgumentException($"{nameof(TrackBass)} does not support {nameof(Tempo)} specifications below {tempo_minimum_supported}. Use {nameof(Frequency)} instead."); } }; EnqueueAction(() => { Preview = quick; activeStream = prepareStream(data, quick); long byteLength = Bass.ChannelGetLength(activeStream); // will be -1 in case of an error double seconds = Bass.ChannelBytes2Seconds(activeStream, byteLength); bool success = seconds >= 0; if (success) { Length = seconds * 1000; // Bass does not allow seeking to the end of the track, so the last available position is 1 sample before. lastSeekablePosition = Bass.ChannelBytes2Seconds(activeStream, byteLength - BYTES_PER_SAMPLE) * 1000; bitrate = (int)Bass.ChannelGetAttribute(activeStream, ChannelAttribute.Bitrate); stopCallback = new SyncCallback((a, b, c, d) => RaiseFailed()); endCallback = new SyncCallback((a, b, c, d) => { if (Looping) { return; } hasCompleted = true; RaiseCompleted(); }); endMixtimeCallback = new SyncCallback((a, b, c, d) => { // this is separate from the above callback as this is required to be invoked on mixtime. // see "BASS_SYNC_MIXTIME" part of http://www.un4seen.com/doc/#bass/BASS_ChannelSetSync.html for reason why. if (Looping) { seekInternal(RestartPoint); } }); Bass.ChannelSetSync(activeStream, SyncFlags.Stop, 0, stopCallback.Callback, stopCallback.Handle); Bass.ChannelSetSync(activeStream, SyncFlags.End, 0, endCallback.Callback, endCallback.Handle); Bass.ChannelSetSync(activeStream, SyncFlags.End | SyncFlags.Mixtime, 0, endMixtimeCallback.Callback, endMixtimeCallback.Handle); isLoaded = true; relativeFrequencyHandler.SetChannel(activeStream); bassAmplitudeProcessor?.SetChannel(activeStream); } }); InvalidateState(); }