need help with "SampleCreate"

Started by Phil75,

Phil75

Hello,

I need help.
I'm using "Bass.Net."
I'm working with a large ".Wav" file (44100, 16-bit, stereo):

Capture1.png

I know the beginning and end of each sample (in bytes).

I need to save all the samples in a new file.

I use "StreamCreateFile" to load the file.
I use "ChannelSetPosition" to specify the part to save.
I save the file with "BASS_Encode_Start".

Everything works fine.

But now I need to apply effects to each sample.

So, I load the "Sample" files, apply the effects, and save.
That's a lot of files to manage.
Is there a better solution without creating a new file?

Perhaps:

Create a Sample ("SampleCreate"),
copy some of the data into this Sample using "SampleGetData" and "SampleSetData" (?),
apply the effects to the Sample, and save it to a file.

I don't know how to use "SampleGetData" to put the data from the big file into the Sample.

Thanks for your help.

Ian @ un4seen

If I understand correctly, you're currently splitting a large file into multiple smaller new files, and now you want to apply effects while doing that? If so, you would set the effects on the large file stream (using BASS_ChannelSetDSP/FX) before writing the new files.

Or do you just want to play parts of the large file with effects applied, without creating any new files? If so, you can again set the effects on the large file stream, and also use the BASS_POS_END option with BASS_ChannelSetPosition to set the end position of the part that you want to play.

Phil75

Thanks for the reply.

I only want to cut a part of the Sample, apply several effects, and save it to a file.
I don't want to play the file.
It might be better to apply an effect to a portion of the file, then cut that portion out
and save it to a file, but I prefer to create a new object (BASS_StreamCreatePush).

I have progressed.

After reading the documentation, I tried this code:

(sorry for french language, bad variable naming convention and VB.Net)

Dim hBigFile As Integer
Dim hNewSample As Integer

Dim infos As BASS_CHANNELINFO

Dim Debut As Long
Dim Fin As Long
Dim Duree As Long

Dim Datas As Byte()

Debut = 44597933 * 4
Fin = 44869413 * 4

hBigFile = Bass.BASS_StreamCreateFile("D:\BigFile.wav", 0, 0, BASSFlag.BASS_STREAM_DECODE)

Duree = Fin - Debut

Array.Resize(Datas, Duree)

Bass.BASS_ChannelSetPosition(hBigFile, Debut, BASSMode.BASS_POS_BYTE)
Bass.BASS_ChannelSetPosition(hBigFile, Fin, BASSMode.BASS_POS_END)

Duree = Bass.BASS_ChannelGetData(hBigFile, Datas, Duree)

infos = New BASS_CHANNELINFO()
Bass.BASS_ChannelGetInfo(hBigFile, infos)

hNewSample = Bass.BASS_StreamCreatePush(infos.freq, infos.chans, infos.flags, IntPtr.Zero)
Bass.BASS_StreamPutData(hNewSample, Datas, Duree)

BassFx.BASS_FX_GetVersion()

Dim PitchEffectObj As BASS_BFX_PITCHSHIFT
Dim hPitchEffect As Integer
hPitchEffect = Bass.BASS_ChannelSetFX(hNewSample, BASSFXType.BASS_FX_BFX_PITCHSHIFT, 1)
PitchEffectObj = New BASS_BFX_PITCHSHIFT
Bass.BASS_FXGetParameters(hPitchEffect, PitchEffectObj)
PitchEffectObj.fSemitones = 1
Bass.BASS_FXSetParameters(hPitchEffect, PitchEffectObj)
Bass.BASS_ErrorGetCode()

BASS_Encode_Start...

Everything seems to be working fine.

With the "BASS_BFX_VOLUME" effect, there are no problems.
But with the "PITCHSHIFT" effect, it doesn't seem to work.
Here's the file without the effect:

Capture2.png

and the file with the effect:

Capture3.png

After BASS_FXSetParameters, BASS_ErrorGetCode return BASS_OK

Thank you for your help

Ian @ un4seen

Quote from: Phil75I only want to cut a part of the Sample, apply several effects, and save it to a file.
I don't want to play the file.
It might be better to apply an effect to a portion of the file, then cut that portion out
and save it to a file, but I prefer to create a new object (BASS_StreamCreatePush).

I have progressed.

After reading the documentation, I tried this code:
...
Everything seems to be working fine.

Good to hear you've got it working. If you like, you could make the code more efficient (faster and less memory) by processing the original stream (hBigFile) directly without the intermediate "push" stream (hNewSample), something like this:

hBigFile = Bass.BASS_StreamCreateFile("D:\BigFile.wav", 0, 0, BASSFlag.BASS_STREAM_DECODE)

