Too much microphone latency

Started by kafffee,

Ian @ un4seen

Are you using any other callback functions, eg. ASIOPROC/STREAMPROC/DSPPROC/SYNCPROC? If so, I guess it's possible that any of them could be delayed by .Net garbage collection. Does the problem still happen if you remove all callback functions? If you're currently using an ASIOPROC with BASS_ASIO_ChannelEnable for the ASIO input, you could use a "push" stream with BASS_ASIO_ChannelEnableBASS instead:

inputstream = BASS_StreamCreate(BASS_ASIO_GetRate(), 1, BASS_SAMPLE_FLOAT | BASS_STREAM_DECODE, STREAMPROC_PUSH, NULL);
BASS_ASIO_ChannelEnableBASS(true, 0, inputstream, true);

I'm not a .Net user myself, so I'm not very familiar with it, but if it turns out that garbage collection is indeed the issue then you could have a look at Microsoft's docs to see if there are any solutions (perhaps latency modes?):

    https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/

Quote from: kafffeeI cannot hear the sound of my TempoFXStreamHandleDrySplit2 stream. Could you take a look again at what I wrote about this in the second part of reply #20 ?

Where is the sample data coming from? If it's the ASIO input, then I would recommend using a push stream for that instead (as above). Even if the data is coming from somewhere else, you could probably still use a push stream instead of your own buffering and STREAMPROC.

kafffee

First, I need to clarify this: I wrote:

QuoteWhen I completely do not create and add...

