Example #1
0
        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);
        }
Example #2
0
        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);
        }
Example #3
0
        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);
        }
Example #4
0
        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());
        }
Example #5
0
        /// <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();
        }
Example #6
0
        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);
        }
Example #7
0
        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();
        }
Example #8
0
        /// <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));
        }
Example #9
0
        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}"); }
        }
Example #10
0
        /// <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();
        }
Example #11
0
        /// <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();
        }