Author Topic: Aliasing due to different sample rates encoding  (Read 2991 times)

S0lo

  • Posts: 11
Hi,

I'm Encoding/saving a stream using BASS_Encode_Write(). The original sample rate is different than the output sample rate. I understand that if the output sample rate is lower, then I'd have to filter the sample at the output nyquist before encoding. Which I have done correctly using a sinc FIR. I have no doubts about that part.

But the problem I'm facing is whenever the output sample rate is not a perfect multiple of the input sample rate. I get horrible aliasing. This happens whether or not the output sample rate is higher or lower than the input sample rate. 

The only explanation I could come up with is that the encoding is not doing fractional (interpolation) re-sampling. Is there any way around this. Or do I have to re-sample fractionally my self.

Ian @ un4seen

  • Administrator
  • Posts: 22959
Re: Aliasing due to different sample rates encoding
« Reply #1 on: 19 Nov '19 - 13:52 »
What encoder are you using? BASSenc does not do resampling itself, so any resampling would need to be done by the encoder (if it has that option) or by you. When needed, you can use the BASSmix add-on to do resampling, ie. create a mixer with the wanted sample rate and plug the source into it and then encode the mixer output.

S0lo

  • Posts: 11
Re: Aliasing due to different sample rates encoding
« Reply #2 on: 20 Nov '19 - 16:26 »
Thanks Ian,

I let the user choose the encoder using BASS_Encode_GetACMFormat(). The one I'm trying is PCM.

I'll check out BASSmix. Didn't know about it.

I ended up trying resampling my self. But it appears that I need to oversample before I filter otherwise the results won't be clean

S0lo

  • Posts: 11
Re: Aliasing due to different sample rates encoding
« Reply #3 on: 20 Nov '19 - 19:55 »
Hi Ian, I'm trying BASSmix, But I'm not getting what I expect (Or may be what I expect is wrong). The result wav file simply has higher or lower pitch. The output file size is exactly the same as the input file. Here are the relevant parts of the code.


Code: [Select]
hmixer = BASS_Mixer_StreamCreate(acmform->nSamplesPerSec,1,BASS_SAMPLE_FLOAT | BASS_STREAM_DECODE);
BASS_Mixer_StreamAddChannel(hmixer,chan,0);
hencode = BASS_Encode_StartACMFile(hmixer,acmform,BASS_ENCODE_PAUSE,vst_file_select.returnPath);
......
......
BASS_Encode_AddChunk(hencode,"smpl",ptag_smpl,sizeof(*ptag_smpl)+sizeof(*ptag_smpl_loop));
.......
.......
BASS_Encode_Write(hencode,p,(j+1)*sizeof(*p));

Ian @ un4seen

  • Administrator
  • Posts: 22959
Re: Aliasing due to different sample rates encoding
« Reply #4 on: 21 Nov '19 - 14:06 »
That looks like you may be bypassing the mixer (and its resampling) in the BASS_Encode_Write call. What data are you passing to it? Instead of using BASS_Encode_Write, you could try BASS_ChannelGetData on the mixer (and remove the BASS_ENCODE_PAUSE flag the BASS_Encode_StartACMFile call). The mixer should also have the BASS_MIXER_END flag set, so that it ends when the source does. ACM doesn't support floating-point, so you can remove the BASS_SAMPLE_FLOAT flag. It could look something like this:

Code: [Select]
hmixer = BASS_Mixer_StreamCreate(acmform->nSamplesPerSec,1,BASS_STREAM_DECODE | BASS_MIXER_END);
BASS_Mixer_StreamAddChannel(hmixer,chan,0);
hencode = BASS_Encode_StartACMFile(hmixer,acmform,0,vst_file_select.returnPath);
BASS_Encode_AddChunk(hencode,"smpl",ptag_smpl,sizeof(*ptag_smpl)+sizeof(*ptag_smpl_loop));
while (true) {
BYTE buf[20000]; // processing buffer
int r = BASS_ChannelGetData(mixer, buf, sizeof(buf)); // process the mixer (inc. feeding the encoder)
if (r < 0) break; // done
}

If you want to write a PCM WAV file, another way to do that (instead of using BASS_Encode_StartACMFile) is to use BASS_Encode_Start with BASS_ENCODE_PCM. The BASS_Encode_StartACMFile call above could be replaced with this:

Code: [Select]
hencode = BASS_Encode_Start(hmixer, vst_file_select.returnPath, BASS_ENCODE_PCM, NULL, NULL);

That does support floating-point, in case you do want to write floating-point WAV files.

S0lo

  • Posts: 11
