Author Topic: Record PCM data to memory stream or byte array  (Read 298 times)

kafffee

  • Posts: 271
Hi everybody :-)

My goal is to write pcm data  from recording vinyl records into a byte array, memory stream, or such as.

Then, when this is done, I want the user to tell me where to chop up the recorded data into tracks and then prompt the user in which format to write the single tracks to hard disk (mp3, flac, etc.).

My first guess is to use BASS_Encode_Start(handle, Nothing, BASSEncode.BASS_ENCODE_PCM, Nothing, IntPtr.Zero, 0) to record the stream.

But how can I process the data? How can I acccess the data stream in order to chop it up? And how am I going to encode the single tracks to mp3, flac, etc. and finally write it to disc? I think some of it can be done with bass.dll and add-ons, some other parts I will have to find out by myself (in particular the actual "chopping")...

I am looking forward to your ideas :-)

Ian @ un4seen

  • Administrator
  • Posts: 26077
Re: Record PCM data to memory stream or byte array
« Reply #1 on: 16 Sep '24 - 18:00 »
You wouldn't use BASS_Encode_Start to record PCM data to memory. You can just have your RECORDPROC callback store the received data in memory. You can then do what you like with the data in memory. You would use BASS_Encode_Start or BASS_Encode_MP3_StartFile/etc to encode the final result. You could use BASS_Encode_Write to feed the data from memory to the encoders, but you will need a host stream for the encoders. You could create a "dummy" stream (with same sample format as the recording) for that. For example, something like this:

Code: [Select]
dummy = BASS_StreamCreate(freq, chans, BASS_STREAM_DECODE, STREAMPROC_DUMMY, 0); // create a dummy stream
encoder = BASS_Encode_MP3_StartFile(dummy, options, 0, filename); // start an MP3 encoder on it
BASS_Encode_Write(encoder, data, datalen); // send sample data to the encoder
BASS_Encode_Stop(encoder); // stop the encoder

Please see the documentation for details on the mentioned functions.

kafffee

  • Posts: 271
Re: Record PCM data to memory stream or byte array
« Reply #2 on: 23 Sep '24 - 14:41 »
Okay thanks, I managed to write the data into the byte array.

I have three more questions:

(1) How do I playback the recording during recording with this setup?
(2) Is there a way to playback the byte array after recording without prior saving it to the hard drive?
(3) How do I record source or mixer channels in order to write the data to a byte array? So far I only got recording directly to hard drive?

Thanks in advance :-) looking forward to your answer.

Edit:

I tried to write the sample data into a file after recording and ran into this problem:

I get an mp3 file in the length that I recorded, but it doesnt contain what I recorded. Instead I get silence alternately with noise (take a look at the attachment, its a zipped mp3 file, hope thats okay).

Whats wrong with this?:

Code: [Select]
Dim DummyStream As Integer = Bass.BASS_StreamCreateDummy(44100, 2, Nothing, IntPtr.Zero) ' // create a dummy stream
Dim Encoder = BassEnc_Mp3.BASS_Encode_MP3_StartFile(DummyStream, Nothing, AddOn.Enc.BASSEncode.BASS_ENCODE_AUTOFREE Or AddOn.Enc.BASSEncode.BASS_ENCODE_QUEUE, OutputFolder & FileName & ".mp3") ' // start an MP3 encoder On it

Dim TrackLengthInBytes As Long = (EndPos - StartPos - 1)
Dim Track(CInt(TrackLengthInBytes)) As Byte

Array.Copy(RecordedDataComplete.ToArray, StartPos, Track, 0, TrackLengthInBytes)
Un4seen.Bass.AddOn.Enc.BassEnc.BASS_Encode_Write(Encoder, Track, Track.Length) '// send sample data To the encoder

Un4seen.Bass.AddOn.Enc.BassEnc.BASS_Encode_Stop(Encoder) '; // Stop the encoder

Also, when I call BASS_Encode_Stop right after, I will only get an mp3 file with 2 kiloBytes.
« Last Edit: 24 Sep '24 - 11:56 by kafffee »

