bool AudioInterface::init() { if(!p) driver(); return p->init(); } void AudioInterface::term() { if(p) { delete p; p = 0; } } bool AudioInterface::cap(Audio::Setting setting) { if(setting == Audio::Volume) return true; if(setting == Audio::Resample) return true; if(setting == Audio::ResampleOutputFrequency) return true; if(setting == Audio::ResampleInputFrequency) return true; return p ? p->cap(setting) : false; } uintptr_t AudioInterface::get(Audio::Setting setting) { if(setting == Audio::Volume) return volume; if(setting == Audio::Resample) return resample_enabled; if(setting == Audio::ResampleOutputFrequency) return r_outfreq; if(setting == Audio::ResampleInputFrequency) return r_infreq; return p ? p->get(setting) : false; } bool AudioInterface::set(Audio::Setting setting, uintptr_t param) { if(setting == Audio::Volume) { volume = param; return true; } if(setting == Audio::Resample) { resample_enabled = param; return true; } if(setting == Audio::ResampleOutputFrequency) { r_outfreq = max(1, param); r_step = (double)r_infreq / (double)r_outfreq; r_frac = 0; return true; } if(setting == Audio::ResampleInputFrequency) { r_infreq = max(1, param); r_step = (double)r_infreq / (double)r_outfreq; r_frac = 0; return true; } return p ? p->set(setting, param) : false; } //4-tap hermite interpolation double AudioInterface::hermite(double mu1, double a, double b, double c, double d) { const double tension = 0.0; //-1 = low, 0 = normal, 1 = high const double bias = 0.0; //-1 = left, 0 = even, 1 = right double mu2, mu3, m0, m1, a0, a1, a2, a3; mu2 = mu1 * mu1; mu3 = mu2 * mu1; m0 = (b - a) * (1 + bias) * (1 - tension) / 2; m0 += (c - b) * (1 - bias) * (1 - tension) / 2; m1 = (c - b) * (1 + bias) * (1 - tension) / 2; m1 += (d - c) * (1 - bias) * (1 - tension) / 2; a0 = +2 * mu3 - 3 * mu2 + 1; a1 = mu3 - 2 * mu2 + mu1; a2 = mu3 - mu2; a3 = -2 * mu3 + 3 * mu2; return (a0 * b) + (a1 * m0) + (a2 * m1) + (a3 * c); } void AudioInterface::sample(uint16_t left, uint16_t right) { int s_left = (int16_t)left; int s_right = (int16_t)right; if(volume != 100) { s_left = sclamp<16>((double)s_left * (double)volume / 100.0); s_right = sclamp<16>((double)s_right * (double)volume / 100.0); } r_left [0] = r_left [1]; r_left [1] = r_left [2]; r_left [2] = r_left [3]; r_left [3] = s_left; r_right[0] = r_right[1]; r_right[1] = r_right[2]; r_right[2] = r_right[3]; r_right[3] = s_right; if(resample_enabled == false) { if(p) p->sample(left, right); return; } while(r_frac <= 1.0) { int output_left = sclamp<16>(hermite(r_frac, r_left [0], r_left [1], r_left [2], r_left [3])); int output_right = sclamp<16>(hermite(r_frac, r_right[0], r_right[1], r_right[2], r_right[3])); r_frac += r_step; if(p) p->sample(output_left, output_right); } r_frac -= 1.0; } void AudioInterface::clear() { r_frac = 0; r_left [0] = r_left [1] = r_left [2] = r_left [3] = 0; r_right[0] = r_right[1] = r_right[2] = r_right[3] = 0; if(p) p->clear(); } AudioInterface::AudioInterface() { p = 0; volume = 100; resample_enabled = false; r_outfreq = r_infreq = 1; r_step = r_frac = 0; r_left [0] = r_left [1] = r_left [2] = r_left [3] = 0; r_right[0] = r_right[1] = r_right[2] = r_right[3] = 0; } AudioInterface::~AudioInterface() { term(); }