Re: Aliasing due to different sample rates encoding
« Reply #5 on: 22 Nov '19 - 18:34 »
Thanks Ian, Still trying with not much luck. The input data is 32bit float at any possible sampling rate.

One question, Why did you use the BASS_ChannelGetData() when the purpose was actually to PUT/send data into the mixer -> encoder ?


Ian @ un4seen

  • Administrator
  • Posts: 22959
Re: Aliasing due to different sample rates encoding
« Reply #6 on: 25 Nov '19 - 14:39 »
BASSenc uses a DSP function (DSPPROC) to feed the encoder by default (when BASS_ENCODE_PAUSE isn't used). That means the encoder gets fed whenever the source produces any data. In this case, the encoder's source is a mixer that has the BASS_STREAM_DECODE flag set, so it is processed by calling BASS_ChannelGetData on it. If the BASS_STREAM_DECODE flag wasn't set then you would start the processing by calling BASS_ChannelPlay on it.

If you're still having trouble, please confirm what the "chan" handle in the BASS_Mixer_StreamAddChannel call is, eg. how are you creating that? And does it contain the data that you want to encode, or do you actually want to encode data that isn't in a stream? If the latter, you can use a "push" stream (BASS_StreamCreate with proc=STREAMPROC_PUSH) to put the data in a stream, which you can then plug into the mixer.

S0lo

  • Posts: 11
Re: Aliasing due to different sample rates encoding
« Reply #7 on: 27 Nov '19 - 11:56 »
or do you actually want to encode data that isn't in a stream? If the latter, you can use a "push" stream (BASS_StreamCreate with proc=STREAMPROC_PUSH) to put the data in a stream, which you can then plug into the mixer.

Thats what I want to do. I have float data in an array that I want to save to a wav file. thats all.  I tried with and without both/either BASS_STREAM_DECODE and BASS_ENCODE_PAUSE. Still no luck. Will removing BASS_SAMPLE_FLOAT from the mixer make any difference?

I admit, my understanding of how BASS works is superficial. Probably the reason why I'm stuck. Here is more or less the code.

Code: [Select]
chan=BASS_StreamCreate(smp_sr,1,BASS_SAMPLE_FLOAT,STREAMPROC_PUSH,0)
....
dtemp = BASS_Encode_GetACMFormat(chan,acmform,acmformlen,"Choose the output format",BASS_ACM_DEFAULT | BASS_ACM_CHANS);
if (dtemp)
{ hmixer = BASS_Mixer_StreamCreate(acmform->nSamplesPerSec,1,BASS_STREAM_DECODE | BASS_SAMPLE_FLOAT);
BASS_Mixer_StreamAddChannel(hmixer,chan,0);
hencode = BASS_Encode_StartACMFile(hmixer,acmform,BASS_ENCODE_PAUSE,vst_file_select.returnPath);
BASS_Encode_AddChunk(hencode,"smpl",ptag_smpl,sizeof(*ptag_smpl)+sizeof(*ptag_smpl_loop));
.....
BASS_StreamPutData(chan,p,(j+1)*sizeof(*p));
}
....



Ian @ un4seen

  • Administrator
  • Posts: 22959
Re: Aliasing due to different sample rates encoding
« Reply #8 on: 27 Nov '19 - 15:50 »
Try adding this in front of the code that I posted earlier:

Code: [Select]
chan = BASS_StreamCreate(smp_sr, 1, BASS_SAMPLE_FLOAT, STREAMPROC_PUSH, 0);
BASS_StreamPutData(chan, p, (j+1)*sizeof(*p));
...

If you want the written file to be floating-point then you should add the BASS_SAMPLE_FLOAT flag to the BASS_Mixer_StreamCreate call and replace BASS_Encode_StartACMFile with BASS_Encode_Start (flags=BASS_ENCDOE_PCM).

S0lo

  • Posts: 11
Re: Aliasing due to different sample rates encoding
« Reply #9 on: 27 Nov '19 - 19:02 »
Ok, so I copy/pasted your code almost exactly as it is. The only thing I had to add is just after the BASS_StreamPutData() is the BASS_Encode_GetACMFormat() to get the format from the user. Still doesn't work.

So I debugged the output and checked each return value from each function all are none zero and none -1 until it reaches BASS_Mixer_StreamAddChannel() which returns 0. I believe that means it failed. So I used BASS_ErrorGetCode() it returned BASS_ERROR_DECODE


Ian @ un4seen

  • Administrator
  • Posts: 22959
Re: Aliasing due to different sample rates encoding
« Reply #10 on: 28 Nov '19 - 12:42 »
Oops. I didn't notice that the BASS_STREAM_DECODE flag was missing from the BASS_StreamCreate call. I also forgot to say that you should use the BASS_STREAMPROC_END flag to signify the end of the data. Try this:

Code: [Select]
chan = BASS_StreamCreate(smp_sr, 1, BASS_SAMPLE_FLOAT | BASS_STREAM_DECODE, STREAMPROC_PUSH, 0);
BASS_StreamPutData(chan, p, ((j+1)*sizeof(*p)) | BASS_STREAMPROC_END);
...

S0lo

  • Posts: 11
Re: Aliasing due to different sample rates encoding
« Reply #11 on: 29 Nov '19 - 13:54 »
Thanks, That worked!!

When down sampled to 8Khz, the results still have some considerable amount of aliasing. That level is may be acceptable for casual play back, but still may be not for DAW and vst editing. Not that 8Khz is important that much, but it's just a thing.

I'll try to dig deeper into the mixer doc and see if I can tweak any re-sampling parameters. Probably increasing coefficient count in the re-sampling filter would solve it.

Edit: down sampling to 11Khz does have some minor aliasing too.
« Last Edit: 29 Nov '19 - 14:05 by S0lo »

Ian @ un4seen

  • Administrator
  • Posts: 22959
Re: Aliasing due to different sample rates encoding
« Reply #12 on: 29 Nov '19 - 14:28 »
Good to see you've got it working now.

Regarding resampling quality, you can adjust that via the BASS_ATTRIB_SRC option. This will give the highest quality:

Code: [Select]
BASS_ChannelSetAttribute(chan, BASS_ATTRIB_SRC, 6);

rv

  • Posts: 319
Re: Aliasing due to different sample rates encoding
« Reply #13 on: 1 Dec '19 - 04:11 »

S0lo

  • Posts: 11
Re: Aliasing due to different sample rates encoding
« Reply #14 on: 1 Dec '19 - 20:16 »
Thanks Ian, Works like a charm. Performance is very good too!!

It would be useful (in the future). To also support higher sinc point counts. The thing is I offer oversampling in a synth. So recorded samples can be higher than 44.1Khz. Which then has to be exported/saved in lower rates. In these cases, it may be useful to use higher order filtering.

Thanks again.

Ian @ un4seen

  • Administrator
  • Posts: 22959
Re: Aliasing due to different sample rates encoding
« Reply #15 on: 2 Dec '19 - 16:17 »
I thought value 4 was the maximum?
http://www.un4seen.com/doc/#bass/BASS_ATTRIB_SRC.html

4 is the maximum for normal BASS playback but BASSmix supports up to 6:

   www.un4seen.com/doc/#bassmix/BASS_Mixer_StreamAddChannel.html

S0lo

  • Posts: 11
Re: Aliasing due to different sample rates encoding
« Reply #16 on: 4 Dec '19 - 18:56 »
Is there is a way to add more attributes (sample rate, bit depth options) to that PCM format combo box in the dialog that the BASS_Encode_GetACMFormat() shows ?
« Last Edit: 4 Dec '19 - 19:20 by S0lo »

Ian @ un4seen

  • Administrator
  • Posts: 22959
Re: Aliasing due to different sample rates encoding
« Reply #17 on: 5 Dec '19 - 15:33 »
What options are you currently seeing in the dialog? You could try removing the BASS_ACM_DEFAULT flag from the BASS_Encode_GetACMFormat call and see if that gives you more.

S0lo

  • Posts: 11
Re: Aliasing due to different sample rates encoding
« Reply #18 on: 5 Dec '19 - 19:56 »
The options for PCM are 8Khz, 11Khz, 22Khz, 44Khz all at both 16bit and 8bit.

Would be good if I could add 48Khz, 16Khz etc... Removing BASS_ACM_DEFAULT didn't add any.

One thing I noticed is if the input data has a sampling rate thats not in the list. It actually gets added to the list!!. But not permanently.  So I'm thinking there might be a systematic way to add to that list.


Ian @ un4seen

  • Administrator
  • Posts: 22959
Re: Aliasing due to different sample rates encoding
« Reply #19 on: 6 Dec '19 - 13:36 »
Internally, BASS_Encode_GetACMFormat uses the acmFormatChoose function to display the dialog. If you would like to see what options that has available, you can check its documentation here:

   https://docs.microsoft.com/en-us/windows/win32/api/msacm/ns-msacm-acmformatchoose

I don't think it's possible to add custom sample rates to the dialog. If you need that (or any other options) to be shown, perhaps you could create your own dialog that includes them.

S0lo

  • Posts: 11
Re: Aliasing due to different sample rates encoding
« Reply #20 on: 7 Dec '19 - 09:45 »
Thanks. Yeah, I guess I'm going to just provide my own dialog/menu thing.