Trying to record usb mic and mp3, but only hear mp3 through soundcard output

Started by chrisw100,

chrisw100

hello,

ive hit a snag that i cant fathom. In the case below. Im creating two mixers, a monitormixer so i just hear the mp3 file play, and a recordmixer that records the USB mic and the mp3 file when its manually played to a wav. So with the code shown below, I hear the mp3 play out the soundcard and no USB mic (as desired but the mp3 file doesnt appear on the recording). If i change the line 'BASS_StreamCreateFile("test.mp3", 0, 0, BASSFlag.BASS_SAMPLE_FLOAT)' to be DECODE dont hear the mp3 play out but it does get recorded to the wav file. However on that recording while the mp3 file is playing, the audio from the USB mic gets choppy, then when the mp3 file has finished playing / stopped manually, the usb mic audio is again fine).

Any thoughts what im missing ?

thank you.


   Private Sub btnStartRecording_Click(sender As Object, e As EventArgs) Handles btnStartRecording.Click
       'Create Record Mixer
       recordMixer = BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_DEFAULT)
       Console.WriteLine($"recordMixer={recordMixer}")

       'Create Monitor Mixer
       monitorMixer = BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_DEFAULT) ' NOT decode → can be played
       Console.WriteLine($"monitorMixer={monitorMixer}")

       'Create Jingle to mix into both mixers (on user demand)
       FileStream = Bass.BASS_StreamCreateFile("test.mp3", 0, 0, BASSFlag.BASS_SAMPLE_FLOAT)
       JingleSplit1 = BassMix.BASS_Split_StreamCreate(FileStream, BASSFlag.BASS_SAMPLE_FLOAT, Nothing)
       JingleSplit2 = BassMix.BASS_Split_StreamCreate(FileStream, BASSFlag.BASS_SAMPLE_FLOAT, Nothing)

       'Create Soundcard Channel
       inputStream = Bass.BASS_RecordStart(44100, 2, BASSFlag.BASS_STREAM_DECODE, Nothing, IntPtr.Zero)
       Console.WriteLine($"inputStream={inputStream}")
       BassMix.BASS_Mixer_StreamAddChannel(recordMixer, inputStream, BASSFlag.BASS_MIXER_CHAN_DOWNMIX)

       'Start Mixers

       Bass.BASS_ChannelPlay(recordMixer, False)
       Bass.BASS_ChannelPlay(monitorMixer, False)

       'Start Recording
       encoder = BassEnc.BASS_Encode_Start(recordMixer, "output.wav", BASSEncode.BASS_ENCODE_PCM, Nothing, IntPtr.Zero)
       Console.WriteLine($"encoder={encoder}")
       If encoder = 0 Then
           Timer1.Enabled = True
       End If
   End Sub
   Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
       If encoder = 0 Then Exit Sub
       Dim buf(4095) As Byte
       Bass.BASS_ChannelGetData(recordMixer, buf, buf.Length)
   End Sub

   Private Sub btnPlay_Click(sender As Object, e As EventArgs) Handles btnPlay.Click
       'Start Jingle to both mixers

       BassMix.BASS_Mixer_StreamAddChannel(monitorMixer, JingleSplit1, BASSFlag.BASS_DEFAULT)
       BassMix.BASS_Mixer_StreamAddChannel(recordMixer, JingleSplit2, BASSFlag.BASS_DEFAULT)
       Bass.BASS_ChannelPlay(FileStream, False)
   End Sub

Ian @ un4seen

Quote from: chrisw100      FileStream = Bass.BASS_StreamCreateFile("test.mp3", 0, 0, BASSFlag.BASS_SAMPLE_FLOAT)
      JingleSplit1 = BassMix.BASS_Split_StreamCreate(FileStream, BASSFlag.BASS_SAMPLE_FLOAT, Nothing)
      JingleSplit2 = BassMix.BASS_Split_StreamCreate(FileStream, BASSFlag.BASS_SAMPLE_FLOAT, Nothing)

Those BASS_Split_StreamCreate calls will be failing because FileStream isn't a decoding channel. Splitter and mixer sources need to be decoding channels, so the BASS_STREAM_DECODE flag should be added to all 3 calls. You can also remove the BASS_SAMPLE_FLOAT flag from the BASS_Split_StreamCreate calls, as a spitter automatically has the same sample format as its source.

The later BASS_ChannelPlay call on FileStream can/should be removed, or do you also want it played outside of the 2 mixers? If you do then you can create another splitter (without BASS_STREAM_DECODE) for that.

Quote from: chrisw100      BassMix.BASS_Mixer_StreamAddChannel(recordMixer, inputStream, BASSFlag.BASS_MIXER_CHAN_DOWNMIX)

