Mixing two stream channels and record result to hard disk/stream to web

Started by kafffee,

kafffee

There is no BASS_MIXER_CHAN_BUFFER provided, only BASS_MIXER_BUFFER. Am I using an obsolete version of BassMix.dll? Currently I got version 2.4.10.0

And is this correct?:

Dim peak() As Single = {0, 0}
Dim Flagge As BASSLevel = CType(16, BASSLevel)
BassMix.BASS_Mixer_ChannelGetLevel(MainModule.streamfx(WhichDeck - 1), peak, 0.1, Flagge Or BASSLevel.BASS_LEVEL_STEREO)

or should i go with this:

peakint = BassMix.BASS_Mixer_ChannelGetLevel(MainModule.streamfx(WelchesDeck - 1))

kafffee

OK did this - still no change.

But thinking of the word "buffer": I removed this from directly after my BASS_Mixer_StreamCreate call:

Bass.BASS_ChannelSetAttribute(MainModule.mixer, BASSAttribute.BASS_ATTRIB_BUFFER, 0)
Now i can play my music without adding the mic to the mix before. Its still chopped up, but it plays, and the peak meter looks like it's working fine... Maybe "chopped up" is the wrong word. It seems like "a bit out of order"... Its hard to tell but it also seems like its slowly increasing playback speed at the beginning... I might be wrong though...

Maybe I gotta try something with BASS_CONFIG_BUFFER? What do you think? What would be a good value?

Or maybe it has something to do with my BASS_ATTRIB_TEMPO and BASS_ATTRIB_TEMPO_PITCH calls, which I apply on streamfx

Ian @ un4seen

The mixer's playback buffer shouldn't affect whether sources are heard in the mix. If it sounds like bits of a source are being skipped then there are probably still some BASS_ChannelGetLevel/Data calls on the source somewhere. Looking again at the code you posted above, I suspect it's the Spektrum.CreateSpectrumLinePeak call, which will be using BASS_ChannelGetData internally by default. BASS.Net's Visuals class has a "ChannelIsMixerSource" property that you can set to "true" to make it use BASS_Mixer_ChannelGetData instead.

kafffee

Thank God it works  ;D Thank you so much guys!!

There's a little problem left though.... When I use Bass.BASS_ChannelSetAttribute(MainModule.mixer, BASSAttribute.BASS_ATTRIB_BUFFER, 0) after my BASS_Mixer_StreamCreate call, the music wont start playing at all, neither does the peak meter and spectrum analyzer show any action. When I do leave it out, everything works fine but the microphone which is added to the stream as well, has this long delay again. What can I do to fix this?

Ian @ un4seen

That's strange. If you monitor what BASS_ChannelIsActive and BASS_ChannelGetPosition say about the mixer, does it show the mixer is active and advancing? If not, also check the mixer's BASS_ChannelPlay return value.

kafffee

BASS_ChannelPlay(mixer) returns 0, but BASS_ChannelIsActive(mixer) returns 2 - Playback of the stream has been stalled due to there not being enough sample data to continue playing. The playback will automatically resume once there's sufficient data to do so.
BASS_ChannelGetPosition(mixer) starts increasing as soon as I play a song via StreamAddChannel

Ian @ un4seen

Did you mean BASS_ChannelPlay is returning 0, or the error code is 0? If the former then that means the call failed - please check the error code with BASS_ErrorGetCode. If BASS_ChannelPlay is successful then next check what BASS_Mixer_ChannelIsActive says about the source.

kafffee

BASS_ChannelPlay(mixer) returns BASS_ErrorGetCode = 0, and also BASS_Mixer_ChannelIsActive(streamfx(0)) returns 1 (The channel is playing (or recording)) when I add my stream to the mixer, no matter if I do BASS_ChannelSetAttribute(MainModule.mixer, BASSAttribute.BASS_ATTRIB_BUFFER, 0) or not

Ian @ un4seen

OK. To get a clearer picture of what's happening, please post the mixer and source setup code that's producing the problem.

kafffee

Sure  :)

I'm initializing with this:

Public Sub GetPlaybackDevices()
        Dim PlaybackDeviceInfo As New BASS_DEVICEINFO
        For i = 0 To Bass.BASS_GetDeviceCount - 1
            Bass.BASS_GetDeviceInfo(i, PlaybackDeviceInfo)
            Speakers.Add(PlaybackDeviceInfo.name)
            If IsInDesignMode = False Then          'only initialize when  in runtime
                Bass.BASS_Init(i, 44100, BASSInit.BASS_DEVICE_DEFAULT, Nothing)
            End If
        Next
        Headphones = Speakers 'Headphones and Speakers are each a list of playback devices
        SpeakerIndex = 1           'Selecting playback devices via index. this is the index of Headphones and Speakers
        HeadphoneIndex = 1
    End Sub

