Probleme with BASS_Mixer_StreamAddChannel

Started by Phil75,

Phil75

Hello  :)

This code doesn't work and I don't understand why:

hSample1 = Bass.BASS_SampleLoad("C:\Sample1.wav", 0, 0, 1, BASSFlag.BASS_DEFAULT)

hChannel1 = Bass.BASS_SampleGetChannel(hSample1, BASSFlag.BASS_STREAM_DECODE)

hMixer = BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_STREAM_DECODE)

Dim b As Boolean = BassMix.BASS_Mixer_StreamAddChannel(hMixer, hChannel1, BASSFlag.BASS_STREAM_DECODE)

Bass.BASS_ErrorGetCode()

b = False
BASS_ErrorGetCode() return BASS_ERROR_DECODE

Chris

you can try this
hSample1 = Bass.BASS_SampleLoad("C:\Sample1.wav", 0, 0, 1, BASSFlag.BASS_DEFAULT)

hChannel1 = Bass.BASS_SampleGetChannel(hSample1, BASSFlag.BASS_STREAM_DECODE OR BASS_SAMCHAN_STREAM)

a Mixer will not work with "Samples" (only hMusic, hRecord, hStream)
but with the flag "BASS_SAMCHAN_STREAM" BASS_SampleGetChannel will Create a stream (HSTREAM) rather than a sample channel.


Phil75


Phil75

To avoid having to create a new topic, I have another problem.

Dim fx As Integer = Bass.BASS_ChannelSetFX(hChannel, Un4seen.Bass.BASSFXType.BASS_FX_BFX_VOLUME_ENV, 0)
fx = 0

Bass.BASS_ErrorGetCode() return BASS_ERROR_ILLTYPE

I use "BASS.net".

Phil75

I just want to explain my project.

I'm trying to create a virtual piano with samples.

I don't know if it's possible with "BASS".

I added a "Fade-Out" with '"BASS_ChannelSlideAttribute"' to simulate the Sustain pedal.
It seems to work.

All that remains is to add a low-pass filter with "BASS_FXSetParameters".

For now, I use one button to start one sound and to stop it.
88 Samples will remain to be added.

But when I turn on the sound quickly, I sometimes hear "clicks".

Bass.BASS_Init(0, 44100, BASSInit.BASS_DEVICE_DEFAULT, Me.Handle)
BassAsio.BASS_ASIO_Init(0, BASSASIOInit.BASS_ASIO_THREAD)

BassMix.LoadMe()
BassFx.LoadMe()

hSample = Bass.BASS_SampleLoad("C:\test.wav", 0, 0, 1, BASSFlag.BASS_DEFAULT)

hChannel = Bass.BASS_SampleGetChannel(hSample, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_SAMCHAN_STREAM)

hMixer = BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_STREAM_DECODE)

BassMix.BASS_Mixer_StreamAddChannel(hMixer, hChannel, BASSFlag.BASS_STREAM_DECODE)

_asio = New BassAsioHandler(ASIODeviceSel, 0, hMixer)

BassAsio.BASS_ASIO_Start(0)


Private Sub Button1_MouseDown(sender As Object, e As MouseEventArgs) Handles Button1.MouseDown

    Bass.BASS_ChannelSlideAttribute(hChannel, BASSAttribute.BASS_ATTRIB_VOL, 1.0F, 0)

    Bass.BASS_ChannelSetPosition(hChannel, 0)

End Sub

Private Sub Button1_MouseUp(sender As Object, e As MouseEventArgs) Handles Button1.MouseUp

    Bass.BASS_ChannelSlideAttribute(hChannel, BASSAttribute.BASS_ATTRIB_VOL, 0F, 1000)

End Sub

Ian @ un4seen

Quote from: Phil75It works, thank you very much for your help  :)

One thing to note is that a sample's streams (unlike HCHANNEL) aren't recycled by BASS_SampleGetChannel, and you will need to free them (eg. call BASS_StreamFree) when you're finished with them. They will be freed automatically when the sample is freed (via BASS_SampleFree) though.

