1 #include "opn_chip_base.h"
2 #include <cmath>
3 #include <cstdio>
4 
5 #if defined(OPNMIDI_ENABLE_HQ_RESAMPLER)
6 #include <zita-resampler/vresampler.h>
7 #endif
8 
9 #if !defined(LIKELY) && defined(__GNUC__)
10 #define LIKELY(x) __builtin_expect((x), 1)
11 #elif !defined(LIKELY)
12 #define LIKELY(x) (x)
13 #endif
14 
15 #if !defined(UNLIKELY) && defined(__GNUC__)
16 #define UNLIKELY(x) __builtin_expect((x), 0)
17 #elif !defined(UNLIKELY)
18 #define UNLIKELY(x) (x)
19 #endif
20 
21 /* OPNChipBase */
OPNChipBase(OPNFamily f)22 inline OPNChipBase::OPNChipBase(OPNFamily f) :
23     m_id(0),
24     m_rate(44100),
25     m_clock(7670454),
26     m_family(f)
27 {
28 }
29 
~OPNChipBase()30 inline OPNChipBase::~OPNChipBase()
31 {
32 }
33 
clockRate() const34 inline uint32_t OPNChipBase::clockRate() const
35 {
36     return m_clock;
37 }
38 
39 /* OPNChipBaseT */
40 
41 template <class T>
OPNChipBaseT(OPNFamily f)42 OPNChipBaseT<T>::OPNChipBaseT(OPNFamily f)
43     : OPNChipBase(f),
44       m_runningAtPcmRate(false)
45 #if defined(OPNMIDI_AUDIO_TICK_HANDLER)
46     ,
47       m_audioTickHandlerInstance(NULL)
48 #endif
49 {
50 #if defined(OPNMIDI_ENABLE_HQ_RESAMPLER)
51     m_resampler = new VResampler;
52 #endif
53     setupResampler(m_rate);
54 }
55 
56 template <class T>
~OPNChipBaseT()57 OPNChipBaseT<T>::~OPNChipBaseT()
58 {
59 #if defined(OPNMIDI_ENABLE_HQ_RESAMPLER)
60     delete m_resampler;
61 #endif
62 }
63 
64 template <class T>
family() const65 OPNFamily OPNChipBaseT<T>::family() const
66 {
67     return m_family;
68 }
69 
70 template <class T>
nativeClockRate() const71 uint32_t OPNChipBaseT<T>::nativeClockRate() const
72 {
73     return opn2_getNativeClockRate(m_family);
74 }
75 
76 template <class T>
isRunningAtPcmRate() const77 bool OPNChipBaseT<T>::isRunningAtPcmRate() const
78 {
79     return m_runningAtPcmRate;
80 }
81 
82 template <class T>
setRunningAtPcmRate(bool r)83 bool OPNChipBaseT<T>::setRunningAtPcmRate(bool r)
84 {
85     if(r != m_runningAtPcmRate)
86     {
87         if(r && !static_cast<T *>(this)->canRunAtPcmRate())
88             return false;
89         m_runningAtPcmRate = r;
90         static_cast<T *>(this)->setRate(m_rate, m_clock);
91     }
92     return true;
93 }
94 
95 #if defined(OPNMIDI_AUDIO_TICK_HANDLER)
96 template <class T>
setAudioTickHandlerInstance(void * instance)97 void OPNChipBaseT<T>::setAudioTickHandlerInstance(void *instance)
98 {
99     m_audioTickHandlerInstance = instance;
100 }
101 #endif
102 
103 template <class T>
setRate(uint32_t rate,uint32_t clock)104 void OPNChipBaseT<T>::setRate(uint32_t rate, uint32_t clock)
105 {
106     uint32_t oldRate = m_rate;
107     uint32_t oldClock = m_clock;
108     m_rate = rate;
109     m_clock = clock;
110     if(rate != oldRate || clock != oldClock)
111         setupResampler(rate);
112     else
113         resetResampler();
114 }
115 
116 template <class T>
effectiveRate() const117 uint32_t OPNChipBaseT<T>::effectiveRate() const
118 {
119     return m_runningAtPcmRate ? m_rate : opn2_getNativeRate(m_family);
120 }
121 
122 template <class T>
nativeRate() const123 uint32_t OPNChipBaseT<T>::nativeRate() const
124 {
125     return opn2_getNativeRate(m_family);
126 }
127 
128 template <class T>
reset()129 void OPNChipBaseT<T>::reset()
130 {
131     resetResampler();
132 }
133 
134 template <class T>
generate(int16_t * output,size_t frames)135 void OPNChipBaseT<T>::generate(int16_t *output, size_t frames)
136 {
137     static_cast<T *>(this)->nativePreGenerate();
138     for(size_t i = 0; i < frames; ++i)
139     {
140         int32_t frame[2];
141         static_cast<T *>(this)->resampledGenerate(frame);
142         for (unsigned c = 0; c < 2; ++c) {
143             int32_t temp = frame[c];
144             temp = (temp > -32768) ? temp : -32768;
145             temp = (temp < 32767) ? temp : 32767;
146             output[c] = (int16_t)temp;
147         }
148         output += 2;
149     }
150     static_cast<T *>(this)->nativePostGenerate();
151 }
152 
153 template <class T>
generateAndMix(int16_t * output,size_t frames)154 void OPNChipBaseT<T>::generateAndMix(int16_t *output, size_t frames)
155 {
156     static_cast<T *>(this)->nativePreGenerate();
157     for(size_t i = 0; i < frames; ++i)
158     {
159         int32_t frame[2];
160         static_cast<T *>(this)->resampledGenerate(frame);
161         for (unsigned c = 0; c < 2; ++c) {
162             int32_t temp = (int32_t)output[c] + frame[c];
163             temp = (temp > -32768) ? temp : -32768;
164             temp = (temp < 32767) ? temp : 32767;
165             output[c] = (int16_t)temp;
166         }
167         output += 2;
168     }
169     static_cast<T *>(this)->nativePostGenerate();
170 }
171 
172 template <class T>
generate32(int32_t * output,size_t frames)173 void OPNChipBaseT<T>::generate32(int32_t *output, size_t frames)
174 {
175     static_cast<T *>(this)->nativePreGenerate();
176     for(size_t i = 0; i < frames; ++i)
177     {
178         static_cast<T *>(this)->resampledGenerate(output);
179         output += 2;
180     }
181     static_cast<T *>(this)->nativePostGenerate();
182 }
183 
184 template <class T>
generateAndMix32(int32_t * output,size_t frames)185 void OPNChipBaseT<T>::generateAndMix32(int32_t *output, size_t frames)
186 {
187     static_cast<T *>(this)->nativePreGenerate();
188     for(size_t i = 0; i < frames; ++i)
189     {
190         int32_t frame[2];
191         static_cast<T *>(this)->resampledGenerate(frame);
192         output[0] += frame[0];
193         output[1] += frame[1];
194         output += 2;
195     }
196     static_cast<T *>(this)->nativePostGenerate();
197 }
198 
199 template <class T>
nativeTick(int16_t * frame)200 void OPNChipBaseT<T>::nativeTick(int16_t *frame)
201 {
202 #if defined(OPNMIDI_AUDIO_TICK_HANDLER)
203     opn2_audioTickHandler(m_audioTickHandlerInstance, m_id, effectiveRate());
204 #endif
205     static_cast<T *>(this)->nativeGenerate(frame);
206 }
207 
208 template <class T>
setupResampler(uint32_t rate)209 void OPNChipBaseT<T>::setupResampler(uint32_t rate)
210 {
211 #if defined(OPNMIDI_ENABLE_HQ_RESAMPLER)
212     double ratio = rate * (1.0 / opn2_getNativeRate(m_family));
213     m_resampler->setup(ratio, 2, 48);
214 #else
215     m_oldsamples[0] = m_oldsamples[1] = 0;
216     m_samples[0] = m_samples[1] = 0;
217     m_samplecnt = 0;
218     m_rateratio = (int32_t)(uint32_t)((((uint64_t)144 * rate) << rsm_frac) / m_clock);
219 #endif
220 }
221 
222 template <class T>
resetResampler()223 void OPNChipBaseT<T>::resetResampler()
224 {
225 #if defined(OPNMIDI_ENABLE_HQ_RESAMPLER)
226     m_resampler->reset();
227 #else
228     m_oldsamples[0] = m_oldsamples[1] = 0;
229     m_samples[0] = m_samples[1] = 0;
230     m_samplecnt = 0;
231 #endif
232 }
233 
234 #if defined(OPNMIDI_ENABLE_HQ_RESAMPLER)
235 template <class T>
resampledGenerate(int32_t * output)236 void OPNChipBaseT<T>::resampledGenerate(int32_t *output)
237 {
238     if(UNLIKELY(m_runningAtPcmRate))
239     {
240         int16_t in[2];
241         static_cast<T *>(this)->nativeTick(in);
242         output[0] = (int32_t)in[0] * T::resamplerPreAmplify / T::resamplerPostAttenuate;
243         output[1] = (int32_t)in[1] * T::resamplerPreAmplify / T::resamplerPostAttenuate;
244         return;
245     }
246 
247     VResampler *rsm = m_resampler;
248     float scale = (float)T::resamplerPreAmplify /
249         (float)T::resamplerPostAttenuate;
250     float f_in[2];
251     float f_out[2];
252     rsm->inp_count = 0;
253     rsm->inp_data = f_in;
254     rsm->out_count = 1;
255     rsm->out_data = f_out;
256     while(rsm->process(), rsm->out_count != 0)
257     {
258         int16_t in[2];
259         static_cast<T *>(this)->nativeTick(in);
260         f_in[0] = scale * (float)in[0];
261         f_in[1] = scale * (float)in[1];
262         rsm->inp_count = 1;
263         rsm->inp_data = f_in;
264         rsm->out_count = 1;
265         rsm->out_data = f_out;
266     }
267     output[0] = static_cast<int32_t>(lround(f_out[0]));
268     output[1] = static_cast<int32_t>(lround(f_out[1]));
269 }
270 #else
271 template <class T>
resampledGenerate(int32_t * output)272 void OPNChipBaseT<T>::resampledGenerate(int32_t *output)
273 {
274     if(UNLIKELY(m_runningAtPcmRate))
275     {
276         int16_t in[2];
277         static_cast<T *>(this)->nativeTick(in);
278         output[0] = (int32_t)in[0] * T::resamplerPreAmplify / T::resamplerPostAttenuate;
279         output[1] = (int32_t)in[1] * T::resamplerPreAmplify / T::resamplerPostAttenuate;
280         return;
281     }
282 
283     int32_t samplecnt = m_samplecnt;
284     const int32_t rateratio = m_rateratio;
285     while(samplecnt >= rateratio)
286     {
287         m_oldsamples[0] = m_samples[0];
288         m_oldsamples[1] = m_samples[1];
289         int16_t buffer[2];
290         static_cast<T *>(this)->nativeTick(buffer);
291         m_samples[0] = buffer[0] * T::resamplerPreAmplify;
292         m_samples[1] = buffer[1] * T::resamplerPreAmplify;
293         samplecnt -= rateratio;
294     }
295     output[0] = (int32_t)(((m_oldsamples[0] * (rateratio - samplecnt)
296                             + m_samples[0] * samplecnt) / rateratio)/T::resamplerPostAttenuate);
297     output[1] = (int32_t)(((m_oldsamples[1] * (rateratio - samplecnt)
298                             + m_samples[1] * samplecnt) / rateratio)/T::resamplerPostAttenuate);
299     m_samplecnt = samplecnt + (1 << rsm_frac);
300 }
301 #endif
302 
303 /* OPNChipBaseBufferedT */
304 
305 template <class T, unsigned Buffer>
reset()306 void OPNChipBaseBufferedT<T, Buffer>::reset()
307 {
308     OPNChipBaseT<T>::reset();
309     m_bufferIndex = 0;
310 }
311 
312 template <class T, unsigned Buffer>
nativeGenerate(int16_t * frame)313 void OPNChipBaseBufferedT<T, Buffer>::nativeGenerate(int16_t *frame)
314 {
315     unsigned bufferIndex = m_bufferIndex;
316     if(bufferIndex == 0)
317         static_cast<T *>(this)->nativeGenerateN(m_buffer, Buffer);
318     frame[0] = m_buffer[2 * bufferIndex];
319     frame[1] = m_buffer[2 * bufferIndex + 1];
320     bufferIndex = (bufferIndex + 1 < Buffer) ? (bufferIndex + 1) : 0;
321     m_bufferIndex = bufferIndex;
322 }
323