I am selecting playback devices like this: (same as for HeadphoneIndex)

Private _SpeakerIndex As Integer
    Public Property SpeakerIndex As Integer
        Get
            Return _SpeakerIndex
        End Get
        Set(value As Integer)
            _SpeakerIndex = value
            Bass.BASS_ChannelSetDevice(MainModule.mixer, value)
            Debug.WriteLine("setdevice mixer to speaker: " & Bass.BASS_ErrorGetCode)
            RaisePropertyChanged()
        End Set
    End Property

I am creating the mixer as follows:

GetPlaybackDevices()

MainModule.mixer = Un4seen.Bass.AddOn.Mix.BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_DEFAULT Or BASSFlag.BASS_SAMPLE_FLOAT)
        Debug.WriteLine("mixerstreamcerate" & Bass.BASS_ErrorGetCode)
        Bass.BASS_ChannelSetAttribute(MainModule.mixer, BASSAttribute.BASS_ATTRIB_BUFFER, 0) ' disable playback buffering'
        'Debug.WriteLine("mixer disable playback buffering: " & Bass.BASS_ErrorGetCode)
        Bass.BASS_ChannelSetDevice(MainModule.mixer, SpeakerIndex)
        Debug.WriteLine("set mixerdevice to selected speaker: " & Bass.BASS_ErrorGetCode)
        Bass.BASS_ChannelPlay(MainModule.mixer, False)
        Debug.WriteLine("mixer play: " & Bass.BASS_ErrorGetCode)
        Debug.WriteLine("bass_channelisactive: " & CStr(Bass.BASS_ChannelIsActive(MainModule.mixer)))
        Debug.WriteLine("bass.channelgetposition: " & CStr(Bass.BASS_ChannelGetPosition(MainModule.mixer)))

When I hit play, the following is being executed:

 Public Sub Play_Execute(obj As Object)
        Bass.BASS_ChannelStop(stream)
        If stream <> 0 Then Bass.BASS_StreamFree(stream)
        stream = Bass.BASS_StreamCreateFile(Playlist(PlaylistSelectedIndex).Filename, 0, 0, BASSFlag.BASS_STREAM_PRESCAN Or BASSFlag.BASS_STREAM_DECODE)
        Debug.WriteLine("streamcreatefile: " & CStr(Bass.BASS_ErrorGetCode))

        If MainModule.streamfx(WhichDeck - 1) <> 0 Then Bass.BASS_StreamFree(MainModule.streamfx(WhichDeck - 1))

        MainModule.streamfx(WhichDeck - 1) = BassFx.BASS_FX_TempoCreate(stream, BASSFlag.BASS_FX_FREESOURCE Or BASSFlag.BASS_STREAM_DECODE)
        Debug.WriteLine("tempocreate: " & CStr(Bass.BASS_ErrorGetCode))
        Bass.BASS_ChannelSetDevice(MainModule.mixer, SpeakerIndex)
        Debug.WriteLine("channelsetdevice" & Bass.BASS_ErrorGetCode)
        BassMix.BASS_Mixer_StreamAddChannel(MainModule.mixer, MainModule.streamfx(WhichDeck - 1), BASSFlag.BASS_MIXER_NORAMPIN Or BASSFlag.BASS_STREAM_AUTOFREE Or BASSFlag.BASS_MIXER_BUFFER)
        Debug.WriteLine("add stream to mix: " & CStr(Bass.BASS_ErrorGetCode))
        MainModule.MeinEQ(WhichDeck - 1) = New Equalizer(MainModule.streamfx(WhichDeck - 1))
        MainModule.MeinEQ(WhichDeck - 1).EQ_Init()
        MainModule.VisualizationTimer.Start()
    End Sub

VisualizationTimer calls this every 25 milliseconds:

Public Sub ShowPeak(ByVal sender As Object, ByVal e As EventArgs)
        Dim Flag As BASSLevel = CType(16, BASSLevel)
       
        BassMix.BASS_Mixer_ChannelGetLevel(MainModule.streamfx(WhichDeck - 1), peak, 0.1, Flag Or BASSLevel.BASS_LEVEL_STEREO)
        If peak IsNot Nothing Then
            'Debug.WriteLine("L" & CStr(peak(0)) & "R" & CStr(peak(1)))
            Debug.WriteLine("bass.channelgetposition: " & CStr(Bass.BASS_ChannelGetPosition(MainModule.mixer)))
            Debug.WriteLine("bass.cjannelisactive: " & CStr(BassMix.BASS_Mixer_ChannelIsActive(MainModule.streamfx(0))))
            PeakLeft = peak(0)
            PeakRight = peak(1)
        End If
    End Sub