Quote from: Phil75I have another problem.

Dim fx As Integer = Bass.BASS_ChannelSetFX(hChannel, Un4seen.Bass.BASSFXType.BASS_FX_BFX_VOLUME_ENV, 0)
fx = 0

Bass.BASS_ErrorGetCode() return BASS_ERROR_ILLTYPE

That looks like BASS_FX.DLL isn't loaded, so its effects can't be used. You can force it to be loaded by calling a function from it, eg. BASS_FX_GetVersion during initialization.

Quote from: Phil75But when I turn on the sound quickly, I sometimes hear "clicks".

Try replacing the BASS_ChannelSetPosition call with BASS_Mixer_ChannelSetPosition. The mixer will then ramp-in the new position, which should help avoid clicks.

Quote from: Phil75BassMix.BASS_Mixer_StreamAddChannel(hMixer, hChannel, BASSFlag.BASS_STREAM_DECODE)

Please note BASS_STREAM_DECODE isn't a valid flag for BASS_Mixer_StreamAddChannel, so that should be removed. Using flags from different functions can result in accidentally setting other flags that happen to have the same values. In won't actually be causing a problem in this case because BASS_Mixer_StreamAddChannel doesn't currently have a flag with the same value as BASS_STREAM_DECODE (0x200000) but good to fix that anyway in case one is added in future, and something to keep in mind for other calls too (the valid flags are listed in a function's documentation).

Phil75

Hello  :)

Thank you for your help.

I made a lot of mistakes.

QuotePlease note BASS_STREAM_DECODE isn't a valid flag for BASS_Mixer_StreamAddChannel...

Removed

QuoteBASS_FX_GetVersion during initialization...

Added "BASS_FX_GetVersion". Now the filter works fine.

QuoteTry replacing the BASS_ChannelSetPosition call with BASS_Mixer_ChannelSetPosition...

I tried but I still hear the "clicks".

I also tried adding an envelope (BASS_FX_BFX_VOLUME_ENV) with a 100ms attack, but it didn't work.
The envelope changes the attack of the sound, but I still hear occasional clicks.

I checked the "Sample", it starts with zero values.

Capture1.png

Another question:

I'm using "BASS_SampleGetChannel" with the "BASS_SAMCHAN_STREAM" parameter.
So I should then use "Bass.BASS_StreamFree" instead of "BASS_ChannelFree"?
And I have to use "BASS_SampleFree" after using "BASS_SampleLoad"?

Thank you

Ian @ un4seen

Quote from: Phil75
QuoteTry replacing the BASS_ChannelSetPosition call with BASS_Mixer_ChannelSetPosition...

I tried but I still hear the "clicks".

I also tried adding an envelope (BASS_FX_BFX_VOLUME_ENV) with a 100ms attack, but it didn't work.
The envelope changes the attack of the sound, but I still hear occasional clicks.

I checked the "Sample", it starts with zero values.

I think the remaining clicks are likely to be from the data at the old position just before restarting, ie. if that data wasn't also close to zero values.

Do you need the Button1_MouseUp function to fade-out over 1 second, or is that intended just to prevent a click when stopping? If the latter then you could actually use BASS_ChannelSetAttribute instead because the mixer will ramp volume changes anyway, ie. it wouldn't suddenly jump from 1 to 0. If you still hear clicks then you may need to add a short delay (according to the ASIO buffer length) before restarting to give the mixer a chance to apply that volume change first.

Quote from: Phil75I'm using "BASS_SampleGetChannel" with the "BASS_SAMCHAN_STREAM" parameter.
So I should then use "Bass.BASS_StreamFree" instead of "BASS_ChannelFree"?
And I have to use "BASS_SampleFree" after using "BASS_SampleLoad"?

Either BASS_StreamFree or BASS_ChannelFree will work then. BASS_SampleFree does need to be used to free a sample.

Phil75

