As a non maths-pro, I'm looking for some pointers.

I am rewriting the audio core in my emulator to improve accuracy, and am getting a bit stuck on the specifics of the technique.

I am trying to resample a sample buffer of 4,466 samples, at a sample rate of 223,807.5 Hz (from a simulated Yamaha SN76489), to a sample buffer of 880 samples at a sample rate of 44,100 Hz, which can then be output to a sound card.

Now from what I understand, as the ratio between 44,100 and 223,807.5 Hz is 5.075, I need to turn this into a fraction, which works out as 203/40, and then interpolate by the denominator (leaving 0 samples inbetween), run a low-pass filter, and then decimate by the numerator, giving me my 880 samples of 44,100 Hz output.

(1) Am I along the right lines here? Before I was just downsampling by a straight 5 (i.e. missing out 4 of every 5 samples) and whilst it worked well enough, some notes are slightly out of key in some games, and there is aliasing. Is this new approach correct?

(2) Also, I am not sure what would do the trick in terms of a low-pass filter. I found the following pseudocode on wikipedia that seems to fit the bill:

    // Return RC low-pass filter output samples, given input samples,
    // time interval dt, and time constant RC
    function lowpass(real[0..n] x, real dt, real RC)
       var real[0..n] y
       var real α := dt / (RC + dt)
       y[0] := x[0]
       for i from 1 to n
           y[i] := α * x[i] + (1-α) * y[i-1]
       return y

But I have no idea how to get RC and dt - what are these in relation to the filter I wish to achieve? As I don't know how to select suitable values here, the output signal is heavily garbled at the moment. If a better/more understandable formula is available then by all means suggest it. Sorry for the newbish question and I hope this is the right place for it. Thanks :-)

  • $\begingroup$ Absolutely fine by me - thank you for your time :-) $\endgroup$
    – PhilPotter1987
    Jan 10 '16 at 21:48
  • $\begingroup$ what about efficiency ? As for the emulator, do you seek to be more accurate or more efficient ? $\endgroup$
    – Fat32
    Jan 10 '16 at 23:58
  • $\begingroup$ At the moment I'd like something I can actually understand - efficiency is good but understanding is the key for me. $\endgroup$ Jan 11 '16 at 0:00
  • $\begingroup$ your approach is correct. It will produce what you want. But if you directly implement it, due to high interpolation of the initial stage, the required lowpass filter must be capable of removing all the images (due to upsampling - filling with zeros) before decimation to avoid aliasing. Most probably it is the low-pass filter who creates the problem. $\endgroup$
    – Fat32
    Jan 11 '16 at 0:34
  • $\begingroup$ Thanks, good to know. The low-pass filter is where I get caught up sadly. I just need something simple that can attenuate anything above a sampling rate of 44.1 kHz - and I somehow need to understand it too. $\endgroup$ Jan 11 '16 at 0:37

you can use this approach provided it does not yield efficiency burdens.

% Note that matlab arrays start from index 1, not 0.
F1 = 223807.5;     % Sampling rate of Yamaha chip
F2 = 44100;        % New sampling rate of standard Audio-CD
M = 203;           % Necessary Decimation ratio
N = 40;            % necessary Expansion ratio
Lx = 4466;         % Length of Audio Input Buffer at F1 rate
Ly = Lx*N/M;       % Length of Resampled Output Buffer at F2 rate

x = sin(2*pi*1234*[0:Lx-1]/F1);  % Just a test sine wave
y = zeros(1,Ly);                 % allocate output signal memory

for i=0:Ly-1              % run per each output sample
   n = i*(M/N);          % compute exact sampling position inside the long buffer 
   ind = floor(n);       % convert it into largest integer smaller than itself for array indexing
   d = n-ind;            % take the difference for proportional weighting
   y(i+1) = (1-d)*x(ind+1) + d*x(ind+2); % sum the weighted mixture.

figure,plot(x);            %plot each waveforms...
  • $\begingroup$ So would I be right in thinking this is similar to the approach I found on Wikipedia, except it interpolates the points in the output buffer directly? $\endgroup$ Jan 11 '16 at 9:11
  • $\begingroup$ No they are different approaches. The one you want to proceed uses a theoretically exact approach by performing [upsampling-->filtering-->downsampling] operations. This approach produces exact sample values but requires more computation. The one I suggest uses much less computation and provides quite accurate but not exact values proportional to oversampling of original signal. $\endgroup$
    – Fat32
    Jan 11 '16 at 9:47
  • $\begingroup$ Sorry, probably seems like a stupid question :-) Thank you for your help, this approach seems to make sense in my head and looks relatively simple to convert to C - I shall try it tonight and it will hopefully give me better results :-) $\endgroup$ Jan 11 '16 at 9:53
  • $\begingroup$ Would I be correct in deducing that "y(i+1) = (1-d)*x(ind+1) + d*x(ind+2)" is responsible for smoothing the output signal also, due to the difference value used? $\endgroup$ Jan 11 '16 at 9:55
  • $\begingroup$ Yes! Just try it to observe computational performance and resulting accuracy. If both are acceptable it's juts fine. Else if accuracy is not acceptable but performance still allows we can always improve the interpolator.. $\endgroup$
    – Fat32
    Jan 11 '16 at 9:57

For a ratio of such large integers, you might be better off directly interpolating values at the sample points for the new sample rate using a high quality interpolator, rather than upsampling followed by downsampling. A windowed Sinc interpolation kernel of suitable width can include it's own anti-alas low-pass filter.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.