Author Topic: Sound file lengths sometimes shorter than they should be when recording.  (Read 232 times)

Chris Oakley

  • Posts: 17
This might be a quick one. Does anyone know why I would occasionally see a shorter file length than I should when recording. I've written an audio logger. It simply records hour long files, so at the start of an hour it begins and at the end it closes the current recording and starts a new one. This is regardless of if I use the WaveWriter in BASS.NET or encode using Lame.exe etc.

What I will get is a bunch of lengths like 01:00:00 which is what I expect. But then I get the odd 00:59:40 or 00:59:58.

There's no reason for this and the files are named with the date and time and they're all spot on where they should be. The other oddity is I did this with short lengths, instead of 1 hour I just did 20 second segments and again I would get a bunch of files all 20 seconds long but then the odd one which was 10 seconds or in one case 6 seconds long.

Now, I thought "I must be missing some audio here", but when I took the files and pasted them all together they were seamless. No drop outs, no missing audio, nothing.

Has anyone else seen this behaviour? It's driving my OCD mad.

Ian @ un4seen

  • Administrator
  • Posts: 20393
How are you recording? If you are using WASAPI loopback recording (mentioned in your other thread), note that a loopback device will only produce data while the corresponding output device is active. You can force that by also initializing the output device via BASS_WASAPI_Init (no need to actually play anything on it). The corresponding output device always immediately precedes a loopback device in the BASSWASAPI device list. If you're using the default loopback device (-3), then you can also initialize the default output device (-1). When you have multiple WASAPI devices initialized (eg. an output and its loopback), you will need to use BASS_WASAPI_SetDevice to set which device subsequent BASSWASAPI function calls are to be applied to. Please see the BASS_WASAPI_SetDevice documentation for details.

If that's all good, also confirm how you are timing when to start a new recording, eg. is it based on the system clock or on how much data has been received from the recording? Also, are you actually stopping and restarting recording each time or just setting a new file writer on the same recording? I would suggest the latter, to avoid dropped data between the files.

Chris Oakley

  • Posts: 17
Thanks Ian. I'm using ASIO in this instance not WASAPI but I'm recording an outgoing stream. So I'm casting but I'm also recording the encoder channel which is doing that on a different encoder channel - if that makes sense.

I'm timing using a simple timer which fires every 500 milliseconds just to check if the system hour has changed from the previous one. If it has then it closes the current encoder creating the file and then starts a new one. I even tried this using a background worker but to no avail, got the same results.

EDIT: Sorry, I should also have mentioned I'm not using a filewriter. I create a new file. First I stop the previous encoder:

BassEnc.BASS_Encode_StopEx(EncoderLog, True)

Then start a new one:

EncoderLog = BassEnc.BASS_Encode_Start(MixerChan, "lame -r -x -s " & DeviceFrequency & " -b " & Bitrate & " --resample " & Frequency & " --alt-preset standard - """ & FName & ".mp3""", BASSEncode.BASS_ENCODE_NOHEAD Or BASSEncode.BASS_ENCODE_AUTOFREE Or BASSEncode.BASS_ENCODE_FP_16BIT Or BASSEncode.BASS_ENCODE_QUEUE, Nothing, IntPtr.Zero)
« Last Edit: 4 Sep '17 - 18:03 by Chris Oakley »

Ian @ un4seen

  • Administrator
  • Posts: 20393
OK, that sounds fine. As you're not using the sample count to time the recordings, small differences are to be expected but that shouldn't be as much as several seconds.

When you say "I'm casting but I'm also recording the encoder channel which is doing that on a different encoder channel", does that mean you have 2 encoders set on the mixer that is feeding the ASIO output? If so, do both have the BASS_ENCODE_QUEUE flag set? If you aren't already doing so, you could try using BASS_Encode_SetNotify on the encoders and see if any notifications are received.

Chris Oakley

  • Posts: 17
Sorry, I didn't make that clear or accurate about the encoders.

I have one encoder which is casting a Mixer, but I have another encoder which is recording the same Mixer. So this does mean I have two encoders set on the Mixer which is being fed by the ASIO output. Only the recording encoder has the ENCODE_QUEUE flag set, the casting encoder doesn't.

I will try the SetNotify, that's a good idea. I've also removed the AUTOFREE from the recording encoder to see if that was somehow closing itself off. Don't know if you think taking that flag off may help?

Chris Oakley

  • Posts: 17
Okay I've had no notifications from either encoder but the file lengths are still different. However I noticed one was longer than it should be. I then did a load of digging and found that the stream I create and add to the mixer which plays the emergency backup file is responsible for causing this. Because I'm using a mixer I'm having to get the mixer data myself in a worker thread to process it. This is where a lot of the issue are coming from I believe. I must be doing something wrong.

This is my worker thread:

Code: [Select]
        Do Until bkgLevel.CancellationPending

            Dim MixLevel As Integer = Bass.BASS_ChannelGetLevel(MixerChan)

            Dim Level As Integer = BassMix.BASS_Mixer_ChannelGetLevel(RChan)
            If Level > -1 Then
                Dim LeftLevel As Integer = Math.Abs(Un4seen.Bass.Utils.HighWord(Level))
                Dim RightLevel As Integer = Math.Abs(Un4seen.Bass.Utils.LowWord(Level))
                OverallLevel = Math.Max(LeftLevel, RightLevel)
            Else
                Level = 0
            End If

            Dim b As Integer = BassMix.BASS_Mixer_ChannelGetLevel(RChan)
            If MixLevel > -1 Then
                bkgLevel.ReportProgress(10, MixLevel)
            Else
                MixLevel = 0
                bkgLevel.ReportProgress(10, MixLevel)
            End If

            Threading.Thread.Sleep(10)

        Loop

I'm using it to get the levels as well and feed them to an event. I get a level for the entire mix MixerChan and a level for just the streamed audio RChan without the emergency channel. This is so one can be used to detect the silence on that channel. I've also noticed that the emergency channel isn't buffering properly and skips then get's faster. It also crackles like hell when it cross fades with the returned output stream.

There must be a simple way to do what I'm trying to do. I can't help but think this is all a bit contrived.

Ian @ un4seen

  • Administrator
  • Posts: 20393
OK. If I understand correctly, you have a recording channel plugged into a mixer, and you're processing the mixer (via BASS_ChannelGetLevel calls) in a worker thread? If so, are you using the BASS_MIXER_LIMIT flag in the BASS_Mixer_StreamAddChannel call that adds the recording to the mixer? You should do so, to limit the mixer processing to the amount of data that the recording is providing. That will prevent the mixer processing going too fast. You will also need to make sure that it isn't going too slow. I would suggest using BASS_ChannelGetLevelEx instead of BASS_ChannelGetLevel, as it allows you to specify how much data is used to get the levels. The processing loop could look something like this:

Code: [Select]
int lasttime = timeGetTime() - 10;
while (!stop) {
int time = timeGetTime();
float levels[2];
BASS_ChannelGetLevelEx(mixer, levels, (time - lasttime + 1) / 1000.0, 0); // extra 1ms just to be sure it isn't too slow
// do something with the levels in "levels" here
lasttime = time;
Sleep(10);
}

Please see the BASS_ChannelGetLevelEx documentation for details on that.

Chris Oakley

  • Posts: 17
Thanks Ian, that's done the trick :)

I've now got the file lengths within a second or two of their actual lengths which is pretty normal.

For reference I think adding BASSFlag.BASS_MIXER_NONSTOP to the mixer itself has helped.