I removed all instructions in the "Button1_MouseUp" event.

I only kept the "BassMix.BASS_Mixer_ChannelSetPosition" instruction in the "Button1_MouseUp" event.

Private Sub Button1_MouseDown(sender As Object, e As MouseEventArgs) Handles Button1.MouseDown

    BassMix.BASS_Mixer_ChannelSetPosition(hChannel, 0)

End Sub

Private Sub Button1_MouseUp(sender As Object, e As MouseEventArgs) Handles Button1.MouseUp

End Sub

I still hear "clicks".

I tried without using "ASIO". There is a lot of delay, but the "clicks" are still present.

Thank you for your help.

Ian @ un4seen

Yep, if you remove the volume fading/ramping then there is quite likely to be a click heard when restarting mid-playback due to the different sample data at the old and new positions. Try keeping the volume changes but use BASS_ChannelSetAttribute instead of BASS_ChannelSlideAttribute (for a short ramp instead of long fade), and if you still hear clicks, also add a little delay between them. For example:

Private Sub Button1_MouseDown(sender As Object, e As MouseEventArgs) Handles Button1.MouseDown
    Bass.BASS_ChannelSetAttribute(hChannel, BASSAttribute.BASS_ATTRIB_VOL, 1.0F)
    BassMix.BASS_Mixer_ChannelSetPosition(hChannel, 0)
End Sub

Private Sub Button1_MouseUp(sender As Object, e As MouseEventArgs) Handles Button1.MouseUp
    Bass.BASS_ChannelSetAttribute(hChannel, BASSAttribute.BASS_ATTRIB_VOL, 0F)
    Thread.Sleep(50) ' wait a bit for volume change to be applied
End Sub

Phil75

@Ian I followed your advice and used "Thread.Sleep()". It works  :)

But now I think I have an audio saturation problem. See the attached "Mp3" file.

I tried to reduce the volume with "BASS_ASIO_ChannelSetVolume" but even with a very low volume, it was not effective.

audio.zip

Ian @ un4seen

Quote from: Phil75@Ian I followed your advice and used "Thread.Sleep()". It works  :)

Great!

One remaining issue is that the source will still be playing after you mute it, which is a waste of CPU. To avoid that, you could also pause and resume it:

Private Sub Button1_MouseDown(sender As Object, e As MouseEventArgs) Handles Button1.MouseDown
    Bass.BASS_ChannelSetAttribute(hChannel, BASSAttribute.BASS_ATTRIB_VOL, 1.0F)
    BassMix.BASS_Mixer_ChannelSetPosition(hChannel, 0)
    BassMix.BASS_Mixer_ChannelFlags(hChannel, 0, BASSFlag.BASS_MIXER_CHAN_PAUSE) ' unpause
End Sub

Private Sub Button1_MouseUp(sender As Object, e As MouseEventArgs) Handles Button1.MouseUp
    Bass.BASS_ChannelSetAttribute(hChannel, BASSAttribute.BASS_ATTRIB_VOL, 0F)
    Thread.Sleep(50) ' wait a bit for volume change to be applied
    BassMix.BASS_Mixer_ChannelFlags(hChannel, BASSFlag.BASS_MIXER_CHAN_PAUSE, BASSFlag.BASS_MIXER_CHAN_PAUSE) ' pause
End Sub

I think it could be nice if BASSmix had an option to automatically ramp-out when pausing, which would avoid the need for the BASS_ATTRIB_VOL setting. I'll look into that.

Quote from: Phil75I tried to reduce the volume with "BASS_ASIO_ChannelSetVolume" but even with a very low volume, it was not effective.

What parameters are you using in that call? If you want to affect the level of all output channels then you can use channel=-1 for the master volume, like this:

BassAsio.BASS_ASIO_ChannelSetVolume(false, -1, volume)

Ian @ un4seen

Quote from: Ian @ un4seenI think it could be nice if BASSmix had an option to automatically ramp-out when pausing, which would avoid the need for the BASS_ATTRIB_VOL setting. I'll look into that.