Bass.BASS_ChannelSetPosition(hBigFile, Debut, BASSMode.BASS_POS_BYTE)
Bass.BASS_ChannelSetPosition(hBigFile, Fin, BASSMode.BASS_POS_END)

BassFx.BASS_FX_GetVersion()

Dim PitchEffectObj As BASS_BFX_PITCHSHIFT
Dim hPitchEffect As Integer
hPitchEffect = Bass.BASS_ChannelSetFX(hBigFile, BASSFXType.BASS_FX_BFX_PITCHSHIFT, 1)
PitchEffectObj = New BASS_BFX_PITCHSHIFT
Bass.BASS_FXGetParameters(hPitchEffect, PitchEffectObj)
PitchEffectObj.fSemitones = 1
Bass.BASS_FXSetParameters(hPitchEffect, PitchEffectObj)
Bass.BASS_ErrorGetCode()

BASS_Encode_Start(hBigFile,...

And then call BASS_Encode_Stop, and BASS_ChannelSetPosition and BASS_Encode_Start again for the next part.

Quote from: Phil75With the "BASS_BFX_VOLUME" effect, there are no problems.
But with the "PITCHSHIFT" effect, it doesn't seem to work.
Here's the file without the effect:

Capture2.png

and the file with the effect:

Capture3.png

Are you referring to the delay/gap at the start? That seems to be expected. Here's a detailed description of how the effect works:

    https://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/

Note the "The global I/O delay is inFifoLatency samples (which means that the start of your output will contain that many samples of of silence!) – this has to be taken into account when we write the data out to a file" bit. You would want to process that before starting the encoder (eg. call BASS_ChannelGetData before BASS_Encode_Start), so that it isn't present in the output file. It looks like you can calculate the "inFifoLatency" value like this:

delay = lFFTsize - lFFTsize / lOsamp

Where "lFFTsize" and "lOsamp" are as set in the effect's parameters (BASS_BFX_PITCHSHIFT).

Phil75

Thanks for the reply.

Thank you for all these explanations.

Quote. If you like, you could make the code more efficient (faster and less memory) by processing the original stream (hBigFile) directly without the intermediate "push" stream (hNewSample), something like this:

You are probably right, and I will try this method.

QuoteAre you referring to the delay/gap at the start? That seems to be expected. Here's a detailed description of how the effect works:

    https://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/

Note the "The global I/O delay is inFifoLatency samples (which means that the start of your output will contain that many samples of of silence!) – this has to be taken into account when we write the data out to a file" bit. You would want to process that before starting the encoder (eg. call BASS_ChannelGetData before BASS_Encode_Start), so that it isn't present in the output file. It looks like you can calculate the "inFifoLatency" value like this:

It's a little complicated for me, but I'll try to understand.

I just noticed something strange.
Regarding "BASS_BFX_PITCHSHIFT", the documentation tells us this:

lFFTsize : Defines the FFT frame size used for the processing. Typical values are 1024, 2048 (default) and 4096, max is 8192. 
lOsamp : Is the STFT oversampling factor which also determines the overlap between adjacent STFT frames. Default = 8

Always with the same code, after executing the "BASS_FX GetParameters", I see this :

Capture4.png

and after executing the "BASS_FX SetParameters", BASS_ErrorGetCode return BASS_OK

But if I add this code:

PitchEffectObj.lFFTsize = 2048
PitchEffectObj.lOsamp = 8
PitchEffectObj.fSemitones = 1
Bass.BASS_FXSetParameters(hPitchEffect, PitchEffectObj)

I see this :

Capture5.png

and after executing the "BASS_FX SetParameters", BASS_ErrorGetCode return BASS_ERROR_ILLPARAM

Thank you for your help  :)

Ian @ un4seen

It looks like there's a conflict between BASS_FX and BASS.Net in the BASS_BFX_PITCHSHIFT structure due to the use of the "long" type. "long" is 32-bit in C/C++ (on Windows) and 64-bit in .Net. "int" should really be used there instead. I'll make that change for the next BASS_FX release and ask the BASS.Net developer to do the same. In the meantime, perhaps you can use a custom BASS_BFX_PITCHSHIFT class? I'm not a .Net user myself, but perhaps something like this:

[Serializable, StructLayout(LayoutKind.Sequential)]
public sealed class BASS_BFX_PITCHSHIFT
{
float fPitchShift;
float fSemitones;
int lFFTsize;
int lOsamp;
int lChannel;
}

radio42

Hi,
yes, I can change that. But why do you use int, long, long long....?
In BASS you explicitly defined DWORD for a 32-bit integer value - i.e. the C# int equivalent.