Ian @ un4seen

  • Administrator
  • Posts: 26077
Re: Record PCM data to memory stream or byte array
« Reply #3 on: 24 Sep '24 - 16:53 »
(1) How do I playback the recording during recording with this setup?

You could create a "push" stream with BASS_StreamCreate (proc=STREAMPROC_PUSH) and have your RECORDPROC feed that with BASS_StreamPutData. The push stream should have the same sample format as the recording.

(2) Is there a way to playback the byte array after recording without prior saving it to the hard drive?

Yes, you can use BASS_StreamCreate again for that. You could either use a push stream again like above, or instead have a STREAMPROC callback read from your byte array.

(3) How do I record source or mixer channels in order to write the data to a byte array? So far I only got recording directly to hard drive?

You can use a DSPPROC callback on them via BASS_ChannelSetDSP to receive their data (and put it in an array). Note that the "priority" value determines where your callback is in the DSP chain, if there are other DSP/FX. For reference, BASSenc uses priority -1000 by default (see BASS_CONFIG_ENCODE_PRIORITY).

I tried to write the sample data into a file after recording and ran into this problem:

I get an mp3 file in the length that I recorded, but it doesnt contain what I recorded. Instead I get silence alternately with noise (take a look at the attachment, its a zipped mp3 file, hope thats okay).

Whats wrong with this?:

Code: [Select]
Dim DummyStream As Integer = Bass.BASS_StreamCreateDummy(44100, 2, Nothing, IntPtr.Zero) ' // create a dummy stream
Dim Encoder = BassEnc_Mp3.BASS_Encode_MP3_StartFile(DummyStream, Nothing, AddOn.Enc.BASSEncode.BASS_ENCODE_AUTOFREE Or AddOn.Enc.BASSEncode.BASS_ENCODE_QUEUE, OutputFolder & FileName & ".mp3") ' // start an MP3 encoder On it

Dim TrackLengthInBytes As Long = (EndPos - StartPos - 1)
Dim Track(CInt(TrackLengthInBytes)) As Byte

Array.Copy(RecordedDataComplete.ToArray, StartPos, Track, 0, TrackLengthInBytes)
Un4seen.Bass.AddOn.Enc.BassEnc.BASS_Encode_Write(Encoder, Track, Track.Length) '// send sample data To the encoder

Un4seen.Bass.AddOn.Enc.BassEnc.BASS_Encode_Stop(Encoder) '; // Stop the encoder

Also, when I call BASS_Encode_Stop right after, I will only get an mp3 file with 2 kiloBytes.

You should remove the BASS_ENCODE_QUEUE flag in this case, as you're encoding one big block of data rather than a live source. You can also remove BASS_ENCODE_AUTOFREE, as you're calling BASS_Encode_Stop anyway :)

It looks like there is valid sound followed by noise at regular intervals in your recording. Could it be that your RECORDPROC is writing too much data to the array, ie. the recorded data plus whatever randomness follows it?

kafffee

  • Posts: 271
Re: Record PCM data to memory stream or byte array
« Reply #4 on: 24 Sep '24 - 18:10 »
Wow thats a lot of new input thank you. I'll see how far I can get with this.

I'll start off with the code I already got, i.e. writing the byte array to disc.

I replaced AddOn.Enc.BASSEncode.BASS_ENCODE_AUTOFREE Or AddOn.Enc.BASSEncode.BASS_ENCODE_QUEUE with Nothing. Still I get this random noise with parts of silence.

I'm not sure whether I implemented the RECORDPROC callback right, can you see if there's anything wrong?