If you would like to give it a try, such an option has now been added:

    www.un4seen.com/stuff/bassmix.zip

The new option is a BASS_MIXER_CHAN_RAMPOUT flag (0x80000), which can be used with BASS_Mixer_StreamAddChannel and BASS_Mixer_ChannelFlags. It isn't defined in BASS.Net yet but you can access it via CType(&H80000, BASSFlag) in the meantime:

Private Sub Button1_MouseDown(sender As Object, e As MouseEventArgs) Handles Button1.MouseDown
    BassMix.BASS_Mixer_ChannelSetPosition(hChannel, 0)
    BassMix.BASS_Mixer_ChannelFlags(hChannel, 0, BASSFlag.BASS_MIXER_CHAN_PAUSE) ' unpause
End Sub

Private Sub Button1_MouseUp(sender As Object, e As MouseEventArgs) Handles Button1.MouseUp
    BassMix.BASS_Mixer_ChannelFlags(hChannel, BASSFlag.BASS_MIXER_CHAN_PAUSE Or CType(&H80000, BASSFlag),
        BASSFlag.BASS_MIXER_CHAN_PAUSE Or CType(&H80000, BASSFlag)) ' pause and ramp-out
    Thread.Sleep(50) ' wait a bit for ramp-out to be applied
End Sub

The Thread.Sleep call might not be needed (you can try removing it to find out).

Phil75

@Ian Thank you for this new option.

But the project has evolved a lot.
I decided to use a VB Timer to manage the release of the samples and thus simulate the half-sustain pedal like on real pianos.
It's not perfect but it works.
The button was for testing.
Now, thanks to "BASS.net," I use the MIDI output of my Yamaha keyboard to trigger the 88 samples.
When the "NoteOff" occurs, the VB Timer gradually decreases the volume of the note to zero.
I tried:

BassMix.BASS_Mixer_ChannelFlags(hChannel, BASSFlag.BASS_MIXER_CHAN_PAUSE, BASSFlag.BASS_MIXER_CHAN_PAUSE)
and indeed it reduces the number of active Samples.
But I can't use it because I added a "Reverb VST Plugin" to the "BASS Mixer".
And when I stop the Channel, the sound cuts out abruptly because of the Reverb.
I think this is normal operation.
So I keep all the sounds playing but it doesn't seem to consume much CPU.
I am satisfied, everything works perfectly  :)

Ian @ un4seen

If the reverb effect is set on the mixer (not the source) then you can have it continue when the source is paused by including the BASS_MIXER_NONSTOP flag in your BASS_Mixer_StreamCreate call.

jpf

Quote from: Phil75I decided to use a VB Timer to manage the release of the samples and thus simulate the half-sustain pedal like on real pianos.

In my piano half-pedaling has a seemingly different effect:
The decay time is approximately proportional to the position of the pedal and can be adjusted in real time during the decay by changing the position of the pedal. Pedal fully deppresed: no damping (samples are played to the end, no volume or filtering slide applied, noteoff event has no effect). Pedal fully up, rest position: maximum damping (decay time is the shortest possible and applied from the moment of the noteoff event). Also not just volume is slided, also the harmonics content is slided. I think this can be better simulated by simultaneously sliding the volume and a low-pass filter with slide time controlled in real time (during the slide) by the position of the pedal. And each sample must have its own volume and low-pass filer. Maybe this is a very CPU consuming setup but seems more realistic than your approach. I didn't try this myself, though; it's just speculation.

I think my piano (a Casio Privia) also switches samples depending on the position of the sustain pedal for a more realistic effect. This surely raises the complexity of the setup and the amount of memory needed for the samples. Maybe this is too much for your project. I'm just saying.

A side note:
I also use Pianotek (free version) in my PC with my piano as Midi controller. It isn't as realistic as the hardware sound but it's good enough.

Phil75

