private int prepareStream(Stream data, bool quick) { //encapsulate incoming stream with async buffer if it isn't already. dataStream = data as AsyncBufferStream ?? new AsyncBufferStream(data, quick ? 8 : -1); fileCallbacks = new FileCallbacks(new DataStreamFileProcedures(dataStream)); BassFlags flags = Preview ? 0 : BassFlags.Decode | BassFlags.Prescan; int stream = Bass.CreateStream(StreamSystem.NoBuffer, flags, fileCallbacks.Callbacks, fileCallbacks.Handle); if (!Preview) { // We assign the BassFlags.Decode streams to the device "bass_nodevice" to prevent them from getting // cleaned up during a Bass.Free call. This is necessary for seamless switching between audio devices. // Further, we provide the flag BassFlags.FxFreeSource such that freeing the stream also frees // all parent decoding streams. const int bass_nodevice = 0x20000; Bass.ChannelSetDevice(stream, bass_nodevice); tempoAdjustStream = BassFx.TempoCreate(stream, BassFlags.Decode | BassFlags.FxFreeSource); Bass.ChannelSetDevice(tempoAdjustStream, bass_nodevice); stream = BassFx.ReverseCreate(tempoAdjustStream, 5f, BassFlags.Default | BassFlags.FxFreeSource); Bass.ChannelSetAttribute(stream, ChannelAttribute.TempoUseQuickAlgorithm, 1); Bass.ChannelSetAttribute(stream, ChannelAttribute.TempoOverlapMilliseconds, 4); Bass.ChannelSetAttribute(stream, ChannelAttribute.TempoSequenceMilliseconds, 30); } return(stream); }
protected override void Dispose(bool disposing) { if (activeStream != 0) { isRunning = false; Bass.ChannelStop(activeStream); Bass.StreamFree(activeStream); } activeStream = 0; dataStream?.Dispose(); dataStream = null; fileCallbacks?.Dispose(); fileCallbacks = null; stopCallback?.Dispose(); stopCallback = null; endCallback?.Dispose(); endCallback = null; base.Dispose(disposing); }
public AudioTrackBass(Stream data, bool quick = false) { Preview = quick; BassFlags flags = Preview ? 0 : (BassFlags.Decode | BassFlags.Prescan); if (data == null) throw new ArgumentNullException(@"Data couldn't be loaded!"); //encapsulate incoming stream with async buffer if it isn't already. dataStream = data as AsyncBufferStream ?? new AsyncBufferStream(data, quick ? 8 : -1); procs = new DataStreamFileProcedures(dataStream); audioStreamPrefilter = Bass.CreateStream(StreamSystem.NoBuffer, flags, procs.BassProcedures, IntPtr.Zero); if (Preview) activeStream = audioStreamPrefilter; else { activeStream = BassFx.TempoCreate(audioStreamPrefilter, BassFlags.Decode); activeStream = BassFx.ReverseCreate(activeStream, 5f, BassFlags.Default); Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoUseQuickAlgorithm, 1); Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoOverlapMilliseconds, 4); Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoSequenceMilliseconds, 30); } Length = (Bass.ChannelBytes2Seconds(activeStream, Bass.ChannelGetLength(activeStream)) * 1000); Bass.ChannelGetAttribute(activeStream, ChannelAttribute.Frequency, out initialFrequency); }
/// <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) { EnqueueAction(() => { Preview = quick; if (data == null) { throw new ArgumentNullException(nameof(data)); } //encapsulate incoming stream with async buffer if it isn't already. dataStream = data as AsyncBufferStream ?? new AsyncBufferStream(data, quick ? 8 : -1); procedures = CreateDataStreamFileProcedures(dataStream); if (!RuntimeInfo.SupportsIL) { pinnedProcedures = GCHandle.Alloc(procedures, GCHandleType.Pinned); } BassFlags flags = Preview ? 0 : BassFlags.Decode | BassFlags.Prescan | BassFlags.Float; activeStream = Bass.CreateStream(StreamSystem.NoBuffer, flags, procedures.BassProcedures, RuntimeInfo.SupportsIL ? IntPtr.Zero : GCHandle.ToIntPtr(pinnedProcedures)); if (!Preview) { // We assign the BassFlags.Decode streams to the device "bass_nodevice" to prevent them from getting // cleaned up during a Bass.Free call. This is necessary for seamless switching between audio devices. // Further, we provide the flag BassFlags.FxFreeSource such that freeing the activeStream also frees // all parent decoding streams. const int bass_nodevice = 0x20000; Bass.ChannelSetDevice(activeStream, bass_nodevice); tempoAdjustStream = BassFx.TempoCreate(activeStream, BassFlags.Decode | BassFlags.FxFreeSource); Bass.ChannelSetDevice(activeStream, bass_nodevice); activeStream = BassFx.ReverseCreate(tempoAdjustStream, 5f, BassFlags.Default | BassFlags.FxFreeSource); Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoUseQuickAlgorithm, 1); Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoOverlapMilliseconds, 4); Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoSequenceMilliseconds, 30); } // will be -1 in case of an error double seconds = Bass.ChannelBytes2Seconds(activeStream, Bass.ChannelGetLength(activeStream)); bool success = seconds >= 0; if (success) { Length = seconds * 1000; Bass.ChannelGetAttribute(activeStream, ChannelAttribute.Frequency, out float frequency); initialFrequency = frequency; bitrate = (int)Bass.ChannelGetAttribute(activeStream, ChannelAttribute.Bitrate); isLoaded = true; } }); InvalidateState(); }
protected override void Dispose(bool disposing) { if (activeStream != 0) Bass.ChannelStop(activeStream); if (audioStreamPrefilter != 0) Bass.StreamFree(audioStreamPrefilter); activeStream = 0; audioStreamPrefilter = 0; dataStream?.Dispose(); dataStream = null; base.Dispose(disposing); }
public TrackBass(Stream data, bool quick = false) { PendingActions.Enqueue(() => { Preview = quick; if (data == null) { throw new ArgumentNullException(nameof(data)); } //encapsulate incoming stream with async buffer if it isn't already. dataStream = data as AsyncBufferStream ?? new AsyncBufferStream(data, quick ? 8 : -1); var procs = new DataStreamFileProcedures(dataStream); BassFlags flags = Preview ? 0 : BassFlags.Decode | BassFlags.Prescan; activeStream = Bass.CreateStream(StreamSystem.NoBuffer, flags, procs.BassProcedures, IntPtr.Zero); if (!Preview) { // We assign the BassFlags.Decode streams to the device "bass_nodevice" to prevent them from getting // cleaned up during a Bass.Free call. This is necessary for seamless switching between audio devices. // Further, we provide the flag BassFlags.FxFreeSource such that freeing the activeStream also frees // all parent decoding streams. const int bass_nodevice = 0x20000; Bass.ChannelSetDevice(activeStream, bass_nodevice); tempoAdjustStream = BassFx.TempoCreate(activeStream, BassFlags.Decode | BassFlags.FxFreeSource); Bass.ChannelSetDevice(activeStream, bass_nodevice); activeStream = BassFx.ReverseCreate(tempoAdjustStream, 5f, BassFlags.Default | BassFlags.FxFreeSource); Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoUseQuickAlgorithm, 1); Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoOverlapMilliseconds, 4); Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoSequenceMilliseconds, 30); } Length = Bass.ChannelBytes2Seconds(activeStream, Bass.ChannelGetLength(activeStream)) * 1000; float frequency; Bass.ChannelGetAttribute(activeStream, ChannelAttribute.Frequency, out frequency); initialFrequency = frequency; bitrate = (int)Bass.ChannelGetAttribute(activeStream, ChannelAttribute.Bitrate); isLoaded = true; OnLoaded?.Invoke(this); }); InvalidateState(); }
protected override void Dispose(bool disposing) { if (activeStream != 0) { isRunning = false; Bass.ChannelStop(activeStream); Bass.StreamFree(activeStream); } activeStream = 0; dataStream?.Dispose(); dataStream = null; base.Dispose(disposing); }
internal AudioTrackBass(Stream data, bool quick = false, bool loop = false) { procs = new BASS_FILEPROCS(ac_Close, ac_Length, ac_Read, ac_Seek); Preview = quick; Looping = loop; BASSFlag flags = Preview ? 0 : (BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_STREAM_PRESCAN); if (data == null) { throw new AudioNotLoadedException(); } else { //encapsulate incoming stream with async buffer if it isn't already. DataStream = data as AsyncBufferStream; if (DataStream == null) { DataStream = new AsyncBufferStream(data, quick ? 8 : -1); } audioStreamPrefilter = Bass.BASS_StreamCreateFileUser(BASSStreamSystem.STREAMFILE_NOBUFFER, flags, procs, IntPtr.Zero); } if (Preview) { audioStream = audioStreamForwards = audioStreamPrefilter; } else { audioStream = audioStreamForwards = BassFx.BASS_FX_TempoCreate(audioStreamPrefilter, loop ? BASSFlag.BASS_MUSIC_LOOP : BASSFlag.BASS_DEFAULT); audioStreamBackwards = BassFx.BASS_FX_ReverseCreate(audioStreamPrefilter, 5f, BASSFlag.BASS_DEFAULT); Bass.BASS_ChannelSetAttribute(audioStream, BASSAttribute.BASS_ATTRIB_TEMPO_OPTION_USE_QUICKALGO, Bass.TRUE); Bass.BASS_ChannelSetAttribute(audioStream, BASSAttribute.BASS_ATTRIB_TEMPO_OPTION_OVERLAP_MS, 4); Bass.BASS_ChannelSetAttribute(audioStream, BASSAttribute.BASS_ATTRIB_TEMPO_OPTION_SEQUENCE_MS, 30); } Length = (Bass.BASS_ChannelBytes2Seconds(audioStream, Bass.BASS_ChannelGetLength(audioStream)) * 1000); Bass.BASS_ChannelGetAttribute(audioStream, BASSAttribute.BASS_ATTRIB_FREQ, ref initialAudioFrequency); currentAudioFrequency = initialAudioFrequency; AudioEngine.RegisterTrack(this); }
internal static AudioTrack CreateAudioTrack(Beatmap beatmap, bool quick, bool loop = false, AudioTrack last = null) { AudioTrack track = null; Stream stream = null; AudioTrackBass bass = last as AudioTrackBass; if (bass != null && bass.Beatmap == beatmap && bass.DataStream != null) { //reuse memory-backed buffer when we can. stream = new AsyncBufferStream(beatmap.GetAudioStream(), quick ? 4 : -1, bass.DataStream); } else { stream = beatmap.GetAudioStream(); } if (stream == null) { track = new AudioTrackVirtual() { Length = beatmap.TotalLength < 0 ? 600 * 1000 : beatmap.TotalLength + 10000 } } ; else { track = new AudioTrackBass(stream, quick, loop); } if (track != null) { track.Beatmap = beatmap; } return(track); }
protected override void Dispose(bool disposing) { if (activeStream != 0) { isRunning = false; Bass.ChannelStop(activeStream); Bass.StreamFree(activeStream); } activeStream = 0; dataStream?.Dispose(); dataStream = null; if (pinnedProcedures.IsAllocated) { pinnedProcedures.Free(); } procedures = null; base.Dispose(disposing); }
protected override void Dispose(bool disposing) { PendingActions.Enqueue(() => { if (activeStream != 0) { Bass.ChannelStop(activeStream); } if (audioStreamPrefilter != 0) { Bass.StreamFree(audioStreamPrefilter); } activeStream = 0; audioStreamPrefilter = 0; dataStream?.Dispose(); dataStream = null; }); base.Dispose(disposing); }
protected override void Dispose(bool disposing) { if (audioStream != 0) { Bass.BASS_ChannelStop(audioStream); } if (audioStreamForwards != 0) { Bass.BASS_StreamFree(audioStreamForwards); } if (audioStreamBackwards != 0) { Bass.BASS_StreamFree(audioStreamBackwards); } if (audioStreamPrefilter != 0) { Bass.BASS_StreamFree(audioStreamPrefilter); } audioStream = 0; audioStreamForwards = 0; audioStreamBackwards = 0; audioStreamPrefilter = 0; State = AudioStates.Stopped; if (DataStream != null) { DataStream.Dispose(); } DataStream = null; AudioEngine.UnregisterTrack(this); base.Dispose(disposing); }
/// <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)); } // 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; //encapsulate incoming stream with async buffer if it isn't already. dataStream = data as AsyncBufferStream ?? new AsyncBufferStream(data, quick ? 8 : -1); fileCallbacks = new FileCallbacks(new DataStreamFileProcedures(dataStream)); BassFlags flags = Preview ? 0 : BassFlags.Decode | BassFlags.Prescan; activeStream = Bass.CreateStream(StreamSystem.NoBuffer, flags, fileCallbacks.Callbacks, fileCallbacks.Handle); if (!Preview) { // We assign the BassFlags.Decode streams to the device "bass_nodevice" to prevent them from getting // cleaned up during a Bass.Free call. This is necessary for seamless switching between audio devices. // Further, we provide the flag BassFlags.FxFreeSource such that freeing the activeStream also frees // all parent decoding streams. const int bass_nodevice = 0x20000; Bass.ChannelSetDevice(activeStream, bass_nodevice); tempoAdjustStream = BassFx.TempoCreate(activeStream, BassFlags.Decode | BassFlags.FxFreeSource); Bass.ChannelSetDevice(tempoAdjustStream, bass_nodevice); activeStream = BassFx.ReverseCreate(tempoAdjustStream, 5f, BassFlags.Default | BassFlags.FxFreeSource); Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoUseQuickAlgorithm, 1); Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoOverlapMilliseconds, 4); Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoSequenceMilliseconds, 30); } // will be -1 in case of an error double seconds = Bass.ChannelBytes2Seconds(activeStream, byteLength = Bass.ChannelGetLength(activeStream)); 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; Bass.ChannelGetAttribute(activeStream, ChannelAttribute.Frequency, out float frequency); initialFrequency = frequency; bitrate = (int)Bass.ChannelGetAttribute(activeStream, ChannelAttribute.Bitrate); stopCallback = new SyncCallback((a, b, c, d) => RaiseFailed()); endCallback = new SyncCallback((a, b, c, d) => { if (!Looping) { RaiseCompleted(); } }); Bass.ChannelSetSync(activeStream, SyncFlags.Stop, 0, stopCallback.Callback, stopCallback.Handle); Bass.ChannelSetSync(activeStream, SyncFlags.End, 0, endCallback.Callback, endCallback.Handle); isLoaded = true; } }); InvalidateState(); }
public DataStreamFileProcedures(AsyncBufferStream data) { dataStream = data; }
/// <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) { EnqueueAction(() => { Preview = quick; if (data == null) { throw new ArgumentNullException(nameof(data)); } //encapsulate incoming stream with async buffer if it isn't already. dataStream = data as AsyncBufferStream ?? new AsyncBufferStream(data, quick ? 8 : -1); fileCallbacks = new FileCallbacks(new DataStreamFileProcedures(dataStream)); BassFlags flags = Preview ? 0 : BassFlags.Decode | BassFlags.Prescan; activeStream = Bass.CreateStream(StreamSystem.NoBuffer, flags, fileCallbacks.Callbacks, fileCallbacks.Handle); if (!Preview) { // We assign the BassFlags.Decode streams to the device "bass_nodevice" to prevent them from getting // cleaned up during a Bass.Free call. This is necessary for seamless switching between audio devices. // Further, we provide the flag BassFlags.FxFreeSource such that freeing the activeStream also frees // all parent decoding streams. const int bass_nodevice = 0x20000; Bass.ChannelSetDevice(activeStream, bass_nodevice); tempoAdjustStream = BassFx.TempoCreate(activeStream, BassFlags.Decode | BassFlags.FxFreeSource); Bass.ChannelSetDevice(activeStream, bass_nodevice); activeStream = BassFx.ReverseCreate(tempoAdjustStream, 5f, BassFlags.Default | BassFlags.FxFreeSource); Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoUseQuickAlgorithm, 1); Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoOverlapMilliseconds, 4); Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoSequenceMilliseconds, 30); } // will be -1 in case of an error double seconds = Bass.ChannelBytes2Seconds(activeStream, Bass.ChannelGetLength(activeStream)); bool success = seconds >= 0; if (success) { Length = seconds * 1000; Bass.ChannelGetAttribute(activeStream, ChannelAttribute.Frequency, out float frequency); initialFrequency = frequency; bitrate = (int)Bass.ChannelGetAttribute(activeStream, ChannelAttribute.Bitrate); stopCallback = new SyncCallback((a, b, c, d) => RaiseFailed()); endCallback = new SyncCallback((a, b, c, d) => { if (!Looping) { RaiseCompleted(); } }); Bass.ChannelSetSync(activeStream, SyncFlags.Stop, 0, stopCallback.Callback, stopCallback.Handle); Bass.ChannelSetSync(activeStream, SyncFlags.End, 0, endCallback.Callback, endCallback.Handle); isLoaded = true; } }); InvalidateState(); }