and this:

Private Sub UpdateVisualization(ByVal sender As Object, ByVal e As EventArgs)
        BMP = Spektrum.CreateSpectrumLinePeak(MainModule.streamfx(WhichEQ - 1), Width, Height, System.Drawing.Color.Green, System.Drawing.Color.IndianRed, System.Drawing.Color.SlateGray, System.Drawing.Color.Transparent, Resolution, 3, Distance, 40, False, True, True)
        Bild = BitmapToImageSource(BMP)
    End Sub

There  is also code to add input devices, I dont know if its relevant, it follows the same pattern as GetPlaybackDevices():

Public Sub GetRecordingDevices()
        Dim RecordingDeviceInfo As New BASS_DEVICEINFO
        For i = 0 To Bass.BASS_RecordGetDeviceCount - 1
            Bass.BASS_RecordGetDeviceInfo(i, RecordingDeviceInfo)
            Microphone.Add(RecordingDeviceInfo.name)
            If IsInDesignMode = False Then
                Bass.BASS_RecordInit(i)
            End If
        Next
        LineIn = Microphone
        MicrophoneIndex = 0
        LineInIndex = 0
    End Sub

This code produces of course some invalid handlers, is this relevant to the issue? I did not get to fix this yet....

Private _MikrophoneIndex As Integer
    Public Property MicrophoneIndex As Integer
        Get
            Return _MicrophoneIndex
        End Get
        Set(value As Integer)
            _MicrophoneIndex = value

            BassMix.BASS_Mixer_ChannelRemove(MainModule.mikro)
            Debug.WriteLine("mikro channelremove: " & Bass.BASS_ErrorGetCode)
            Bass.BASS_RecordSetDevice(value)
            Debug.WriteLine("recordsetdevice mikro: " & CStr(Bass.BASS_ErrorGetCode))
            MainModule.mikro = Bass.BASS_RecordStart(44100, 1, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_SAMPLE_FLOAT, Nothing, IntPtr.Zero)
            Debug.WriteLine("recordstart mikro: " & CStr(Bass.BASS_ErrorGetCode))
            BassMix.BASS_Mixer_StreamAddChannel(MainModule.mixer, MainModule.mikro, BASSFlag.BASS_MIXER_NORAMPIN Or BASSFlag.BASS_STREAM_AUTOFREE)
            Debug.WriteLine("mikro streamaddchannel: " & Bass.BASS_ErrorGetCode)
            RaisePropertyChanged()
        End Set
    End Property

Ian @ un4seen

OK. Next please try reducing that code to the minimum required to produce the problem, and post that. For example, does it still happen if you basically just create the mixer and add the file to it, without any effects and vis stuff?

kafffee

Yes it still happens with this when I reduce to this: (I also encountered no errors, BASS_ErrorGetCode returns 0 on any call)

Edit:
When I skip BASS_ChannelSetDevice, it works.... But I don't know why, there is no error...

Edit2: Okay I see - there is no need to keep it - I already set the Speaker device in GetPlaybackDevices... But would be interesting to know why it behaves that way...

Public Sub Play_Execute(obj As Object)
Bass.BASS_ChannelStop(stream)
        If stream <> 0 Then Bass.BASS_StreamFree(stream)
        stream = Bass.BASS_StreamCreateFile(Playlist(PlaylistSelectedIndex).Filename, 0, 0, BASSFlag.BASS_STREAM_PRESCAN Or BASSFlag.BASS_STREAM_DECODE)
Bass.BASS_ChannelSetDevice(MainModule.mixer, 2)
        BassMix.BASS_Mixer_StreamAddChannel(MainModule.mixer, stream, BASSFlag.BASS_MIXER_NORAMPIN Or BASSFlag.BASS_STREAM_AUTOFREE Or BASSFlag.BASS_MIXER_BUFFER)
End Sub

Ian @ un4seen

If you call BASS_ChannelGetDevice before and after BASS_ChannelSetDevice, which values do you get?

kafffee

Don't know if you have read my two edits, but:

When I set to index 1 in GetPlaybackDevices and I set to 2 in Play_Execute()

I get the same before and after: 5 (which would be the speakers of my screen)

Ian @ un4seen