@Ian Thanks for the info. it works very well. I should be more careful to the options listed in the documentation  :)

@jpf On my Yamaha piano, the sustain pedal ranges from 0 (pedal released) to 80 (pedal almost fully depressed).
It suddenly increases to 127.

My Timer starts at NoteOff, and gradually decreases the volume of the Sample to zero.
At a speed that depends on the pedal value. That's all.

On each sample, I added a low-pass filter whose cutoff frequency varies according to the velocity.
Because all my samples were recorded at a velocity of 127.
It works quite well.
For me "Pianoteq" is the best piano simulator.

Everything works pretty well but for some unknown reason, when playing, whatever samples are used,
even without Reverb, the sound is not very nice.
I managed to solve the problem by reducing the frequency of 1400Hz at the Mixer output.

These 2 codes give good results:

Dim eq As New BASS_DX8_PARAMEQ()
_fxEQ(0) = Bass.BASS_ChannelSetFX(hSamplePhil, BASSFXType.BASS_FX_DX8_PARAMEQ, 0)
eq.fBandwidth = 12.0F
eq.fCenter = 1400.0F
Bass.BASS_FXSetParameters(_fxEQ(0), eq)

or

Dim Param As BASS_BFX_BQF
Param = New BASS_BFX_BQF
Param.lFilter = BASSBFXBQF.BASS_BFX_BQF_NOTCH
Param.fCenter = 1400.0F
Param.fBandwidth = 2.0F
Param.lChannel = BASSFXChan.BASS_BFX_CHANALL
hFilterNotch = Bass.BASS_ChannelSetFX(hMixer, BASSFXType.BASS_FX_BFX_BQF, 0)
Bass.BASS_FXSetParameters(hFilterNotch, Param)

but I don't know which one is more effective (CPU, Latency)

jpf

Quote from: Phil75On my Yamaha piano, the sustain pedal ranges from 0 (pedal released) to 80 (pedal almost fully depressed).
It suddenly increases to 127.

That seems to make sense, so the pedal will be perceived as an on/off swith by the synths that don't support half-pedaling.

Quote from: Phil75My Timer starts at NoteOff, and gradually decreases the volume of the Sample to zero.
At a speed that depends on the pedal value. That's all.

This setup doesn't seem to change the remining damping time in real time when the pedal position changes during the damping, but if this is OK to you, then you succeeded. Well done!

Quote from: Phil75On each sample, I added a low-pass filter whose cutoff frequency varies according to the velocity.
Because all my samples were recorded at a velocity of 127.
It works quite well.

Well done!

Quote from: Phil75For me "Pianoteq" is the best piano simulator.

I don't recall any other physical simulation synth, so I can't tell how good it is, but I like the sample-based synthesis of my piano better. The software sample-based piano synths I've tried are crap, but I've only tried a few of the more small-sized (small memory-footprint and low CPU usage). Pianoteq still sounds pretty realistic for its size so I'll keep using it for recording.

Phil75

QuoteThis setup doesn't seem to change the remining damping time in real time when the pedal position changes during the damping

@jpf If I release the key while the pedal is pressed, the note gradually fades out.
But the more I release the pedal, the faster the note length decreases.
I made it work only in this direction, so the note's volume never increases.
I hope I was clear, the translation is not easy for me.

But for now I have another little problem.

The "BASS_VST_GetChunk" function usually works very well.
But I think I have a VST that it doesn't work very well with.
Actually, "BASS_VST_GetChunk" seems to work fine, but "BASS_VST_SetChunk" doesn't.
Only with this VST.

Dim Tab() As Byte        (Global declaration)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

    Tab = BassVst.BASS_VST_GetChunk(hVST, True)

End Sub

I make adjustments in the VST...

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click

    BassVst.BASS_VST_SetChunk(hVST, True, Tab)

End Sub

No settings have changed

