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
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
Why is BASS behaving in such way ?
Code:
<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:
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 !