Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: PCM Resampling (Read 11189 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

PCM Resampling

Hi all,
  I need to resample a PCM audio data stream (both upsample and downsample) to 44,1 kHz.

At the moment I do the following:

Starting from a buffer that contains pcm data with an arbitrary sampling rate I create an MP3 file using the LAME encoder, using 44100 as the output sampling rate.
Then I read this file with the LAME decoder and I obtain a buffer with PCM data sampled correctly.

I would like to simply resample my pcm data from one buffer to another, without encoding and decoding an mp3 file. Is this possible? With lame or any other library?

I have tried  "libresample", but it adds too much noise to my audiostream...

Thanks in advance, BM

PCM Resampling

Reply #1
maybe libresample is just bad

I suggest "SSRC"

that is available in foobar2000
http://www.foobar2000.org/

just download it ....

after downloading..install....

go to Preference

Playback->DSP Manager...set "Resemmpler SSRC"
again go to Resempler page...choose desired sampling frequency

now, go to
Component -> diskwriter
check "Apply DSP"

finally, drag the file you want to convert into foobar2000's playlist
right click.  convert to ..

that's all

PCM Resampling

Reply #2
Thanks for the suggestion, but I need this resample inside a program. I need to link a library to my program that performs a resample. I dont want to use an external program. And I want to use only buffered data, without reading and writing external files.

BM

PCM Resampling

Reply #3
Look at these projects:
SRC (GPL)
SSRC (LGPL)
Source code of both is available.
"To understand me, you'll have to swallow a world." Or maybe your words.

PCM Resampling

Reply #4
Quote
I have tried  "libresample", but it adds too much noise to my audiostream...
[a href="index.php?act=findpost&pid=280986"][{POST_SNAPBACK}][/a]


You are doing something wrong. While libresample might not be the best in terms of speed/quality, it should not have issues for general use.

PCM Resampling

Reply #5
libsamplerate works nicely, in my experience.

However, I agree with Garf, libresample should work well enough not to add an unacceptable amount of noise. How loud is this noise? Is it just white noise, or a spurious tone or crackle/hiss?

PCM Resampling

Reply #6
I have used libresample

Resampling from 8k to 44,1kHz it adds crackling noise

BM


PCM Resampling

Reply #8
Hi.

I am looking for a low-complexity re-sampler, one that uses integer (fixed point) maths, rather than the more usual floating point maths.

I am specifically after a re-sampler that can take buffers of 11kHz audio, and down-convert to 8kHz. I am initially working in C to get the logic right, but my aim is to move into very low power hardware. Hence, I want as little floating point maths as I can possibly get, hopefully none!

I have done quite a bit of searching, and I can't find *any* non-floating-point implementations of re-samplers.

Quality is not my main goal, low power is. I would be happy with a noise floor of -60db, maybe even up to -40db.

My conversion ratio will always be 11:8, and I can optimise more generic code to do this, but I would really appreciate a starting point.

Any pointers to integer re-sampling code? Anyone?

Cheers,
MustardMan.

PCM Resampling

Reply #9
Quote
Quality is not my main goal, low power is. I would be happy with a noise floor of -60db, maybe even up to -40db.

My conversion ratio will always be 11:8, and I can optimise more generic code to do this, but I would really appreciate a starting point.

Any pointers to integer re-sampling code? Anyone?[a href="index.php?act=findpost&pid=336145"][{POST_SNAPBACK}][/a]


You know the simplist is to just step through the input 11khz waveform and output it 8 times for every 11 steps, like
Code: [Select]
for( int insam = start; insam < end; insam++ )
{ 8KhWvFrm[(insam*8)/11]=11KhWvFrm[insam]; }


That would be a rather lowquality but complete 'resampling loop'

or same but quicker - 3/11th quicker, (looping through the outputs index)
Code: [Select]
for( int outsam = start; outsam < end; outsam++ )
{ 8KhWvFrm[outsam]=11KhWvFrm[(outsam*11)/8; }


Might do for getting on with, no idea about the noise floor measurement, it would be very nonlinear. - shouldnt be much 'crackling' though...i dont think.

Or maybe some psuedotweak like,
[span style='font-size:7pt;line-height:100%']
Code: [Select]
for( int outsam = start; outsam < end; outsam++ )
{ 8KhWvFrm[outsam] =

 11KhWvFrm[(outsam]*((outsam*11)%8)/(8*4)
+11KhWvFrm[(outsam+1)]*(((outsam+1)*11)%8)/(8*4)
+11KhWvFrm[(outsam+2)]*(((outsam+2)*11)%8)/(8*4)
+11KhWvFrm[(outsam+3)]*(((outsam+3)*11)%8)/(8*4); }
[/span]
-that one definetly wont work, but if you can guess the sort of thing its buggily trying to do, youve a keener eye than mine
-best ignore it actualy, it could be completely nonsensical.

Next step up in complexety might involve examining the input stream in small stretches to discern patterns to keep in the output stream.

'gl
no conscience > no custom

PCM Resampling

Reply #10
Quote
Quality is not my main goal, low power is. I would be happy with a noise floor of -60db, maybe even up to -40db.

I just thought of a slightly better option for fast low quality resampling, looks a bit like this:
Code: [Select]
/*waveform pattern reference, like:

0 1 2 3 4 5 6 7 8 9 a  -11 KHz
| | | | | | | | | | |
0 1/ \2 3/ \4 5 6/ \7   -8  Khz

shows pattern used to 'map' samples in loop*/

for(lp=start; lp<end; lp++)
{
outwav[lp*8+0] = inwav[lp*11+0];
outwav[lp*8+1] = (inwav[lp*11+1]*2+inwav[lp*11+2])/3;
outwav[lp*8+2] = (inwav[lp*11+3]*2+inwav[lp*11+2])/3;
outwav[lp*8+3] = (inwav[lp*11+4]*2+inwav[lp*11+5])/3;
outwav[lp*8+4] = (inwav[lp*11+6]*2+inwav[lp*11+5])/3;
outwav[lp*8+5] = inwav[lp*11+7];
outwav[lp*8+6] = (inwav[lp*11+8]*2+inwav[lp*11+9])/3;
outwav[lp*8+7] = (inwav[lp*11+10]*2+inwav[lp*11+9])/3;
}

I might try this one out myself, doesnt deal properly with high frequencies being reflected from 4 to 5.5 Khz in the 11Khz sample into 4 to ~3 Khz in the 8Khz sample, but it would blur them and i think it might not sound all that bad.

Pretty optimistic though.
no conscience > no custom

PCM Resampling

Reply #11
This is probably what i would do in this situation:

- resample 11 kHz to 22 kHz via zero-stuffing + lowpass filtering with a curoff frequency at 4 kHz
- do linear interpolation from 22 to 8 kHz. This is acceptable in this case because the 22kHz signal only contains frequencies up to 4 kHz (due to the lowpass). So, the signal is sampled at a frequency 2,75 times higher than necessary. Linear approximation in this case is not that bad.

The lowpass filter thingy is probably the trickiest one:

To get a good and fast lowpass filter I'd make use of an order-6 IIR filter which I'd apply bidirectionally on slightly overlapping chunks (cross-fading the resulting overlap part for the output). Since I have to do this with integer arithmetic only I'd factor this order-6 IIR filter into 3 biquads and quantize ther coefficients carefully to keep it as stable as possible. These 3 biquads need to be applied consecutivly for one pass. (Remember: I'd want to apply the filter bidirectionally (twice, forwards and backwards)

What's a biquad ? It's a 2nd order IIR filter. Each IIR filter can be factored into multiple biquads. An order-6 IIR can be factored into 3 biquads. The input/output relation of a biquad can be described via
a0 * y_n + a1 * y_(n-1) + a2 * y_(n-2) = b0 * x_n + b1 * x_(n-1) + b2 * x_(n-2)
(x being the input signal and y being the output)
This is equivalent to
y_n = b0/a0 * x_n + b1/a0 * x_(n-1) + b2/a0 * x_(n-2) - a1/a0 * y_(n-1) - a2/a0 * y_(n-2)
which is the recursive formula you can use to calcualte the samples of y.

Code: [Select]
Biquads I just generated with Matlab:
b0   b1                b2  a0   a1                 a2
---------------------------------------------------------------------
 1   1.00686764516081   1   1  -0.82793795078910   0.26986315368756
 1  -0.52308847881206   1   1  -0.88042274575949   0.70502159922953
 1  -0.81016971101343   1   1  -0.91754984236612   0.93761686400769

Since they are given in their "normalized" form one needs to scale the result (the outcome after applying these 3 biquads consecutifly) by a certain factor -- in this case 0.06955.

edit:
- you might want to do pre- & post scaling (multiply by 8 for example, apply the filter and post scale by 0.06955/8) to minimize requantization errors
- you might want to just apply this filter twice unidirectionally. It won't be linear phase anymore but you won't need to do this overlap/crossfade stuff.


Sebi

PCM Resampling

Reply #12
Quote
This is probably what i would do in this situation:


Interesting to hear how this is done more properly.
Is there a benefit from applying the biquad process to the sequence at 22KHz rather than 11Khz (for twice as much computation)?
Does the upsampling improve accuracy or more the clarity of algorythm?
I mean could the upsampling be factored out of the stream and be squeezed into the action 'so to speak.

[span style='font-size:8pt;line-height:100%']I have to warn, Im still not ready to take on board very much of the contemporary handles on this myself because Im still making headway manipulating signals with my own methods and want to see how far they lead without coming across their destination. The biquad is kind of similar to a function I nickname a 'demipole' Theres so many demi's and semi's to distinguish between ! [/span]
no conscience > no custom

PCM Resampling

Reply #13
Quote
Quote
This is probably what i would do in this situation:

Interesting to hear how this is done more properly.
Is there a benefit from applying the biquad process to the sequence at 22KHz rather than 11Khz (for twice as much computation)?
Does the upsampling improve accuracy or more the clarity of algorythm?
I mean could the upsampling be factored out of the stream and be squeezed into the action 'so to speak.
[a href="index.php?act=findpost&pid=336333"][{POST_SNAPBACK}][/a]


No. Since 11 kHz is not a multiple of 8 kHz you need to somehow interpolate things. And this "upsampling" must be at least done implicitely. If you have 16 kHz to begin with, you could just do a lowpass filter to avoid aliasing followed by throwing every 2nd sample away. (Since you throw every 2nd sample away you only need to calculate every 2nd filtered sample if possible)

If you want to do things right you actually need to "zero-stuff" the 11 kHz signal to the smallest common multiple of 8 kHz and 11 kHz (which is 88 kHz) apply a lowpass filter and output only every 11th sample.

This all can be done in one step using a FIR filter. Because of the many zeros in the 88kHz signal (zero stuffing is dead simple)  and the fact that you only need every 11th sample it's possible to speed-optimize the whole thing. (With a good filter you need around 40 MACs (multiply and accumulate) per output sample in this case).

However, the idea I described in my first replay might be a bit faster. I actually did not think it through completely. Let's do it now:
- zero stuffing (0 MULs, 0 ADDs)
- bidirectionally applied IIR filter using the biquad factorization (22/8x2x3x(3 MULs+4 ADDs) = 49,5 MULs + 66 ADDs)
- linear interpolation (1 MUL, 2 ADDs)
=> 50 MULs, 68 ADDs per output sample

Well, it looks like the old-school approach is slightly better in this case (in terms of speed, quality and simplicity) ;-)

Why is that ? The thing with IIR filters is: I can apply cool IIR filters with few MACs whereas applying similar FIR filters would require significantly more MACs. But: Here we're only interested in a subset of the filtered samples (every nth sample) and many on the filter input samples are zero (due to the zero-stuffing). This can only be utilized by a FIR convolver. I underestimated this possible speed-improvement in this case.

edit:
The "old-school" approach boils down to something very similar to what you described, ChiGung -- only with larger window. For example:
outwav[lp*8+t] = inwav[lp*11-20]*c1 + inwav[lp*11-19]*c2 + ... + inwav[lp*11+30]*c51
where for each t in 0<=t<8 there's a special coefficient set c1...c51.


Sebi

PCM Resampling

Reply #14
I read coefficients are values which modify sample values in time (or other dimension) compounding expression types.
The term seems generic for polynomial and series type's 'calibratable variables'
The order of a filter, is the number of samples used in its expression.
The name/type of a filter eg FIR IIR is a theoreticaly backed up handle (im wary of adopting) on the low level expression types nature and useability.
Zero padding introduces a weird harmonic~ish pattern to sample ,which partialy negates itself out or is removed fully by lowpassing (?)
..single order Zero stuffing would be like frequency modulation..
-its not an immediately accessible idea to me.

I fiddled about to write a ~slightly more refined lowlevel sample converter method.

Code: [Select]
public short[] resample(short[] inWv, int inWvFq, int oWvFq, int strt, int fnsh)
{
short[] OutWv=new short[fnsh-strt];
//care in bounding these params to inWv array, both pcm series have to coincide at start=0.
//This method can be used to return chunks of resampled output in sequence
//or strt and fnsh must be precalculated to map OutWv against inWv.

//inWvFq =11; oWvFq =8; or scale these to lessen dither strength

int tdither/*timeditherer*/ , rnddith/*ditherStartRandomiser*/;            
tdither=0; rnddith=(int)Math.random(60);

for(int tiOutWv=strt; tiOutWv<fnsh; tiOutWv++) //TimeIndexofOutWaveArray
{ inWvTrgt=tiOutWv*inWvFq-tdither;             //TargetIndexofInwavArray

  OutWv[tiOutWv-strt]= (short)
  ( inWv[  inWvTrgt/oWvFq ] *(oWvFq-(inWvTrgt %oWvFq))/oWvFq
   +inWv[1+inWvTrgt/oWvFq ] *       (inWvTrgt %oWvFq) /oWvFq );
    
  tdither=((rnddith+tiOutWv*207)&(tiOutWv*203))%3;
  }
return OutWv;
}//end method


Not sure how this would sound yet, since im stuck elsewhere on trying to use most efficiently a FileInputStream which seems unwilling to be left open outside its 'try' statement
I suspect the dither could do with being scaled down, and a craftier derivation.

Not sure about the byquading, cant see how to jam it into the loop straight away. Would you say it would improve things - maybe high freqs are already fudged beyond improvement by the time dithering and '~1.5 order averaging' done.

[span style='font-size:8pt;line-height:100%']edit: might almost work now[/span]
no conscience > no custom

PCM Resampling

Reply #15
ChiGung, it looks like linear interpolation plus intentional jitter - though i don't see why you are introducing jitter (which you call "time dithering").

For educational purpose you could try and see what zero stuffing does. insert 2 or 3 zeros after each sample and run a spectrum analysis on the result (like Cool Edit's Spectrum view / Voice print)

There used to be a good tutorial around on how to resample audio data / what bandlimited interpolatin is .... I don't have the links at hand but Google is your friend.

This looks promising at first glance.

Sebi

PCM Resampling

Reply #16
Quote
ChiGung, it looks like linear interpolation plus intentional jitter - though i don't see why you are introducing jitter (which you call "time dithering").

just a notion, a little entropy to smooth out gremlins.
Quote
For educational purpose you could try and see what zero stuffing does. insert 2 or 3 zeros after each sample and run a spectrum analysis on the result (like Cool Edit's Spectrum view / Voice print)

Yes im very interested in how it looks. Ive gotten used to looking a test tune with my own spectral estimation methods which ive been tuning for the last few weeks  Ive been Just messing about for a few days. Have to do some work and get over the stupid FileInputStream error, next week.
Quote
There used to be a good tutorial around on how to resample audio data / what bandlimited interpolatin is .... I don't have the links at hand but Google is your friend.
This looks promising at first glance.
Sebi

hmm cant read that, ive had my education, research feels like cheating now 
just throwing some code and blurb into the thread so it can be seen someone elses interest 

andy
no conscience > no custom

PCM Resampling

Reply #17
Quote
just a notion, a little entropy to smooth out gremlins.
[a href="index.php?act=findpost&pid=336818"][{POST_SNAPBACK}][/a]

TBH. I don't think anyone would want to do that unless he intentionally wants to distort the signal.

Quote
Yes im very interested in how it looks. Ive gotten used to looking a test tune with my own spectral estimation methods which ive been tuning for the last few weeks  Ive been Just messing about for a few days. Have to do some work and get over the stupid FileInputStream error, next week.
[a href="index.php?act=findpost&pid=336818"][{POST_SNAPBACK}][/a]

Unfortunately I can't find a good website explaining what zero stuffing does including a nice picture. Please do yourself a favour and try it out using a nice spectrum view like Cool Edit's.

Quote
hmm cant read that, ive had my education, research feels like cheating now 
just throwing some code and blurb into the thread so it can be seen someone elses interest 
[a href="index.php?act=findpost&pid=336818"][{POST_SNAPBACK}][/a]

This is hardly constructive. 

Sebi

PCM Resampling

Reply #18
Quote
Quote
just a notion, a little entropy to smooth out gremlins.

TBH. I don't think anyone would want to do that unless he intentionally wants to distort the signal.
Not even a little bit? Okay then.
Quote
Unfortunately I can't find a good website explaining what zero stuffing does including a nice picture. Please do yourself a favour and try it out using a nice spectrum view like Cool Edit's.

Ill post what it looks like with my spectral estimator in a few days - its making nice images so far
Quote
Quote
hmm cant read that, ive had my education, research feels like cheating now
just throwing some code and blurb into the thread so it can be seen someone elses interest
This is hardly constructive. 

yeah im sorry i didnt like how it read, but too much post editing recently. Its not that I think I know it all, its a foible.

A Tone sweeping from low Hz to near half the sampling frequency:
------

Same Tone Zero Stuffed 1:1
------
no conscience > no custom

PCM Resampling

Reply #19
Quote
A Tone sweeping from low Hz to near half the sampling frequency:
------

Same Tone Zero Stuffed 1:1
------
[a href="index.php?act=findpost&pid=336927"][{POST_SNAPBACK}][/a]


if done right the visualization of the zerostuffed version (original samples interleaved with zero samples) should have shown perfect symmetry (the upper half is the mirrored image of the lower half). And this is what zero stuffing does. It keeps the lower part as it is and introduces alias frequencies above. Now, if you apply a lowpass filter to remove the alias frequencies you did upsample the signal. :-)

(note: the gain should be also adjusted... if you insert one zero after each sample you need to adjust the gain by factor two afterwards)

bye,
Sebi

PCM Resampling

Reply #20
Quote
if done right the visualization of the zerostuffed version (original samples interleaved with zero samples) should have shown perfect symmetry (the upper half is the mirrored image of the lower half).

Fair enough, these plots render amplitude/sqrt(wavlen), for a different purpose.

edit: a precise definition of what they render is pending.... % }

... I did a little experimentation there, multiplying the output * wavlength balances the weight of the curves, so it would seem from observation that its amp/wavlen orgionally rendered.
no conscience > no custom