Author Topic: Using BASSMix to recode PCM / Wave data  (Read 146 times)

Gazoo

  • Posts: 55
Using BASSMix to recode PCM / Wave data
« on: 2 May '21 - 12:04 »
Hey BASS forum,

I'm currently using BASS to load raw PCM data from .mp3 files. If the sample rate isn't 44.1 Khz or the audio is in Mono, I'd like to recode it to 44.1 Khz / Stereo. I've found a number of examples using BASSMix to do this, but they all connect with a file:

https://www.un4seen.com/forum/?topic=15531.msg108129#msg108129
https://www.un4seen.com/forum/?topic=17333.msg121548;topicseen#msg121548

Thus far I've tried to put this code together to just do it in-memory providing the raw PCM wave data:

Code: [Select]
auto streamMixer = BASS_Mixer_StreamCreate( BuildOptions::SampleRate, 2, BASS_MIXER_END | BASS_STREAM_DECODE );

auto success = BASS_StreamPutData( streamMixer, data.get(), sizeInBytes );

int64_t audioLengthInBytes = BASS_ChannelGetLength( streamMixer, BASS_POS_BYTE );

////BASS_StreamPutData( instream, buffer, length );
while (1) {
BYTE buf[20000];
if (BASS_ChannelGetData( streamMixer, buf, sizeof( buf ) ) == -1) break; // process the mixer until it fails/ends
}

But the ChannelGetData appears to return nothing. Do I need a separate stream or? What am I missing?

Thanks in advance,

Gazoo

Ian @ un4seen

  • Administrator
  • Posts: 23656
Re: Using BASSMix to recode PCM / Wave data
« Reply #1 on: 3 May '21 - 15:43 »
You had the right idea with BASS_StreamPutData but you will need to create a "push" stream for that rather than using it directly on the mixer. For example, you could modify your code like this:

Code: [Select]
auto streamMixer = BASS_Mixer_StreamCreate( BuildOptions::SampleRate, 2, BASS_MIXER_END | BASS_STREAM_DECODE );
auto streamPush = BASS_StreamCreate(freq, chans, BASS_STREAM_DECODE, STREAMPROC_PUSH, 0);
BASS_Mixer_StreamAddChannel(streamMixer, streamPush, BASS_MIXER_CHAN_NORAMPIN);

auto success = BASS_StreamPutData( streamPush, data.get(), sizeInBytes | BASS_STREAMPROC_END );

while (1) {
BYTE buf[20000];
if (BASS_ChannelGetData( streamMixer, buf, sizeof( buf ) ) == -1) break; // process the mixer until it fails/ends
}

The BASS_STREAMPROC_END flag means there's no more data. Remove that if there's more to come, but note BASS_ChannelGetData will return 0 rather than -1 until it's set.

Gazoo

  • Posts: 55
Re: Using BASSMix to recode PCM / Wave data
« Reply #2 on: 10 May '21 - 10:25 »
Much appreciated Ian - that did the trick. Especially after I figured out I also needed to attach the
Code: [Select]
BASS_DATA_FLOAT flag, as my data is kept in floats :)

Two follow up questions:
  • As previously stated, I use BASS to decode mp3 data to raw PCM wave, and then re-encode it. Is it also possible to attach the mixer directly to the decoding channel?
  • When decoding the mp3 data I rely on BASS_ChannelGetLength to determine an upper memory limit. If I could directly attach the mixer, could I still estimate the resulting raw PCM wave size? I've tried using BASS_ChannelGetLength on the push and mixer streams in the code snippet we've been discussing without success.

Thanks in advance,
Gazoo

Ian @ un4seen

  • Administrator
  • Posts: 23656
Re: Using BASSMix to recode PCM / Wave data
« Reply #3 on: 10 May '21 - 15:04 »
Much appreciated Ian - that did the trick. Especially after I figured out I also needed to attach the
Code: [Select]
BASS_DATA_FLOAT flag, as my data is kept in floats :)

If you want to receive floating-point data from the BASS_ChannelGetData call then I would recommend adding the BASS_SAMPLE_FLOAT flag to the BASS_Mixer_StreamCreate call. The internal mixer processing is floating-point, and the BASS_SAMPLE_FLOAT flag will keep the mixer output that way too, so it will avoid unnecessary float->integer->float conversion.

As previously stated, I use BASS to decode mp3 data to raw PCM wave, and then re-encode it. Is it also possible to attach the mixer directly to the decoding channel?

Do you need the decoded data for anything else? If not, you could indeed skip the push stream and plug the decoder directly into the mixer instead (put its handle in the BASS_Mixer_StreamAddChannel call).

When decoding the mp3 data I rely on BASS_ChannelGetLength to determine an upper memory limit. If I could directly attach the mixer, could I still estimate the resulting raw PCM wave size? I've tried using BASS_ChannelGetLength on the push and mixer streams in the code snippet we've been discussing without success.

You can calculate the length using to the ratio of the sample rates, ie. original length * new rate / original rate. That can also be done using BASS_ChannelBytes2Seconds and BASS_ChannelSeconds2Bytes, like this:

Code: [Select]
QWORD newlength = BASS_ChannelSeconds2Bytes(mixer, BASS_ChannelBytes2Seconds(decoder, BASS_ChannelGetLength(decoder, BASS_POS_BYTE)));

You can skip the BASS_ChannelSeconds2Bytes call if you happen to want the new length in seconds.