Code: [Select]
Private Function MyRecording(handle As Integer, buffer As IntPtr, length As Integer, user As IntPtr) As Boolean
    Dim cont As Boolean = True

    If length > 0 AndAlso buffer <> IntPtr.Zero Then
        If RecordedData Is Nothing OrElse RecordedData.Length < length Then
            RecordedData = New Byte(length) {}
        End If

        ' copy from managed to unmanaged memory
        Marshal.Copy(buffer, RecordedData, 0, length)
        BytesWritten += length

        RecordedDataComplete.AddRange(RecordedData)    'this is a Private List(Of Byte)

        Dim Percent As Double = BytesWritten / MaxTrackLengthInBytes * 100
        RecordingXPosWF = WFWidth / 100 * Percent

        ' get and draw our live recording waveform
        WF.RenderRecording(buffer, length)
        Services.ServiceContainer.GetService(Of IMainWindowService)?.HoleDispatcher().Invoke(Sub() DrawWaveForm())
        If BytesWritten >= MaxTrackLengthInBytes Then
            cont = False ' stop recording
        End If
    End If
    Return cont
End Function

PS/Edit:

I have been thinking about problem (1) and (2) and thought it might even be more useful to only implement problem (2), so the user will be able to work on the record while it is still recording (playback from at the desired position). Could you get a bit more into detail about that, I have been browsing thru the docs for a while now but I'm still missing a clue on how to get this going. As for now, I think this suggestion of yours seems more attractive to me:

Quote
or instead have a STREAMPROC callback read from your byte array.

I think this code sample would be a good start to understand whats going on, but I don't really know where the variable "stream" comes from? Did it get mashed up with "orig" accidentally?:

Code: [Select]
Private _dupCallback As DSPPROC
...
' create stream on device 1
Bass.BASS_SetDevice(1)
Dim orig As Integer = Bass.BASS_StreamCreateFile("test.mp3", 0, 0, BASSFlag.BASS_SAMPLE_LOOP)
Bass.BASS_ChannelPlay(orig, False)
...
' create a clone on device 2
Dim info As BASS_CHANNELINFO = Bass.BASS_ChannelGetInfo(stream)
Bass.BASS_SetDevice(2)
Dim clone As Integer = Bass.BASS_StreamCreatePush(info.freq, info.chans, info.flags, IntPtr.Zero)
' pause source stream to synchonise buffer contents
Bass.BASS_ChannelPause(stream)
Dim c As Integer = Bass.BASS_ChannelGetData(stream, IntPtr.Zero, CInt(BASSData.BASS_DATA_AVAILABLE))
Dim buf(c) As Byte
Bass.BASS_ChannelGetData(stream, buf, c)
Bass.BASS_StreamPutData(clone, buf, c)
' set DSP to copy new data from source stream
_dupCallback = New DSPPROC(DupDSP)
Bass.BASS_ChannelSetDSP(orig, _dupCallback, New IntPtr(clone), 0)
Bass.BASS_ChannelPlay(orig, False) ' resume source
Bass.BASS_ChannelPlay(clone, False) ' play clone
...
Private Sub DupDSP(handle As Integer, channel As Integer,
                   buffer As IntPtr, length As Integer, user As IntPtr)
  Bass.BASS_StreamPutData(user.ToInt32(), buffer, length)
End Sub
« Last Edit: 24 Sep '24 - 19:32 by kafffee »

Ian @ un4seen

  • Administrator
  • Posts: 26077
Re: Record PCM data to memory stream or byte array
« Reply #5 on: 25 Sep '24 - 16:43 »
I'm not sure whether I implemented the RECORDPROC callback right, can you see if there's anything wrong?

I'm not a VB.Net user myself, so I'm not sure, but it looks like it's always using the highest seen "length" parameter value rather than the current value when adding to the array? That could explain the noise in the recording. Try this change:

Code: [Select]
        ' copy from managed to unmanaged memory
        RecordedData = New Byte(length) {}
        Marshal.Copy(buffer, RecordedData, 0, length)
        BytesWritten += length

        RecordedDataComplete.AddRange(RecordedData)    'this is a Private List(Of Byte)

I have been thinking about problem (1) and (2) and thought it might even be more useful to only implement problem (2), so the user will be able to work on the record while it is still recording (playback from at the desired position). Could you get a bit more into detail about that, I have been browsing thru the docs for a while now but I'm still missing a clue on how to get this going. As for now, I think this suggestion of yours seems more attractive to me:

Quote
or instead have a STREAMPROC callback read from your byte array.

You would basically do the opposite of the RECORDPROC, ie. copy data from your array to the STREAMPROC's buffer. You can use a counter to keep track of where it is in the array, like "BytesWritten" above but maybe "BytesRead". Make sure you don't go beyond the end of the array, ie. limit the requested "length" value if necessary.

kafffee

  • Posts: 271
Re: Record PCM data to memory stream or byte array
« Reply #6 on: 26 Sep '24 - 09:03 »
Quote
I'm not a VB.Net user myself, so I'm not sure, but it looks like it's always using the highest seen "length" parameter value rather than the current value when adding to the array? That could explain the noise in the recording. Try this change:

Not Sure what you mean. Just remove the two "if"-conditions? That doesn't fix it.

Code: [Select]
If length > 0 AndAlso buffer <> IntPtr.Zero Then
    If RecordedData Is Nothing OrElse RecordedData.Length < length Then
        RecordedData = New Byte(length) {}
    End If

    ' copy from managed to unmanaged memory
    Marshal.Copy(buffer, RecordedData, 0, length)
    BytesWritten += length

    RecordedDataComplete.AddRange(RecordedData)
...


Quote
You would basically do the opposite of the RECORDPROC, ie. copy data from your array to the STREAMPROC's buffer. You can use a counter to keep track of where it is in the array, like "BytesWritten" above but maybe "BytesRead".

Could you give me a code sample other than in the docs? I have tried to do it on my own, but didn't get very far...

Ian @ un4seen

  • Administrator
  • Posts: 26077
Re: Record PCM data to memory stream or byte array
« Reply #7 on: 26 Sep '24 - 15:50 »
Not Sure what you mean. Just remove the two "if"-conditions? That doesn't fix it.

Code: [Select]
If length > 0 AndAlso buffer <> IntPtr.Zero Then
    If RecordedData Is Nothing OrElse RecordedData.Length < length Then
        RecordedData = New Byte(length) {}
    End If

    ' copy from managed to unmanaged memory
    Marshal.Copy(buffer, RecordedData, 0, length)
    BytesWritten += length

    RecordedDataComplete.AddRange(RecordedData)
...

Note the RecordedDataComplete.AddRange call doesn't have any length/size parameter, so I'm assuming it adds the entire RecordedData contents. The earlier code seems to only ever expand RecordedData, which means it contains extra unwanted/old data when the RECORDPROC receives less than the max amount. That probably wouldn't sound like noise though (just repeated old sound), so probably not actually the cause of that (unless perhaps if it was previously used for other data elsewhere).

Try using normal VB.Net file functions to write the array to a file and then use Audacity's File>Import>Raw option to load and check it. Make sure you choose the same format as the recording.

Could you give me a code sample other than in the docs? I have tried to do it on my own, but didn't get very far...

I'm afraid I can't really help with the specifics of VB.Net, but it could look like this in C:

Code: [Select]
BYTE *data;
DWORD datalen, readpos;

DWORD CALLBACK StreamProc(HSTREAM handle, void *buffer, DWORD length, void *user)
{
if (length > datalen - readpos) length = datalen - readpos; // limit length to what's remaining
memcpy(buffer, data + readpos, length); // copy data from current position to stream buffer
readpos += length; // advance the position
if (readpos == datalen) return length | BASS_STREAMPROC_END; // reached end of data, end the stream
return length;
}

kafffee

  • Posts: 271
Re: Record PCM data to memory stream or byte array
« Reply #8 on: 26 Sep '24 - 16:26 »
Quote
I'm afraid I can't really help with the specifics of VB.Net, but it could look like this in C:

C is fully okay, I think I can handle that. So is this callback function is being called from BASS_StreamCreate? I noticed there's also a StreamCreateDummy and a StreamCreatePush method??

I am pretty confused right now, can't really happening in the background...

Quote
so I'm assuming it adds the entire RecordedData contents.

You're right.

Quote
Try using normal VB.Net file functions to write the array to a file and then use Audacity's File>Import>Raw option to load and check it. Make sure you choose the same format as the recording.

