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); }
private void LoadSong() { BassFlags Flags = Preview ? 0 : (BassFlags.Decode | BassFlags.Prescan); // Create a new stream CleanStream = Bass.CreateStream(AudioFile.Content, 0, AudioFile.Size, Flags); if (!Preview) { Stream = BassFx.TempoCreate(CleanStream, BassFlags.Decode | BassFlags.FxFreeSource); TempoStream = Stream; Stream = BassFx.ReverseCreate(Stream, 5f, BassFlags.FxFreeSource); Bass.ChannelSetAttribute(Stream, ChannelAttribute.TempoUseQuickAlgorithm, 1); Bass.ChannelSetAttribute(Stream, ChannelAttribute.TempoOverlapMilliseconds, 4); Bass.ChannelSetAttribute(Stream, ChannelAttribute.TempoSequenceMilliseconds, 30); } else { Stream = CleanStream; } Length = (Bass.ChannelBytes2Seconds(Stream, Bass.ChannelGetLength(Stream)) * 1000); Bass.ChannelGetAttribute(Stream, ChannelAttribute.Frequency, out InitialFrequency); SetDirection(false); }
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); }
public ReversePlayer(Decoder decoder, Resolution BufferKind = Resolution.Short, double DecodingBlockLength = 2) : base(BufferKind) { this.decoder = decoder; Handle = BassFx.ReverseCreate(decoder.Handle, (float)DecodingBlockLength, BufferKind.ToBassFlag()); }
/// <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(); }
private int prepareStream(Stream data, bool quick) { switch (data) { case MemoryStream _: case UnmanagedMemoryStream _: case AsyncBufferStream _: // Buffering memory stream is definitely unworthy. dataStream = data; break; default: // It would be most likely a FileStream. // Consider to use RandomAccess to optimise in favor of FileStream in .NET 6 dataStream = new AsyncBufferStream(data, quick ? 8 : -1); break; } fileCallbacks = new FileCallbacks(new DataStreamFileProcedures(dataStream)); BassFlags flags = (Preview ? 0 : BassFlags.Decode | BassFlags.Prescan); // While this shouldn't cause issues, we've had a small subset of users reporting issues on windows. // To keep things working let's only apply to other platforms until we know more. // See https://github.com/ppy/osu/issues/18652. if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows) { flags |= BassFlags.AsyncFile; } int stream = Bass.CreateStream(StreamSystem.NoBuffer, flags, fileCallbacks.Callbacks, fileCallbacks.Handle); bitrate = (int)Math.Round(Bass.ChannelGetAttribute(stream, ChannelAttribute.Bitrate)); 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 | BassFlags.Decode); Bass.ChannelSetAttribute(stream, ChannelAttribute.TempoUseQuickAlgorithm, 1); Bass.ChannelSetAttribute(stream, ChannelAttribute.TempoOverlapMilliseconds, 4); Bass.ChannelSetAttribute(stream, ChannelAttribute.TempoSequenceMilliseconds, 30); } return(stream); }
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(); }
/// <summary> /// Loads the File Channel with FX. /// </summary> protected override int OnLoad(string FileName) { var h = Bass.CreateStream(FileName, Flags: BassFlags.Decode); if (h == 0) { return(0); } h = BassFx.TempoCreate(h, BassFlags.Decode | BassFlags.FxFreeSource); if (h == 0) { return(0); } _tempoHandle = h; return(BassFx.ReverseCreate(h, 2, BassFlags.FxFreeSource)); }
static void SaveReverse(string FilePath) { try { var sfd = ReverseSaveDialog.Value; sfd.FileName = Path.GetFileNameWithoutExtension(FilePath) + ".Reverse"; if (!sfd.ShowDialog().Value) { return; } var fc = Bass.CreateStream(FilePath, Flags: BassFlags.Decode); var rc = BassFx.ReverseCreate(fc, 2, BassFlags.Decode | BassFlags.FxFreeSource); var wf = WaveFormat.FromChannel(fc); var writer = new WaveFileWriter(new FileStream(sfd.FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read), wf); var blockLength = (int)Bass.ChannelSeconds2Bytes(rc, 2); var buffer = new byte[blockLength]; var gch = GCHandle.Alloc(buffer, GCHandleType.Pinned); while (Bass.ChannelIsActive(rc) == PlaybackState.Playing) { var bytesReceived = Bass.ChannelGetData(rc, gch.AddrOfPinnedObject(), blockLength); writer.Write(buffer, bytesReceived); } gch.Free(); writer.Dispose(); Bass.StreamFree(rc); MessageBox.Show("Saved"); } catch (Exception e) { MessageBox.Show($"Failed\n\n{e}"); } }
/// <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(); }
/// <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(); }