The BASS_MIXER_CHAN_LIMIT flag should be added to this call to to fix the choppy recording issue (by limiting the mixer's processing to what the recording has available). Please see the BASS_Mixer_StreamAddChannel documentation for details.

chrisw100

Thank you ian, the recording doesnt chop anymore.

However, im noticing when going from record pause (to see microphone levels before recording) to going into record (where it records the wav), im getting the last second or so. For example if i count in 1-4 then press record, im hearing the word 4, and then when i play the Jingle, its out of line with my voice when i press play on the jingle, and when i press stop record, it cuts off my last word or two. im guessing this is a buffering issue somewhere ?

So the sequence of events is, Record Pause, then Start Record. At some point BtnPlay to play the jingle when required, and then Stop Recording. Timer1 is set to 20 interval time. Ive shown the first part of UpdatePPM to show the code that grabs the levels and leave the data in the buffer.

here is the code im using if you are able to suggest anything, that would be appreciated.

    Private Sub BtnRecordPause_Click(sender As Object, e As EventArgs) Handles BtnRecordPause.Click
        'Create Record Mixer
        recordMixer = BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_STREAM_DECODE)
        Console.WriteLine($"recordMixer={recordMixer}")

        'Create Monitor Mixer
        monitorMixer = BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_SAMPLE_FLOAT) ' NOT decode → can be played
        Console.WriteLine($"monitorMixer={monitorMixer}")

        'Create Jingle into both mixers (on user demand)
        FileStream = Bass.BASS_StreamCreateFile("test.mp3", 0, 0, BASSFlag.BASS_STREAM_DECODE)
        JingleSplit1 = BassMix.BASS_Split_StreamCreate(FileStream, BASSFlag.BASS_STREAM_DECODE, Nothing)
        JingleSplit2 = BassMix.BASS_Split_StreamCreate(FileStream, BASSFlag.BASS_STREAM_DECODE, Nothing)

        'Start record pause to show levels prior to recording
        inputStream = Bass.BASS_RecordStart(44100, 2, BASSFlag.BASS_RECORD_PAUSE, Nothing, IntPtr.Zero)
        Console.WriteLine($"inputStream={inputStream}")
        BassMix.BASS_Mixer_StreamAddChannel(recordMixer, inputStream, BASSFlag.BASS_MIXER_CHAN_LIMIT)

        'Start Record Channel
        Bass.BASS_ChannelPlay(inputStream, False)

        'Start Mixers
        Bass.BASS_ChannelPlay(recordMixer, False)
        Bass.BASS_ChannelPlay(monitorMixer, False)
        Timer1.Enabled = True

    End Sub
    Private Sub btnStartRecording_Click(sender As Object, e As EventArgs) Handles btnStartRecording.Click
        'Start Recording
        encoder = BassEnc.BASS_Encode_Start(recordMixer, "output.wav", BASSEncode.BASS_ENCODE_PCM, Nothing, IntPtr.Zero)
        Console.WriteLine($"encoder={encoder}")
    End Sub
    Private Sub btnPlay_Click(sender As Object, e As EventArgs) Handles btnPlay.Click
        'Start Jingle to both mixers
        BassMix.BASS_Mixer_StreamAddChannel(recordMixer, JingleSplit1, BASSFlag.BASS_DEFAULT)
        BassMix.BASS_Mixer_StreamAddChannel(monitorMixer, JingleSplit2, BASSFlag.BASS_DEFAULT)
    End Sub

    Private Sub btnStop_Click(sender As Object, e As EventArgs) Handles btnStop.Click
        'Bass.BASS_ChannelStop(monitorMixer)
        Bass.BASS_ChannelStop(fileStreamPlay)
    End Sub
    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        ' audio meter code
        UpdatePPM()
        Dim buf(4095) As Byte
        Bass.BASS_ChannelGetData(recordMixer, buf, buf.Length)
    End Sub
    Sub UpdatePPM()
        If inputStream = 0 Then Exit Sub
        Dim LeftLevel As Single, RightLevel As Integer, lvl() As Single
        If inputStream <> 0 Then lvl = Bass.BASS_ChannelGetLevels(inputStream, 0.02, BASSLevel.BASS_LEVEL_RMS Or BASSLevel.BASS_LEVEL_NOREMOVE)

chrisw100

it does seem like setting the timer to a quicker (lower value) may have sorted this, by getting data from the buffers quicker. ive set the timer interval to 10.

Ian @ un4seen

Yeah, if the timer isn't processing quickly enough then that would cause of build-up of data in the recording's buffer, which could explain your delayed start/stop actions. If you monitor the timer's BASS_ChannelGetData return value, you want it to be lower than the requested amount. Increasing the requested amount ("buf" size) may be a more efficient way to achieve that than lowering the timer period.