Okay I will. You mean just write RecordedData to a file? Or append the array to the file once it's opened? What I dont understand is whats happening in the background: Until now I thought that basically RecordedData would hold the data for the entire record and every time the callback funcction is being called it would append buffer to RecordedData?? Is that correct?

Ian @ un4seen

  • Administrator
  • Posts: 26077
Re: Record PCM data to memory stream or byte array
« Reply #9 on: 26 Sep '24 - 17:29 »
So is this callback function is being called from BASS_StreamCreate?

You pass the STREAMPROC to BASS_StreamCreate, and then BASS will call it (repeatedly) when you play the created stream.

Quote
Try using normal VB.Net file functions to write the array to a file and then use Audacity's File>Import>Raw option to load and check it. Make sure you choose the same format as the recording.

Okay I will. You mean just write RecordedData to a file? Or append the array to the file once it's opened? What I dont understand is whats happening in the background: Until now I thought that basically RecordedData would hold the data for the entire record and every time the callback funcction is being called it would append buffer to RecordedData?? Is that correct?

It looks to me like RecordedData is used to create a VB.Net array from a single block of sample data received by the RECORDPROC, and then it's added to RecordedDataComplete? In which case, it's RecordedDataComplete that you should write to file at the end of the recording. If the file doesn't look right, you could then try writing RecordedData, to try to narrow down where the problem is coming from.

kafffee

  • Posts: 271
Re: Record PCM data to memory stream or byte array
« Reply #10 on: 26 Sep '24 - 20:54 »
Quote
In which case, it's RecordedDataComplete that you should write to file at the end of the recording. If it doesn't look right, you could then try writing RecordedData, to narrow down where the problem is coming from.

Okay, I tried to speak louder on my recording and used some good headphones instead of my display's built-in speaker. It actually records right, but that pulsing noise just superimposes it. This also works when I have bass.dll encode RecordedDataComplete to mp3. Listen for yourself, I attached the mp3 to this reply (I keep saying "hallo" on the record).

Knowing this, what is your suggestion?

-------------------------------------------

For the sake of clarity, I replaced my List(Of Byte) with an array of bytes, so now it looks like this:

Code: [Select]
RecordedDataComplete = RecordedDataComplete.Concat(RecordedData).ToArray
...which basically appends RecordedData to RecordedDataComplete...

« Last Edit: 27 Sep '24 - 06:31 by kafffee »

Ian @ un4seen

  • Administrator
  • Posts: 26077
Re: Record PCM data to memory stream or byte array
« Reply #11 on: 27 Sep '24 - 14:03 »
Okay, I tried to speak louder on my recording and used some good headphones instead of my display's built-in speaker. It actually records right, but that pulsing noise just superimposes it. This also works when I have bass.dll encode RecordedDataComplete to mp3. Listen for yourself, I attached the mp3 to this reply (I keep saying "hallo" on the record).

Knowing this, what is your suggestion?

Yep, that's what I saw in your previous recording too. It still sounds to me like the RECORDPROC is adding too much data (ie. valid sound + randomness) to the array. Perhaps you can remove RecordedDataComplete and use ReDim on RecordedData to put all the data in there instead?

Code: [Select]
Dim RecordedData() As Byte

...

Private Function MyRecording(handle As Integer, buffer As IntPtr, length As Integer, user As IntPtr) As Boolean
ReDim Preserve RecordedData(BytesWritten + length - 1)
Marshal.Copy(buffer, RecordedData, BytesWritten, length)
BytesWritten += length
...

kafffee

  • Posts: 271
Re: Record PCM data to memory stream or byte array
« Reply #12 on: 27 Sep '24 - 14:53 »
Ha! It works perfectly  ;D

I don' t really understand why, but it does (I'm new to arrays, I've only used lists so far) :-) Thank you

______________________________________________________________________________________

I have another query concerning your C code in reply #7:

I'm confused with this line of code:

Code: [Select]
memcpy(buffer, data + readpos, length); // copy data from current position to stream buffer
I loooked up memcpy on the internet and it says:

Quote
void *memcpy(void *to, const void *from, size_t numBytes);
Parameters:
to: A pointer to the memory location where the copied data will be stored.
from: A pointer to the memory location from where the data is to be copied.
numBytes: The number of bytes to be copied.

Are you sure this is right? The second parameter in your code is a byte array plus a number??

Where is this STREAMPROC actually called from? I guess BASS_StreamCreate, but I am confused, theres also two functions StreamCreateDummy and StreamCreatePush, are the multiple ways to do this (playback during recording)?

Could you give me another code sample from the function the STREAMPROC is being called from?

Ian @ un4seen

  • Administrator
  • Posts: 26077
Re: Record PCM data to memory stream or byte array
« Reply #13 on: 27 Sep '24 - 16:44 »
Ha! It works perfectly  ;D

I don' t really understand why, but it does (I'm new to arrays, I've only used lists so far) :-) Thank you

Good to hear that sorted it!

You should definitely read up on arrays, as they're pretty important when dealing with sample data.

I'm confused with this line of code:

Code: [Select]
memcpy(buffer, data + readpos, length); // copy data from current position to stream buffer
I loooked up memcpy on the internet and it says:

Quote
void *memcpy(void *to, const void *from, size_t numBytes);
Parameters:
to: A pointer to the memory location where the copied data will be stored.
from: A pointer to the memory location from where the data is to be copied.
numBytes: The number of bytes to be copied.

Are you sure this is right? The second parameter in your code is a byte array plus a number??

Yes. "readpos" is the position in the array that you want data from, and "data" points the start of the array, so you add them to get at the wanted data. In VB.Net, you would probably use Marshal.Copy for this, like in the RECORDPROC (it's basically the same thing in reverse).

Where is this STREAMPROC actually called from? I guess BASS_StreamCreate, but I am confused, theres also two functions StreamCreateDummy and StreamCreatePush, are the multiple ways to do this (playback during recording)?

Could you give me another code sample from the function the STREAMPROC is being called from?

The STREAMPROC is called by BASS to get sample data for the stream to play. If you're uncomfortable with the STREAMPROC stuff then you could use a "push" stream instead with BASS_StreamCreatePush and pass the data to that via BASS_StreamPutData.

kafffee

  • Posts: 271
Re: Record PCM data to memory stream or byte array
« Reply #14 on: 1 Oct '24 - 09:37 »
Okay, I ran into another question:

In the recording callback function, is the argument buffer only the "new" data (byte chunk) or the entire data since the beginning of the recording, respectively length the size of only the "new" data"?

Also, does .RenderRecording require only this "new" data or the entire recording?

Ian @ un4seen

  • Administrator
  • Posts: 26077
Re: Record PCM data to memory stream or byte array
« Reply #15 on: 1 Oct '24 - 14:11 »
In the recording callback function, is the argument buffer only the "new" data (byte chunk) or the entire data since the beginning of the recording, respectively length the size of only the "new" data"?

Each RECORDPROC call delivers the new data (in "buffer") that has arrived since the last call. That's why you need to combine it all in an array to get the whole recording.

Also, does .RenderRecording require only this "new" data or the entire recording?

The code you posted earlier is passing the RECORDPROC's "buffer" and "length" parameters to the RenderRecording function, so that will be seeing the same data as the RECORDPROC is.

kafffee

  • Posts: 271
Re: Record PCM data to memory stream or byte array
« Reply #16 on: 3 Oct '24 - 13:03 »
Alright thanks :-)

I have also managed to playback the recording stream while still recording. Except for one thing:

I can only play from Position 0 s far. I f I want to set playback position with Bass.BASS_ChannelSetPosition, I will get error # 27 (BASS_ERROR_NOTFILE). So what is the proper way to do this?

________________________
Another issue: When I tried to record from mic during my DAW was open, BASS returned an error saying that the device is busy. Is there a way to query before starting recording if the device is busy? Will the IsEnabled property of BASS_DEVICEINFO class do this?
________________________
And a question :-)