BASS_ChannelGetDevice is returning 5 after the BASS_ChannelSetDevice call with device=2? If so, please also check the BASS_ChannelSetDevice return value and error code.

kafffee

QuoteBASS_ChannelGetDevice is returning 5 after the BASS_ChannelSetDevice call with device=2?

Yes. And BASS_ChannelSetDevice is returning True and BASS_ErrorGetCode 0.

Ian @ un4seen

That's very strange then, as I don't see how it's possible for BASS_ChannelSetDevice to succeed without actually setting the device. Can you confirm that 5 is the BASS_ChannelGetDevice return value, not the error code? If it's the error code (BASS_ERROR_HANDLE), that may make more sense. Are you definitely using the same handle in the BASS_ChannelSetDevice and BASS_ChannelGetDevice calls?

kafffee

Hey Ian, sorry for the late response, I've been very busy this week.  :(

I checked again, and you were right, all of the returned values are good. So for me, everything is fine.

But I encountered another issue:

When I want to pause/resume playback of a source channel, I get 8658944 as a result of BASS_Mixer_ChannelFlags (both calls), but nothing happens. This is my code:

Public IsPlaying As Boolean = False
 Public IsNewSong As Boolean = True


Public Sub Play_Execute(obj As Object)

If IsNewSong = True Then
            Bass.BASS_ChannelStop(stream)
            BassMix.BASS_Mixer_ChannelRemove(MainModule.streamfx(WhichDeck - 1))
            If stream <> 0 Then Bass.BASS_StreamFree(stream)
            stream = Bass.BASS_StreamCreateFile(CurrentMP3Info.Filename, 0, 0, BASSFlag.BASS_STREAM_PRESCAN Or BASSFlag.BASS_STREAM_DECODE)

            If MainModule.streamfx(WhichDeck - 1) <> 0 Then Bass.BASS_StreamFree(MainModule.streamfx(WhichDeck - 1))

            MainModule.streamfx(WhichDeck - 1) = BassFx.BASS_FX_TempoCreate(stream, BASSFlag.BASS_FX_FREESOURCE Or BASSFlag.BASS_STREAM_DECODE)
           
BassMix.BASS_Mixer_StreamAddChannel(MainModule.mixer, MainModule.streamfx(WhichDeck - 1), BASSFlag.BASS_MIXER_NORAMPIN Or BASSFlag.BASS_STREAM_AUTOFREE Or BASSFlag.BASS_MIXER_BUFFER)
IsPlaying = True
Else
If IsPlaying = True Then
                Dim success As BASSFlag = BassMix.BASS_Mixer_ChannelFlags(MainModule.streamfx(WhichDeck - 1), BASSFlag.BASS_MIXER_PAUSE, BASSFlag.BASS_DEFAULT)
                Debug.WriteLine(CStr(success))      'success returns 8658944
                IsPlaying = False
                IsNewSong = False
            Else
                Dim success As BASSFlag = BassMix.BASS_Mixer_ChannelFlags(MainModule.streamfx(WhichDeck - 1), Nothing, BASSFlag.BASS_DEFAULT)
                Debug.WriteLine(CStr(success))      'success returns 8658944
                IsPlaying = True
                IsNewSong = False
            End If
        End If
End Sub

Play_Execute is called when I hit the play/pause button.

When I want to start a new song, PlayNewTrack is called:

Public Sub PlayNewTrack_Execute(obj As Object)
        CurrentMP3Info = Playlist(PlaylistSelectedIndex)
        IsNewSong = True
        Abspielen_Execute(Nothing)
        IsNewSong = False
    End Sub

What am I doing wrong?

I guess it's something with the BassMix.BASS_Mixer_ChannelFlags calls... I cannot find the bass flag value 8658944 in the .NET docs of Bassflag...

Ian @ un4seen

Good to hear that the previous issue is resolved.

8658944 is 0x842000 in hex, which means these flags are set: BASS_MIXER_CHAN_BUFFER (0x2000), BASS_STREAM_AUTOFREE (0x40000), BASS_MIXER_CHAN_NORAMPIN (0x800000).

The issue in your case appears to be that your BASS_Mixer_ChannelFlags "mask" parameter is 0, which means don't modify any flags (only fetch them). If you want to change the BASS_MIXER_PAUSE flag then that should be included there, like this:

BASS_Mixer_ChannelFlags(channel, BASS_MIXER_PAUSE, BASS_MIXER_PAUSE); // set PAUSE flag

BASS_Mixer_ChannelFlags(channel, 0, BASS_MIXER_PAUSE); // remove PAUSE flag