...the playback channels: I can still hear the clicking and skips/silence
...the recording channel: I cannot hear the clicking and slips/silence (I may be wrong though, it's hard to keep speaking all the time without taking any breaths in between :-) )

Of course I meant the other way around: When I do not create the playback channels but the recording channel I am not sure about the clicking/gaps.

__________________________________


QuoteAre you using any other callback functions, eg. ASIOPROC/STREAMPROC/DSPPROC/SYNCPROC?

I'm currently only using one ASIOPROC callback function on the input, where I do this:

Private Function AsioInputCallback(input As Boolean, channel As Integer, buffer As IntPtr, length As Integer, user As IntPtr) As Integer

    If Not SuperiorTrack.IsMuted Then
        Bass.BASS_StreamPutData(PushStreamHandleDry, buffer, length)
    End If

    RingBuf.Write(buffer, length)

    Return length
End Function

But the problem also occurs when I do not even create the input channel.

But your idea sounds good (I like ChannelEnableBASS better). So would you just do the same thing I did in my AsioInputCallback in the STREAMPROC_PUSH handler? Would that work out the same way?

__________________________________________


QuoteWhere is the sample data coming from?

It's supposed to have the same sample data as TempoFXStreamHandleDrySplit1:

As you see in my code in reply #20, I use Recording.PlayBackStreamHandle for the original sample data, then add a tempofx channel (Recording.TempoFXStreamHandleDry) on it and then do this:

Recording.TempoFXStreamHandleDrySplit1 = BassMix.BASS_Split_StreamCreate(Recording.TempoFXStreamHandleDry, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_SAMPLE_FLOAT, Nothing)
Recording.TempoFXStreamHandleDrySplit2 = BassMix.BASS_Split_StreamCreate(Recording.TempoFXStreamHandleDry, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_SAMPLE_FLOAT, Nothing)

Then the second "stage" of tempo fx are applied on the tempo fx stream I created in Sub AddWetHandle().

But I can't hear any "2nd-stage-fx" in the mix.

I did it this way because you suggested to create two splitter channels in reply #19. Is this the way that you were thinking of or did I do something that's obviously wrong?

If not and I can't get this to work, I would of course also try the variety w/ the push stream.

Ian @ un4seen

Quote from: kafffeeBut your idea sounds good (I like ChannelEnableBASS better). So would you just do the same thing I did in my AsioInputCallback in the STREAMPROC_PUSH handler? Would that work out the same way?

Yes, BASSASIO will call BASS_StreamPutData to feed the ASIO input channel's data to the provided push stream. You can implement your "IsMuted" switch using BASS_ASIO_ChannelPause (and BASS_ASIO_ChannelReset to resume).

Quote from: kafffeeAs you see in my code in reply #20, I use Recording.PlayBackStreamHandle for the original sample data, then add a tempofx channel (Recording.TempoFXStreamHandleDry) on it and then do this:

Recording.TempoFXStreamHandleDrySplit1 = BassMix.BASS_Split_StreamCreate(Recording.TempoFXStreamHandleDry, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_SAMPLE_FLOAT, Nothing)
Recording.TempoFXStreamHandleDrySplit2 = BassMix.BASS_Split_StreamCreate(Recording.TempoFXStreamHandleDry, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_SAMPLE_FLOAT, Nothing)

Then the second "stage" of tempo fx are applied on the tempo fx stream I created in Sub AddWetHandle().

But I can't hear any "2nd-stage-fx" in the mix.

Are you sure it's being played/processed, eg. does BASS_ChannelGetPosition show it advancing?

In the most recent posted code, PlayBackStreamHandle doesn't appear to be played, ie. no BASS_Mixer_StreamAddChannel call with it?

kafffee

Okay, I think I managed to realize that parallel bus thing on the playback streams with the push stream instead of the split streams. Still got to get it working on the recording channels though:

I am having trouble with this (not sure if I'm doing this right):

If Recording.IsRecording Then

     If Recording.PushStreamHandleDry <> 0 Then Bass.BASS_ChannelFree(Recording.PushStreamHandleDry)

     Recording.PushStreamHandleDry = Bass.BASS_StreamCreatePush(MainModule.Song.SampleRate, 1, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_SAMPLE_FLOAT, IntPtr.Zero)


     If MainModule.Settings.AudioAPI = Enums.AudioAPIs.ASIO Then

         PrepareMixerForASIO()


         Recording.PlayBackStreamHandle = Bass.BASS_StreamCreate(MainModule.Song.SampleRate, 1, BASSFlag.BASS_STREAM_DECODE, Recording.InputStreamProc, Nothing)
         BassAsio.BASS_ASIO_ChannelEnableBASS(True, 0, Recording.PlayBackStreamHandle, True)

         BassMix.BASS_Mixer_StreamAddChannel(MainModule.Mixer, Recording.TempoFXStreamHandleDry, BASSFlag.BASS_DEFAULT)


         BassAsio.BASS_ASIO_ChannelSetFormat(True, 0, BASSASIOFormat.BASS_ASIO_FORMAT_32BIT)

Public Class Recording

Private _PlayBackStreamHandle As Integer
Public Property PlayBackStreamHandle As Integer
    Get
        Return _PlayBackStreamHandle
    End Get
    Set(value As Integer)
        _PlayBackStreamHandle = value
        TempoFXStreamHandleDry = BassFx.BASS_FX_TempoCreate(value, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_SAMPLE_FLOAT)

    End Set
End Property

Public InputStreamProc As STREAMPROC = AddressOf InputCallback

Private Function InputCallback(handle As Integer, buffer As IntPtr, length As Integer, user As IntPtr) As Integer
    If Not SuperiorTrack.IsMuted Then
        Bass.BASS_StreamPutData(PushStreamHandleDry, buffer, length)
    End If

    RingBuf.Write(buffer, length)

    Return length
End Function

End Class

I'm only hearing a loud noise instead of the sound from my mic. How do I do this right? You wrote to do it this way:


Quoteyou could use a "push" stream with BASS_ASIO_ChannelEnableBASS instead

inputstream = BASS_StreamCreate(BASS_ASIO_GetRate(), 1, BASS_SAMPLE_FLOAT | BASS_STREAM_DECODE, STREAMPROC_PUSH, NULL);
BASS_ASIO_ChannelEnableBASS(true, 0, inputstream, true);

I only found this way to create  a push stream in radio42's docs, and that overload does not take a STREAMPROC:

Recording.PushStreamHandleDry = Bass.BASS_StreamCreatePush(MainModule.Song.SampleRate, 1, BASSFlag.BASS_STREAM_DECODE, IntPtr.Zero)

Ian @ un4seen

Yeah, with BASS.Net you can use BASS_StreamCreatePush instead of BASS_StreamCreate(STREAMPROC_PUSH).

Regarding the noise, that could be due to the BASS_ASIO_ChannelSetFormat call setting the wrong format (BASS_ASIO_FORMAT_32BIT). You can remove that call because BASS_ASIO_ChannelEnableBASS sets the ASIO channel format.

kafffee

Okay the following code seems to be working, but there's a little delay in the TempoFXStreamHandleWet(0).WetTempoFXHandle.


Is there a way to play it sample-accurate synchronously to PushStreamHandleDry?:

Private Sub Play_Execute(obj As Object)
    If MainModule.Song Is Nothing Then Return
    BassAsio.BASS_ASIO_Init(0, BASSASIOInit.BASS_ASIO_DEFAULT)

    For Each Track In MainModule.Song.Tracks
        For Each Recording In Track.Recordings
            handleGC = GCHandle.Alloc(Recording, GCHandleType.Normal)


            If Recording.IsRecording Then


                If MainModule.Einstellungen.AudioAPI = Enums.AudioAPIs.ASIO Then

                    PrepareMixerForASIO()

                    If Recording.PushStreamHandleDry <> 0 Then Bass.BASS_ChannelFree(Recording.PushStreamHandleDry)
                    Recording.PushStreamHandleDry = Bass.BASS_StreamCreatePush(MainModule.Song.SampleRate, 1, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_SAMPLE_FLOAT, IntPtr.Zero)
                    Recording.TempoFXStreamHandleDry = BassFx.BASS_FX_TempoCreate(Recording.PushStreamHandleDry, BASSFlag.BASS_STREAM_DECODE)
                    BassAsio.BASS_ASIO_ChannelEnableBASS(True, 0, Recording.PushStreamHandleDry, True)
                    Recording.EnqueueTimer.IsEnabled = True

Else

                PrepareMixerForASIO()

                If Recording.PlayBackStreamHandle <> 0 Then Bass.BASS_ChannelFree(Recording.PlayBackStreamHandle)
                ' Recording.PlayBackStreamHandle = Bass.BASS_StreamCreate(MainModule.Song.SampleRate, MainModule.Song.NumberOfChannels, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_MIXER_END Or BASSFlag.BASS_SAMPLE_FLOAT, StreamProcedure, CType(handleGC, IntPtr)) 'funktioniert
                Dim filename As String
                If Recording.SuperiorTrack.TrackName = "Spur 0" Then
                    filename = "C:\1.mp3"
                ElseIf Recording.SuperiorTrack.TrackName = "Spur 1" Then
                    filename = "C:\2.mp3"
                End If
                Recording.PlayBackStreamHandle = Bass.BASS_StreamCreateFile(filename, 0, 0, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_MIXER_END Or BASSFlag.BASS_SAMPLE_FLOAT) '(MainModule.Song.SampleRate, MainModule.Song.NumberOfChannels, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_MIXER_END Or BASSFlag.BASS_SAMPLE_FLOAT, StreamProcedure, CType(handleGC, IntPtr))

                Recording.PushStreamHandleDry = Bass.BASS_StreamCreatePush(MainModule.Song.SampleRate, MainModule.Song.NumberOfChannels, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_SAMPLE_FLOAT, IntPtr.Zero)
                Recording.TempoFXStreamHandleDry = BassFx.BASS_FX_TempoCreate(Recording.PlayBackStreamHandle, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_SAMPLE_FLOAT)

                BassAsio.BASS_ASIO_ChannelEnableBASS(False, 0, MainModule.Mixer, True)

            End If
            BassMix.BASS_Mixer_StreamAddChannel(MainModule.Mixer, Recording.TempoFXStreamHandleDry, BASSFlag.BASS_DEFAULT)
            Bass.BASS_ChannelSetDSP(Recording.TempoFXStreamHandleDry, Recording.DSPProc, IntPtr.Zero, 0)
        Next

    Next
    BassAsio.BASS_ASIO_Start(1536)
    Bass.BASS_ChannelPlay(MainModule.Mixer, False)

End Sub

Public Class Recording

 Public DSPProc As DSPPROC = AddressOf DSPInputCallback

Private Sub DSPInputCallback(handle As Integer, channel As Integer, buffer As IntPtr, length As Integer, user As IntPtr)
    If TempoFXStreamHandleWet IsNot Nothing AndAlso TempoFXStreamHandleWet.Count > 0 Then
        Bass.BASS_StreamPutData(TempoFXStreamHandleWet(0).WetPushHandle, buffer, length)
    End If

    RingBuf.Write(buffer, length)

End Sub

 Private Sub AddWetHandle(sender As Object, e As ParallelBusWetHandle)
     If e.ParallelBusName = SuperiorTrack.TrackName Then
         Dim num As Integer
         If IsRecording Then num = 1 Else num = 2
         Dim PushHandle = Bass.BASS_StreamCreatePush(MainModule.Song.SampleRate, num, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_SAMPLE_FLOAT, IntPtr.Zero)
         Dim NewWetHandle As New ParallelBusWetHandle With {.ParallelBusName = e.ParallelBusName, .WetPushHandle = PushHandle, .WetTempoFXHandle = BassFx.BASS_FX_TempoCreate(PushHandle, BASSFlag.BASS_STREAM_DECODE)}
         TempoFXStreamHandleWet.Add(NewWetHandle)
         BassMix.BASS_Mixer_StreamAddChannel(MainModule.Mixer, NewWetHandle.WetTempoFXHandle, BASSFlag.BASS_DEFAULT)
     End If
 End Sub

End Class

Ian @ un4seen

If I understand correctly, you're playing the ASIO input data with (NewWetHandle.WetTempoFXHandle) and without (Recording.TempoFXStreamHandleDry) tempo processing? I think the tempo processing is likely to take them out of sync, and could be the cause of the clicks you mentioned earlier (if the tempo processing needs more data). To confirm whether that's the case, are they still out of sync if you don't enable tempo processing?

How is the MainModule.Song.SampleRate value set? I would suggest setting it to BASS_ASIO_GetRate to avoid resampling of the data between input and output. If you want to prefer a certain rate, you can try setting that in a BASS_ASIO_SetRate call first (before calling BASS_ASIO_GetRate).

kafffee

QuoteIf I understand correctly, you're playing the ASIO input data with (NewWetHandle.WetTempoFXHandle) and without (Recording.TempoFXStreamHandleDry) tempo processing?

I have enabled tempo processing on the input as well as the playback streams (both are called Recording.TempoFXStreamHandleDry), but currently have not set the BASS_ATTRIB_TEMPO_PITCH to anything other than 0.0 on them (other than the parallel bus effects, which are being applied via NewWetHandle.WetTempoFXHandle)

QuoteTo confirm whether that's the case, are they still out of sync if you don't enable tempo processing?

Yes, there's still an audible difference when I don't enable tempo processing on the parallel bus, but are still adding the push stream directly to the mixer, like this:

Dim PushHandle = Bass.BASS_StreamCreatePush(MainModule.Song.SampleRate, num, flags, IntPtr.Zero)
Dim NewWetHandle As New ParallelBusWetHandle With {.ParallelBusName = e.ParallelBusName, .WetPushHandle = PushHandle, .WetTempoFXHandle = 0} 'BassFx.BASS_FX_TempoCreate(PushHandle, BASSFlag.BASS_STREAM_DECODE)}
TempoFXStreamHandleWet.Add(NewWetHandle)
'BassMix.BASS_Mixer_StreamAddChannel(MainModule.Mixer, NewWetHandle.WetTempoFXHandle, BASSFlag.BASS_DEFAULT)
BassMix.BASS_Mixer_StreamAddChannel(MainModule.Mixer, NewWetHandle.WetPushHandle, BASSFlag.BASS_DEFAULT)

What I am trying to do is something like a light-weight DAW. It's supposed to take the signal from a track repsectively recording, then add a pitch effect to it and change the volume thereof, then redirect that signal to the mixer, in sync with the original recording. Something like a parallel bus, or also called AUX-bus.

QuoteHow is the MainModule.Song.SampleRate value set?

It's been set to 44100. Just to make sure, I changed it to a readonly property which always returns  BASS_ASIO_GetRate.

Ian @ un4seen

Quote from: kafffeeI have enabled tempo processing on the input as well as the playback streams (both are called Recording.TempoFXStreamHandleDry), but currently have not set the BASS_ATTRIB_TEMPO_PITCH to anything other than 0.0 on them (other than the parallel bus effects, which are being applied via NewWetHandle.WetTempoFXHandle)

Does that mean you have 2 tempo streams with the same source data, and one of them (TempoFXStreamHandleDry) has BASS_ATTRIB_TEMPO_PITCH=0 and the other (WetTempoFXHandle) has BASS_ATTRIB_TEMPO_PITCH!=0? If so, I think the differing BASS_ATTRIB_TEMPO_PITCH settings is quite likely to take them a bit out of sync, and that may also vary because the tempo processing's rate isn't constant (it processes varying sized blocks of data).

If you aren't already using it, you could try the latest BASS_FX build (which has the latest SoundTouch tempo processing):

    www.un4seen.com/stuff/bass_fx.zip

Quote from: kafffeeWhat I am trying to do is something like a light-weight DAW. It's supposed to take the signal from a track repsectively recording, then add a pitch effect to it and change the volume thereof, then redirect that signal to the mixer, in sync with the original recording. Something like a parallel bus, or also called AUX-bus.

Are you sure you need mutiple tempo streams in this case? Wouldn't you only need one? You could create 2 splitters from the original recording, and plug one directly into the mixer, and the other going through tempo processing. For example:

directsplit = BASS_Split_StreamCreate(original, BASS_STREAM_DECODE, 0); // create splitter from original
BASS_Mixer_StreamAddChannel(mixer, directsplit, 0); // add it to the mix
temposplit = BASS_Split_StreamCreate(original, BASS_STREAM_DECODE, 0); // create tempo processing splitter from original
temposplit = BASS_FX_TempoCreate(temposplit, BASS_STREAM_DECODE | BASS_FX_FREESOURCE); // enable tempo processing
BASS_Mixer_StreamAddChannel(mixer, temposplit, 0); // add it to the mix

Note that you don't add the "original" handle directly to the mixer when splitting it (due to the data stealing issue mentioned earlier).

kafffee

QuoteDoes that mean you have 2 tempo streams with the same source data, and one of them (TempoFXStreamHandleDry) has BASS_ATTRIB_TEMPO_PITCH=0 and the other (WetTempoFXHandle) has BASS_ATTRIB_TEMPO_PITCH!=0?

No, WetTempoFXHandle gets its data from TempoFXStreamHandleDry, but not directly:

I have this:

Bass.BASS_ChannelSetDSP(Recording.TempoFXStreamHandleDry, Recording.DSPProc, IntPtr.Zero, 0)

[...]

Public DSPProc As DSPPROC = AddressOf DSPInputCallback

Private Sub DSPInputCallback(handle As Integer, channel As Integer, buffer As IntPtr, length As Integer, user As IntPtr)
    If TempoFXStreamHandleWet IsNot Nothing AndAlso TempoFXStreamHandleWet.Count > 0 Then
        If Not SuperiorTrack.IsMuted Then
            Bass.BASS_StreamPutData(TempoFXStreamHandleWet(0).WetPushHandle, buffer, length)

        End If
    End If

    If IsRecording Then RingBuf.Write(buffer, length)

End Sub

When I add the parallel bus fx, this happens:

Dim PushHandle = Bass.BASS_StreamCreatePush(MainModule.Song.SampleRate, num, flags, IntPtr.Zero)
 Dim NewWetHandle As New ParallelBusWetHandle With {.ParallelBusName = e.ParallelBusName, .WetPushHandle = PushHandle, .WetTempoFXHandle = BassFx.BASS_FX_TempoCreate(PushHandle, BASSFlag.BASS_STREAM_DECODE)}
 TempoFXStreamHandleWet.Add(NewWetHandle)
 BassMix.BASS_Mixer_StreamAddChannel(MainModule.Mixer, NewWetHandle.WetTempoFXHandle, BASSFlag.BASS_DEFAULT)

Note that even if I set both TempoFXStreamHandledry and WetTempoFXHandle and to BASS_ATTRIB_TEMPO_PITCH = 0.0 there is an audible difference after I added WetTempoFXHandle to the mix.

__________________

I am currently using bassfx version 2.4.12.6, don't know if that's the latest version?

__________________

QuoteAre you sure you need mutiple tempo streams in this case? Wouldn't you only need one? You could create 2 splitters from the original recording, and plug one directly into the mixer, and the other going through tempo processing.

Actually not for my own personal use. But I am trying to implement this some kind of "generic" (don't know if that's the right word for this): I have a source track with effects (whether it's "normal" ones or tempo fx) added to it, then I can create a parallel bus, that has this track as a source and adds other fx to it. In the ideal case, it will play in sync with the source channel, only with the additional fx to it.

___________________

If I decide to do this w/ the splitters, will this allow me to playback the 2 streams totally in sync (sample-accurate) or will the adding of fx always delay the signal a bit?


Ian @ un4seen

Quote from: kafffeeI have this:

Bass.BASS_ChannelSetDSP(Recording.TempoFXStreamHandleDry, Recording.DSPProc, IntPtr.Zero, 0)

[...]

Public DSPProc As DSPPROC = AddressOf DSPInputCallback

Private Sub DSPInputCallback(handle As Integer, channel As Integer, buffer As IntPtr, length As Integer, user As IntPtr)
    If TempoFXStreamHandleWet IsNot Nothing AndAlso TempoFXStreamHandleWet.Count > 0 Then
        If Not SuperiorTrack.IsMuted Then
            Bass.BASS_StreamPutData(TempoFXStreamHandleWet(0).WetPushHandle, buffer, length)

        End If
    End If

    If IsRecording Then RingBuf.Write(buffer, length)

End Sub

That looks like WetPushHandle does ultimately get the same data as TempoFXStreamHandleDry? Instead of using a DSP function on TempoFXStreamHandleDry to forward the data to WetPushHandle, you could use splitters on the source (like in the snippet in my previous post). Using a DSP function on one stream to feed another stream depends on the 1st stream being processed before the 2nd stream, otherwise there will be a delay in the 2nd stream (it won't see the data until the next update cycle).

Quote from: kafffeeI am currently using bassfx version 2.4.12.6, don't know if that's the latest version?

That is the current release version, but not the latest build. You could try the latter (posted above) and see if it helps. I did a quick comparison of them with BASS_ATTRIB_TEMPO_PITCH=1, and both actually made the sound a bit earlier than in the original (a negative delay), but the difference was smaller with the latest build.

kafffee

#36
QuoteUsing a DSP function on one stream to feed another stream depends on the 1st stream being processed before the 2nd stream, otherwise there will be a delay in the 2nd stream (it won't see the data until the next update cycle).

Ah okay, that's just what I thought.

Quoteyou could use splitters on the source

Okay, I will try that. By the way, is it possible to create a split stream from another split stream, just in case I still want to have two tempo effects in a row, i.e. use the "wet signal" from the source channel to create another tempo stream from it?

______________________________

Edit:

Tried that option w/ the split streams. Even when I'm using the "dry" source signal, there is a well audible delay. Which makes sense, the computer takes a bit time to calculate the pitch. But is there a way, to eiher compensate that or decrease it? Maybe one of the following?:

1. Measure the delay of the tempo stream then playback the source with this delay?
2. Use a VST
3. Use another function than the one that comes with bass_fx?
4. anything other than that?

PS: I am using the latest bass_fx build now.

Ian @ un4seen

Quote from: kafffeeOkay, I will try that. By the way, is it possible to create a split stream from another split stream, just in case I still want to have two tempo effects in a row, i.e. use the "wet signal" from the source channel to create another tempo stream from it?

Yes, you can create splitter streams from another splitter stream, ie. use a splitter stream handle in BASS_Split_StreamCreate calls.

Quote from: kafffeeTried that option w/ the split streams. Even when I'm using the "dry" source signal, there is a well audible delay. Which makes sense, the computer takes a bit time to calculate the pitch.

Please post that code, to show how you're creating and starting the streams that you're seeing a delay between. Also, how long is the delay?

kafffee

QuotePlease post that code

The creation of the recording channels:

 PrepareMixerForASIO()

 If Recording.PushStreamHandleDry <> 0 Then Bass.BASS_ChannelFree(Recording.PushStreamHandleDry)

 Recording.PushStreamHandleDry = Bass.BASS_StreamCreatePush(MainModule.Song.SampleRate, 1, BASSFlag.BASS_STREAM_DECODE, IntPtr.Zero)
 MessageBox.Show("streamcreatepush: " & Bass.BASS_ErrorGetCode.ToString & "; " & Recording.SuperiorTrack.TrackName)
 'Recording.TempoFXStreamHandleDry = BassFx.BASS_FX_TempoCreate(Recording.PushStreamHandleDry, BASSFlag.BASS_STREAM_DECODE)
 Recording.SplitOriginal = BassMix.BASS_Split_StreamCreate(Recording.PushStreamHandleDry, BASSFlag.BASS_STREAM_DECODE, Nothing)

 BassAsio.BASS_ASIO_ChannelEnableBASS(True, 0, Recording.PushStreamHandleDry, True)
 BassMix.BASS_Mixer_StreamAddChannel(MainModule.Mixer, Recording.SplitOriginal, BASSFlag.BASS_DEFAULT)

respectively the normal playback channels:

PrepareMixerForASIO()

If Recording.PlayBackStreamHandle <> 0 Then Bass.BASS_ChannelFree(Recording.PlayBackStreamHandle)
' Recording.PlayBackStreamHandle = Bass.BASS_StreamCreate(MainModule.Song.SampleRate, MainModule.Song.NumberOfChannels, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_MIXER_END Or BASSFlag.BASS_SAMPLE_FLOAT, StreamProcedure, CType(handleGC, IntPtr)) 'funktioniert

Recording.PlayBackStreamHandle = Bass.BASS_StreamCreateFile(filename, 0, 0, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_MIXER_END Or BASSFlag.BASS_SAMPLE_FLOAT) '(MainModule.Song.SampleRate, MainModule.Song.NumberOfChannels, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_MIXER_END Or BASSFlag.BASS_SAMPLE_FLOAT, StreamProcedure, CType(handleGC, IntPtr))

'Recording.TempoFXStreamHandleDry = BassFx.BASS_FX_TempoCreate(Recording.PlayBackStreamHandle, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_SAMPLE_FLOAT)
Recording.SplitOriginal = BassMix.BASS_Split_StreamCreate(Recording.PlayBackStreamHandle, BASSFlag.BASS_STREAM_DECODE, Nothing)
MessageBox.Show("err...:" & Bass.BASS_ErrorGetCode.ToString)


BassAsio.BASS_ASIO_ChannelEnableBASS(False, 0, MainModule.Mixer, True)
BassMix.BASS_Mixer_StreamAddChannel(MainModule.Mixer, Recording.SplitOriginal, BASSFlag.BASS_DEFAULT)

Then adding the fx of the parallel bus:

Private Sub AddWetHandle(sender As Object, e As ParallelBusWetHandle)
    If e.ParallelBusName = SuperiorTrack.TrackName Then
        Dim num As Integer
        Dim flags As BASSFlag = BASSFlag.BASS_STREAM_DECODE
        If IsRecording Then
            num = 1
        Else
            num = 2
            flags = flags Or BASSFlag.BASS_SAMPLE_FLOAT
        End If
     
        Dim SplitForParBus As Integer = BassMix.BASS_Split_StreamCreate(PushStreamHandleDry, BASSFlag.BASS_STREAM_DECODE, Nothing)
        Dim NewWetHandle As New ParallelBusWetHandle With {.ParallelBusName = e.ParallelBusName, .WetPushHandle = SplitForParBus, .WetTempoFXHandle = BassFx.BASS_FX_TempoCreate(SplitForParBus, BASSFlag.BASS_STREAM_DECODE)}
        TempoFXStreamHandleWet.Add(NewWetHandle)
        BassMix.BASS_Mixer_StreamAddChannel(MainModule.Mixer, NewWetHandle.WetTempoFXHandle, BASSFlag.BASS_DEFAULT)
        'BassMix.BASS_Mixer_StreamAddChannel(MainModule.Mixer, NewWetHandle.WetPushHandle, BASSFlag.BASS_DEFAULT)
        'MessageBox.Show("streamaddchannel push: " & Bass.BASS_ErrorGetCode.ToString & "; " & SuperiorTrack.TrackName)
    End If
End Sub

_______________


QuoteAlso, how long is the delay?

Is there a way to measure it?

I can definitely say that for instance in case of the playback channels, it sounds "richer"/fuller (even if pitch is set to 0.0), and in case of the recording channels, it's more than that: You can actually hear what I'm speaking in the mic twice, i.e. it's more than a doubling effect, you can actually tell the original signal from the parallel bus signal by ear, like it's been spoken twice.

Ian @ un4seen

You can measure a delay between the mixer sources by setting a WAV writer (BASS_Encode_StartPCMFile) on the mixer (MainModule.Mixer), and playing a file containing a very short pulse of sound (eg. sinewave) through it, and then loading the written WAV file in a sample editor to see if there are now multiple pulses and what the gap is between them. If there's no delay, then there should just be one louder pulse (due to mixing multiple copies of the same sound).

kafffee

Quotecontaining a very short pulse of sound (eg. sinewave) through it

Which would be the perfect length for the sinewave to do this in your opinion?

Ian @ un4seen

You could just have a single cycle (see the attached file). You want the sound to be shorter than the delay because then there'll be a gap between each pulse of sound, which makes it clear to see where each pulse begins.