Besides recording from the mic, I want to record my source respectively mixer channels. I am not sure if I understood you right, you  wrote:

Quote
You can use a DSPPROC callback on them via BASS_ChannelSetDSP to receive their data (and put it in an array).

So I've done this:

Code: [Select]
Dim RecChannelHandle As Integer
Select Case ChosenChannel
    Case 0
        RecChannelHandle = MainModule.streamfx(0)
    Case 1
        RecChannelHandle = MainModule.streamfx(1)
    Case 2
        RecChannelHandle = MainModule.mixer
End Select

MyDSPCallback = New DSPPROC(AddressOf MyDSP)

Dim PlayVALP3Channel As Integer = Bass.BASS_ChannelSetDSP(RecChannelHandle, MyDSPCallback, Nothing, 0)
Debug.WriteLine("setDSP: " & Bass.BASS_ErrorGetCode.ToString)


InitializeWaveForm()
Length = CSng(Bass.BASS_ChannelBytes2Seconds(PlayVALP3Channel, CLng(MaxTrackLengthInBytes)))
WF.RenderStartRecording(PlayVALP3Channel, Length, 0)
If Not PeakTimer.Enabled Then PeakTimer.Start()

The PeakTimer's elapsed event handler looks like this:

Code: [Select]
Private Sub UpdatePeak(sender As Object, e As ElapsedEventArgs)
    If (Not (PlayBackChannel = Nothing)) OrElse (PlayBackChannel = 0) Then
    WF.RenderRecording(RenderBuffer, RenderLength)
    UpdateWaveForm(Nothing, Nothing)
    End If
End Sub

And the callback:

Code: [Select]
Private Sub MyDSP(handle As Integer, channel As Integer, buffer As IntPtr, length As Integer, user As IntPtr)
    If length > 0 AndAlso buffer <> IntPtr.Zero Then

        Dim PufferGroesse As Integer

        If BytesWritten + length > RecordedData.Length Then
            PufferGroesse = BytesWritten + length - RecordedData.Length
        Else
            PufferGroesse = length
        End If

        Marshal.Copy(buffer, RecordedData, BytesWritten, PufferGroesse - 1)
        BytesWritten += length

        RenderBuffer = buffer
        RenderLength = length

        If IsPlaying Then Bass.BASS_StreamPutData(PlayBackChannel, buffer, length)
        Dim Prozent As Double = BytesWritten / MaxTrackLaengeInBytes * 100
        RecordingXPosWF = WFBreite / 100 * Prozent
        RecordingPosition = TimeSpan.FromSeconds(GetPositionInSeconds(RecordingXPosWF))
        Services.ServiceContainer.GetService(Of IMainWindowService)?.HoleDispatcher().InvokeAsync(Sub() WF.RenderRecording(buffer, length), DispatcherPriority.SystemIdle)
        Services.ServiceContainer.GetService(Of IMainWindowService)?.HoleDispatcher().InvokeAsync(Sub() UpdateWaveForm(Nothing, Nothing), DispatcherPriority.SystemIdle)

    End If
End Sub

When I call UpdateWaveForm() I get an error here:

Code: [Select]
WF.CreateBitmap(CInt(TransformToPixels(WFWidth)) * Zoom, CInt(TransformToPixels(WFHeight) * MainModule.GetScaling), -1, -1, False)
Debug.WriteLine("CreateBitmap: " & Bass.BASS_ErrorGetCode.ToString)

>> .CreateBitmap returns Nothing. Even though ErrorGetCode returns BASS_OK and SetDSP (in the first code) also returns BASS_OK.

I am initializing my source and the mixer channels like this:

Code: [Select]
MainModule.streamfx(WhichDeck - 1) = BassFx.BASS_FX_TempoCreate(stream, BASSFlag.BASS_STREAM_DECODE)
Code: [Select]
mixer = Un4seen.Bass.AddOn.Mix.BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_DEFAULT Or BASSFlag.BASS_SAMPLE_FLOAT)


What am I doing wrong?