Author Topic: Playing DECODE file added to Mixer misses chunks of data  (Read 267 times)

Chris Oakley

  • Posts: 96
I've got an issue with a file I'm trying to plug into a mixer. The mixer is running fine and casting no problem, however, when I try to plug an actual file into it to play it keeps jumping and missing chunks of data.

I'm adding the file like this:

Code: [Select]
EmergencyChan = Bass.BASS_StreamCreateFile(EmergencyFile, 0, 0, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_SAMPLE_LOOP Or BASSFlag.BASS_SAMPLE_FLOAT)
BassMix.BASS_Mixer_StreamAddChannel(MixerChan, EmergencyChan, BASSFlag.BASS_MIXER_BUFFER Or BASSFlag.BASS_MIXER_LIMIT)

The MixerChan is setup like this:

Code: [Select]
MixerChan = BassMix.BASS_Mixer_StreamCreate(48000, 2, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_MIXER_NONSTOP)

Now for some reason when I do this loop in a worker I get the problem:

Code: [Select]
        Do Until bkgWorker Is Nothing OrElse bkgWorker.CancellationPending
            Dim Levels(2) As Single
            Bass.BASS_ChannelGetLevel(MixerChan Levels, 1, BASSLevel.BASS_LEVEL_STEREO)
            Threading.Thread.Sleep(20)
        Loop

But if I do it like this, it's absolutely fine:

Code: [Select]
        Dim LastMS As Integer = Environment.TickCount - 10
        Do Until bkgWorker Is Nothing OrElse bkgWorker.CancellationPending
            Dim TimeNowMS As Integer = Environment.TickCount
            Dim Levels(2) As Single
            Bass.BASS_ChannelGetLevel(MixerChan, Levels, (TimeNowMS - LastMS) / 1000, BASSLevel.BASS_LEVEL_STEREO)
            LastMS = TimeNowMS
            Threading.Thread.Sleep(10)
        Loop

I can't do it the second way because if I do then a problem we orginally had whereby pops and clicks appear on the casted or logged output returns.

Ian @ un4seen

  • Administrator
  • Posts: 21329
"jumping and missing chunks of data" sounds like what happens when data is being taken from the source outside of the mixer, which means that data is then not seen by the mixer. Are you calling BASS_ChannelGetData/Level/Ex on the source ("EmergencyChan") anywhere?

Chris Oakley

  • Posts: 96
I'm not Ian. I've checked and double checked.

Ian @ un4seen

  • Administrator
  • Posts: 21329
Just to be sure, can you confirm that by "jumping and missing chunks of data", you did mean that the mixer is skipping parts of the source? If so, are there gaps where those parts should be? I assume there are no problems when playing the same file with BASS normally, ie. using BASS_ChannelPlay?

Chris Oakley

  • Posts: 96
No no problems at all playing it normally. Imagine the file playing and it plays 1 second of the audio, then skips the next 3, then plays another second and so on.

Have a quick listen to this - this is what it's doing http://rss-streaming.co.uk:8000/index.html?sid=2

Ian @ un4seen

  • Administrator
  • Posts: 21329
Are you setting the encoder/caster on the "MixerChan" mixer? If you log the position of the mixer and the "EmergencyChan" source (with BASS_ChannelGetPosition) before and after the BASS_ChannelGetLevel call in your loop, what does that look like?

If you set a WAV writer on the "EmergencyChan" channel (BASS_Encode_Start with BASS_ENCODE_PCM) and then play back the written WAV file afterwards, does it sound normal?

Chris Oakley

  • Posts: 96
I should point out that even if I don't cast / encode the problem is still there. I can tell that from the level meters on screen. They should start low and ramp up - they just start loud.

The difference between the MixerChan and the EmergencyChan postitions are:

MixerChan Before GetLevel = 31680032
EmergencyChan Before GetLevel = 58212128
MixerChan After GetLevel = 31872036
EmergencyChan After GetLevel = 58564936

This shows a difference of:

MixerChan = 192004
EmergencyChan = 352808

This difference seems to be consistent. I don't know what this shows.

Ian @ un4seen

  • Administrator
  • Posts: 21329
I forgot to say to also timestamp each entry of the log, to see how long the BASS_ChannelGetLevel calls are taking.