However, the C/C++ 'int' type depends on the OS/compiler - so is here a 16-bit value or a 32-bit value meant to be used?
For structs this is important...

Phil75

Hello  :)

I tried with "BASS_VST", but whatever plugin I use, I also get about 30ms of data with
the value zero at the beginning of the file ("BASS_ChannelGetData" starts filling the buffer with zeros).

It's as if internally in "BASS" the playback starts at the same time as the recording,
and because of the delay introduced by the effect, the process starts recording the data before
the VST sends the data back. Or maybe it's the Plugin that sends zeros for some reason. I don't know.

But I found a solution using "BASS_FX_TempoCreate" and "BASS_ChannelSetAttribute...BASSAttribute.BASS_ATTRIB_TEMPO_PITCH".
Everything works fine.

But I don't know why it works because I didn't understand the difference between "BASS_FX_TempoCreate" and "BASS_StreamCreate".

I thought "BASS_VST" would work better with "BASS_FX_TempoCreate" but no  ;D

radio42

#8
A new 'Bass.Net' version (v2.4.17.7) is available.

The BASS_StreamCreate creates a normal stream. You can adjust the sampling rate on it (i.e. play it faster or slower).

But you can not change the tempo while keeping the pitch (on DJ systems this is often called Master Tempo).
Here you need to use the BASS_FX_TempoCreate function.
To create a Tempo stream you also use a decoding stream created by BASS_StreamCreate and use this stream in the BASS_FX_TempoCreate function as an input. See the docs for details.

Ian @ un4seen

Quote from: radio42yes, I can change that. But why do you use int, long, long long....?
In BASS you explicitly defined DWORD for a 32-bit integer value - i.e. the C# int equivalent.

However, the C/C++ 'int' type depends on the OS/compiler - so is here a 16-bit value or a 32-bit value meant to be used?
For structs this is important...

It looks like the effect's original source code uses "long" and Arthur copied that in the parameters when adding it to BASS_FX. Although the C/C++ "int" can technically be a different size, it is 32-bit on all currently supported platforms. BASS_FX also uses "int" for the integer parameters of its other effects, so may as well stick with that for consistency if nothing else.

Switching to stdint types (eg. "int32_t" instead of "int" and "uint32_t" instead of "DWORD") in all BASS C/C++ headers is being considered to make the sizes explicit, but it would require C/C++ users to change some variable/parameter types in existing code (particularly callback function parameters). Need to decide whether explicit sizes is worth the inconvenience of code changes. Just to be clear, the sizes wouldn't be changing so existing apps would still work fine when just switching DLLs, but code changes may be required when rebuilding an app.

Quote from: radio42A new Bass.Net version (v2.4.17.7) is available.

Great! Updated BASS_FX builds with the BASS_BFX_PITCHSHIFT fix are also available here:

    www.un4seen.com/stuff/bass_fx-osx.zip
    www.un4seen.com/stuff/bass_fx-linux.zip

A Windows update isn't needed because the C/C++ "int" and "long" are both 32-bit there.

Phil75

Hello  :)

The link didn't work for me. I used "http://bass.radio42.com/".

I updated "BASS.Net", and now the default settings with "BASS_FX GetParameters" work.

I may have made a mistake in my code, but I think there is a problem :

Dim hFXpitch As Integer
Dim t As BASS_BFX_PITCHSHIFT
Dim b As Boolean

hStreamSrc = Bass.BASS_StreamCreateFile("D:\sample.wav", 0, 0, BASSFlag.BASS_STREAM_DECODE)

hFXpitch = Bass.BASS_ChannelSetFX(hStreamSrc, BASSFXType.BASS_FX_BFX_PITCHSHIFT, 0)
t = New BASS_BFX_PITCHSHIFT
Bass.BASS_FXGetParameters(hFXpitch, t)
t.fSemitones = 1
b = Bass.BASS_FXSetParameters(hFXpitch, t)
Bass.BASS_ErrorGetCode()

b = True
BASS_ErrorGetCode() return BASS_OK

I applied the effect on "Test2.Wav" but not on "Test1.Wav".
When listening, the two sounds seem identical.
On "Test2.Wav" we see silence of a few milliseconds.
We can therefore assume that the filter has been applied correctly :

Capture6.png

Ian @ un4seen

It looks like fPitchShift needs to be 0 for fSemitones to be used, otherwise fSemitones is ignored and fPitchShift used instead. So like this:

t.fPitchShift = 0
t.fSemitones = 1
b = Bass.BASS_FXSetParameters(hFXpitch, t)

Phil75

Everything is working fine. Thank you for your help and patience  :)