I saved the Bytes array to a file. As is often the case, it is an XML file with a header that specifies the number of Bytes.
I thought the VST had a problem, a bug. But the "Get Chunk" and "Set Chunk" functions work with the "VSTHost" software.
And so far I haven't had this problem with other VSTs.
Can I upload the VST zip file for someone to try?

Falcosoft

Not all VST plugins use chunks to save/restore plugin data.
In VSTHost you can check this at the plugin's info dialog.
If "Program data are handled in formatless chunks" is listed under the "Flags" section then the plugin uses chunks else it does not.

If it does not then you have to iterate through the plugin's programs and parameter list to save/restore parameter values.   

Phil75

@Falcosoft Thanks for the reply.

in the plugin's info dialog, "Program data are handled in formatless chunks" is listed.
"VSTHost" creates a ".FXP" file with a rather large header, probably data it adds to the "Chunk" it takes from the VST.
But it contains the same XML data as with "BASS_VST_GetChunk".
I could save all the VST Parameter values, unfortunately it handles an external file name.
And this external file name appears in the "Chunk" returned by "BASS_VST_GetChunk".
Usually I change the file name, and I send the Bytes array with "BASS_VST_SetChunk",
but with this VST it does not work. Even if I send the same "Chunk".

Capture1.png

kafffee

Sry to interrupt but I started reading this thread out of curiosity...:

What would be the difference between loading audio data with .StreamCreateFile (the overload that streams from memory) and .SampleLoad?

Greetings, kafffee :-)

Ian @ un4seen

Quote from: kafffeeWhat would be the difference between loading audio data with .StreamCreateFile (the overload that streams from memory) and .SampleLoad?

The big difference is that BASS_SampleLoad pre-decodes the entire file to memory, while BASS_StreamCreateFile doesn't. BASS_SampleLoad = decoded sample data in memory, BASS_StreamCreateFile(mem=true) = encoded file in memory. Samples and streams also have other different features, eg. samples can be played multiple times simultaneously, while streams can have syncs and DSP applied. BASS_SampleGetChannel with BASS_SAMCHAN_STREAM can be used to combine the features of both.

Falcosoft

#23
Quote from: Phil75@Falcosoft Thanks for the reply.

in the plugin's info dialog, "Program data are handled in formatless chunks" is listed.
"VSTHost" creates a ".FXP" file with a rather large header, probably data it adds to the "Chunk" it takes from the VST.
But it contains the same XML data as with "BASS_VST_GetChunk".
I could save all the VST Parameter values, unfortunately it handles an external file name.
And this external file name appears in the "Chunk" returned by "BASS_VST_GetChunk".
Usually I change the file name, and I send the Bytes array with "BASS_VST_SetChunk",
but with this VST it does not work. Even if I send the same "Chunk".

Capture1.png

Hi,
I have checked this EasyConvolver.dll plugin and it is buggy in multiple ways:

1. It can only load saved settings before the plugin editor and processing is activated. You can check this even in VSTHost. Once the plugin is fully loaded the 'Plugin menu -> Load bank' option has no effect.

2. You can only change the 'DryWet' parameter's value from the GUI. The DryWet VST parameter reflects the value that is set from the GUI but not the other way around. That is setting the parameter's value programatically during runtime has no effect on either the GUI or the audio processing.
(This bug can also be tested with VSTHost by opening the 'Edit Parameters' dialog and changing the value of the DryWet parameter.)

3. Bass_VST_SetChunk() call is actually successfull somewhat even when it is called during in active state of the plugin in the sense it sets the DryWet VST parameter's value properly but because of bug 2. it has no effect either on the GUI or audio processing.

4. Bass_VST_Setchunk() calls dispatcher with effSetChunk parameter internally. This call should return the bytes accepted/processed by the plugin. But in case of this plugin the call always returns 0 so you cannot determine if the call was successful or not.


Overall Bass_VST_SetChunk() works well, the problems are caused by the quirks of the plugin.

Phil75

Hello,
you are definitely right. I hadn't checked all these details. Thanks for taking the time to check all this out. I'll look for a better convolution VST plugin.