Author Topic: Reversing a stopped reverse stream changes its position.  (Read 2087 times)

aybe

  • Posts: 162
Here's some incorrect behavior I've encountered and created a little code example for you to see.

When such stream is at rest a position zero and it is reversed, its position suddenly changes to EOF :o

Try that:
- open a file, play some audio, reverse direction, stops at zero ... all is fine here.
- now press reverse button twice or more, see the position of the underlying stream changing for no reason.

Unless I'm mistaken, I expect BASS to simply change the playback direction, not the position itself  ;D

Why is BASS behaving in such way ?

Code:

Code: [Select]
<Page
    x:Class="App1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <StackPanel>
        <Button Content="Open" Click="ButtonOpenOnClick" />
        <Button Content="Play" Click="ButtonPlayOnClick" />
        <Button Content="Reverse" Click="ButtonReverseOnClick" />
        <TextBlock x:Name="TextBlock" />
    </StackPanel>
</Page>

Code:

Code: [Select]
using System;
using System.Threading.Tasks;
using Windows.Storage.Pickers;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
using Un4seen.Bass;
using Un4seen.Bass.AddOn.Fx;

namespace App1
{
    public sealed partial class MainPage
    {
        private sealed class BassException : Exception
        {
            public BassException() : base($"{Bass.BASS_ErrorGetCode()}")
            {
            }
        }

        public MainPage()
        {
            InitializeComponent();
            Loaded += OnLoaded;
            Unloaded += OnUnloaded;
            CompositionTarget.Rendering += CompositionTargetOnRendering;
        }

        private int Handle { get; set; }

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            if (!Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero))
                throw new BassException();
        }

        private void OnUnloaded(object sender, RoutedEventArgs e)
        {
            if (!Bass.BASS_Free())
                throw new BassException();
        }

        private async void ButtonOpenOnClick(object sender, RoutedEventArgs e)
        {
            var picker = new FileOpenPicker();
            picker.FileTypeFilter.Add(".wav");

            var file = await picker.PickSingleFileAsync();
            if (file == null)
                return;

            await Task.Run(() => { DoOpen(file.Path); });
        }

        private async void ButtonPlayOnClick(object sender, RoutedEventArgs e)
        {
            await Task.Run(() => { DoPlay(); });
        }

        private async void ButtonReverseOnClick(object sender, RoutedEventArgs e)
        {
            await Task.Run(() => { DoReverse(); });
        }

        private async void CompositionTargetOnRendering(object sender, object e)
        {
            var position = await Task.Run(() => DoPosition());

            TextBlock.Text = TimeSpan.FromSeconds(position).ToString();
        }

        private void DoOpen(string file)
        {
            var stream = Bass.BASS_StreamCreateFile(file, 0, 0, BASSFlag.BASS_STREAM_DECODE);
            if (stream == 0)
                throw new BassException();

            var reverse = BassFx.BASS_FX_ReverseCreate(stream, 3.0f, BASSFlag.BASS_STREAM_DECODE);
            if (reverse == 0)
                throw new BassException();

            const float forward = (float) BASSFXReverse.BASS_FX_RVS_FORWARD;

            if (!Bass.BASS_ChannelSetAttribute(reverse, BASSAttribute.BASS_ATTRIB_REVERSE_DIR, forward))
                throw new BassException();

            var tempo = BassFx.BASS_FX_TempoCreate(reverse, BASSFlag.BASS_DEFAULT);
            if (tempo == 0)
                throw new BassException();

            Handle = tempo;
        }

        private void DoPlay()
        {
            if (Handle == 0)
                return;

            if (!Bass.BASS_ChannelPlay(Handle, false))
                throw new BassException();
        }

        private void DoReverse()
        {
            var reverse = BassFx.BASS_FX_TempoGetSource(Handle);
            if (reverse == 0)
                throw new BassException();

            var value = 0.0f;

            if (!Bass.BASS_ChannelGetAttribute(reverse, BASSAttribute.BASS_ATTRIB_REVERSE_DIR, ref value))
                throw new BassException();

            var direction1 = (BASSFXReverse) value;

            var direction2 = direction1 == BASSFXReverse.BASS_FX_RVS_FORWARD
                ? BASSFXReverse.BASS_FX_RVS_REVERSE
                : BASSFXReverse.BASS_FX_RVS_FORWARD;

            if (!Bass.BASS_ChannelSetAttribute(reverse, BASSAttribute.BASS_ATTRIB_REVERSE_DIR, (float) direction2))
                throw new BassException();
        }

        private double DoPosition()
        {
            if (Handle == 0)
                return -1.0f;

            var bytes = Bass.BASS_ChannelGetPosition(Handle);
            if (bytes == -1)
                throw new BassException();

            var seconds = Bass.BASS_ChannelBytes2Seconds(Handle, bytes);
            if (seconds < 0.0f)
                throw new BassException();

            return seconds;
        }
    }
}

Thank you !