Regarding the level meters not ramping up as expected, does that only happen when you don't have the encoder/caster set on the mixer? If so, note it is the encoder/caster that limits the mixer's processing to realtime speed. Without that enabled, the mixer will be processed as quickly as possible in your loop, and therefore the source (and its level meters) will be rushing forward too. Btw, how are you getting level readings for the meter? I guess from BASS_Mixer_ChannelGetLevel?

Chris Oakley

  • Posts: 96
I've figured out what the problem is, but not sure how to get around it yet. I have a background worker that does:

Code: [Select]
            Bass.BASS_ChannelGetLevel(LevelMixer, Levels, 1, BASSLevel.BASS_LEVEL_STEREO)

And I have another worker that does:

Code: [Select]
            Bass.BASS_ChannelGetLevel(CastingMixer, Levels, 1, BASSLevel.BASS_LEVEL_STEREO)

If I put both these calls in the same worker everything is fine, but if they're in separate workers then it all goes wrong.

I also have a problem when I get it working, because now when I'm getting the level data I'm only getting a value per second. So for an entire second it's the same value.
« Last Edit: 7 Nov '18 - 23:06 by Chris Oakley »

Ian @ un4seen

  • Administrator
  • Posts: 21329
I suspect the "LevelMixer" mixer processing isn't being limited to realtime speed (like the "CastingMixer" mixer is due to the encoder/caster). In that case, you should use the 2nd "Do Until" loop from your 1st post, to limit the processing to realtime speed yourself.

By the way, another way that you could limit the processing to realtime speed is to play the mixers on BASS's "No Sound" device. You would simply call BASS_ChannelPlay then instead of having processing loops in worker threads. You will need the latest BASS build for that ability (it isn't in the current release), which you can get here:

   www.un4seen.com/stuff/bass.zip

Chris Oakley

  • Posts: 96
This is an option, but I don't seem to be able to split off the MixerChan so I can plug into another mixer and resample. Remember I have to be able to cast at one sample rate but record the output at another sample rate.

Ian @ un4seen

  • Administrator
  • Posts: 21329
You would still be able to split the main mixer when using the "No Sound" device. You would remove the BASS_STREAM_DECODE flag from the final streams (the ones that you were processing in a loop) and then call BASS_ChannelPlay on them (instead of processing in a loop).

What encoder are you using on the recording? It may have its own built-in resampling option that you could use to further simplify things.

Chris Oakley

  • Posts: 96
Thanks Ian, I've tested all this and it's great. Superb.

I'm using a combination of encoders as we allow the client to stream via lame, opusenc, ogg and aac - but only some of them allow for resampling in the command line so it's just easier to create a mixer to resample accordingly.

For future reference as well for anyone reading this thread I've discovered that the Environment.TickCount isn't totally spot on in VB.NET and has a resolution of around 15ms. Another pitfall is that you need to make sure after 24 days that you compensate for the fact that it jumps back into negative numbers as it can only count so high.

I did find DateTime.UtcNow.TickCount which offers a greater granularity and is more accurate. It returns nanoseconds so you do have to divide by 1000000 to get the ms value, but it did the job. This said, I now no longer need this process.

Thanks again Ian. I don't know what we would do without you :)

Chris Oakley

  • Posts: 96
Sorry Ian, just one more clarification. In order to create a split from the main mixer and then assign to a mixer I would do this:

Code: [Select]
        CastingSplitStream = BassMix.BASS_Split_StreamCreate(MixerChan, BASSFlag.BASS_STREAM_DECODE , Nothing)
        CastingMixer = BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_DEFAULT Or BASSFlag.BASS_MIXER_NONSTOP)
        BassMix.BASS_Mixer_StreamAddChannel(CastingMixer, CastingSplitStream, BASSFlag.BASS_DEFAULT)
        Bass.BASS_ChannelPlay(CastingMixer, False)

Is that correct?

Ian @ un4seen

  • Administrator
  • Posts: 21329
Yep, that looks correct.

Chris Oakley

  • Posts: 96
Thanks Ian. I can confirm we've had this all operating over the weekend and it's perfect. Streamlined the code so much as well.

Thanks again :)