Subversion Repositories pentevo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
716 lvd 1
#include "../std.h"
2
 
3
#include "../emul.h"
4
#include "../vars.h"
5
 
6
/*
7
   sound resampling core for Unreal Speccy project
8
   created under public domain license by SMT, jan.2006
9
*/
10
 
11
#include "sndrender.h"
12
 
13
unsigned SNDRENDER::render(SNDOUT *src, unsigned srclen, unsigned clk_ticks, bufptr_t dst_start)
14
{
15
   start_frame(dst_start);
16
   for (unsigned index = 0; index < srclen; index++)
17
   {
18
      // if (src[index].timestamp > clk_ticks) continue; // wrong input data leads to crash
19
      update(src[index].timestamp, src[index].newvalue.ch.left, src[index].newvalue.ch.right);
20
   }
21
   return end_frame(clk_ticks);
22
}
23
 
24
const unsigned TICK_F = (1<<TICK_FF);
25
 
26
// b = 1+ln2(max_sndtick) = 1+ln2((max_sndfq*TICK_F)/min_intfq) = 1+ln2(48000*64/10) ~= 19.2;
27
// assert(b+MULT_C <= 32)
28
 
29
 
30
void SNDRENDER::start_frame(bufptr_t dst_start)
31
{
32
   SNDRENDER::dst_start = dstpos = dst_start;
33
   base_tick = tick;
34
   firstsmp = 4; //Alone Coder
35
}
36
 
37
void SNDRENDER::update(unsigned timestamp, unsigned l, unsigned r)
38
{
39
   if (!((l ^ mix_l) | (r ^ mix_r))) // (l == mix_l) && (r == mix_r)
40
       return;
41
 
42
//[vv]   unsigned endtick = (timestamp * mult_const) >> MULT_C;
43
   uint64_t endtick = (timestamp * (uint64_t)sample_rate * TICK_F) / clock_rate;
44
   flush( (unsigned) (base_tick + endtick) );
45
   mix_l = l; mix_r = r;
46
}
47
 
48
unsigned SNDRENDER::end_frame(unsigned clk_ticks)
49
{
50
   // adjusting 'clk_ticks' with whole history will fix accumulation of rounding errors
51
   //uint64_t endtick = ((passed_clk_ticks + clk_ticks) * mult_const) >> MULT_C;
52
   uint64_t endtick = ((passed_clk_ticks + clk_ticks) * (uint64_t)sample_rate * TICK_F) / clock_rate;
53
   flush( (unsigned) (endtick - passed_snd_ticks) );
54
 
55
   unsigned ready_samples = dstpos - dst_start;
56
   #ifdef SND_EXTERNAL_BUFFER
57
   if ((int)ready_samples < 0) ready_samples += SND_EXTERNAL_BUFFER_SIZE;
58
   #endif
59
 
60
   oldfrmleft = ((long)useleft + (long)olduseleft)/2; //Alone Coder
61
   oldfrmright = ((long)useright + (long)olduseright)/2; //Alone Coder
62
 
63
   tick -= (ready_samples << TICK_FF);
64
   passed_snd_ticks += (ready_samples << TICK_FF);
65
   passed_clk_ticks += clk_ticks;
66
 
67
   return ready_samples;
68
}
69
 
70
/*
71
unsigned SNDRENDER::end_empty_frame(unsigned clk_ticks)
72
{
73
   // adjusting 'clk_ticks' with whole history will fix accumulation of rounding errors
74
   //uint64_t endtick = ((passed_clk_ticks + clk_ticks) * mult_const) >> MULT_C;
75
   uint64_t endtick = ((passed_clk_ticks + clk_ticks) * (uint64_t)sample_rate * TICK_F) / clock_rate;
76
   tick = (unsigned)(endtick-passed_snd_ticks); // flush(endtick-passed_snd_ticks);
77
   // todo: change dstpos!
78
 
79
   unsigned ready_samples = dstpos - dst_start;
80
   #ifdef SND_EXTERNAL_BUFFER
81
   if ((int)ready_samples < 0) ready_samples += SND_EXTERNAL_BUFFER_SIZE;
82
   #endif
83
 
84
   tick -= (ready_samples << TICK_FF);
85
   passed_snd_ticks += (ready_samples << TICK_FF);
86
   passed_clk_ticks += clk_ticks;
87
 
88
   return ready_samples;
89
}
90
*/
91
 
92
void SNDRENDER::set_timings(unsigned clock_rate, unsigned sample_rate)
93
{
94
   SNDRENDER::clock_rate = clock_rate;
95
   SNDRENDER::sample_rate = sample_rate;
96
 
97
   tick = 0; dstpos = dst_start = 0;
98
   passed_snd_ticks = passed_clk_ticks = 0;
99
 
784 DimkaM 100
//   mult_const = (unsigned) (((uint64_t)sample_rate << (MULT_C+TICK_FF)) / clock_rate);
716 lvd 101
}
102
 
103
 
784 DimkaM 104
static unsigned filter_diff[TICK_F*2]; // discrete-time step response
716 lvd 105
const double filter_sum_full = 1.0, filter_sum_half = 0.5;
106
const unsigned filter_sum_full_u = (unsigned)(filter_sum_full * 0x10000),
107
               filter_sum_half_u = (unsigned)(filter_sum_half * 0x10000);
108
 
109
void SNDRENDER::flush(unsigned endtick)
110
{
784 DimkaM 111
    unsigned scale;
112
    if(!((endtick ^ tick) & ~(TICK_F - 1))) // (endtick / TICK_F) == (tick / TICK_F)
113
    {   // Оптимизация, децимация не нужна, т.к. после децимации tick совпадет с endtick
114
        // Входной сигнал изменился быстрее чем один период Fs выходного сигнала
115
        // s1 - значение выходного сигнала в левом узле децимации
116
        // s2 - значение выходного сигнала в правом узле децимации
117
        // mix - значение входного сигнала в интервале [tick.. endtick)
716 lvd 118
 
784 DimkaM 119
        //same discrete as before
120
        // Правая точка вычисленная по переходной характеристике
121
        scale = filter_diff[(endtick & (TICK_F - 1)) + TICK_F] - filter_diff[(tick & (TICK_F - 1)) + TICK_F];
122
        s2_l += mix_l * scale;
123
        s2_r += mix_r * scale;
716 lvd 124
 
784 DimkaM 125
        // Левая точка вычисленная по переходной характеристике
126
        scale = filter_diff[endtick & (TICK_F - 1)] - filter_diff[tick & (TICK_F - 1)];
127
        s1_l += mix_l * scale;
128
        s1_r += mix_r * scale;
716 lvd 129
 
784 DimkaM 130
        tick = endtick;
131
        return;
132
    }
716 lvd 133
 
784 DimkaM 134
    // Отрезок [TICK_F + (tick % TICK_F) ... 2*TICK_F-1]
135
    scale = filter_sum_full_u - filter_diff[(tick & (TICK_F - 1)) + TICK_F]; // filter_sum_full_u = filter_diff[(TICK_F - 1) + TICK_F]
716 lvd 136
 
784 DimkaM 137
    unsigned sample_value;
138
    if(conf.soundfilter)
139
    {
140
        /*lame noise reduction by Alone Coder*/
141
        int templeft = int(mix_l * scale + s2_l);
142
        /*olduseleft = useleft;
143
        if (firstsmp)useleft=oldfrmleft,firstsmp--;
144
            else*/ useleft = ((long)templeft + (long)oldleft) / 2;
145
        oldleft = templeft;
146
        int tempright = int(mix_r * scale + s2_r);
147
        /*olduseright = useright;
148
        if (firstsmp)useright=oldfrmright,firstsmp--;
149
            else*/ useright = ((long)tempright + (long)oldright) / 2;
150
        oldright = tempright;
151
        sample_value = unsigned((useleft >> 16) + int(unsigned(useright) & 0xFFFF0000));
152
        /**/
153
    }
154
    else
155
    {
156
        sample_value = ((mix_l*scale + s2_l) >> 16) +
157
            ((mix_r*scale + s2_r) & 0xFFFF0000);
158
    }
716 lvd 159
 
784 DimkaM 160
#ifdef SND_EXTERNAL_BUFFER
161
    SND_EXTERNAL_BUFFER[dstpos].sample += sample_value;
162
    dstpos = (dstpos + 1) & (SND_EXTERNAL_BUFFER_SIZE - 1);
163
#else
164
    dstpos->sample = sample_value;
165
    dstpos++;
166
#endif
716 lvd 167
 
784 DimkaM 168
    // Отрезок [tick % TICK_F ... TICK_F-1]
169
    scale = filter_sum_half_u - filter_diff[tick & (TICK_F - 1)];// filter_sum_half_u = filter_diff[TICK_F - 1]
170
    s2_l = s1_l + mix_l * scale;
171
    s2_r = s1_r + mix_r * scale;
172
 
173
    // Выравнивание до узла децимации
174
    tick = (tick | (TICK_F - 1)) + 1;
175
 
176
    // Цикл децимации в TICK_F раз, tick уже выровнен до сетки с шагом TICK_F
177
    // endtick / TICK_F - endtick после децимации в TICK_F раз
178
    // tick / TICK_F - tick после децимации в TICK_F раз
179
    if((endtick ^ tick) & ~(TICK_F - 1)) // (endtick / TICK_F) != (tick / TICK_F)
180
    { // Оптимизация, проверка на несовпадение tick и endtick после децимации
181
 
182
       // assume filter_coeff is symmetric
183
        // Отрезок [0 ... TICK_F-1]
184
        unsigned val_l = mix_l * filter_sum_half_u;
185
        unsigned val_r = mix_r * filter_sum_half_u;
186
 
187
        // Цикл децимации, [tick/TICK_F ... endtick/TICK_F)
188
        do
189
        {
716 lvd 190
            if(conf.soundfilter)
191
            {
192
                /*lame noise reduction by Alone Coder*/
784 DimkaM 193
                int templeft = int(s2_l + val_l);
716 lvd 194
                /*olduseleft = useleft;
195
                if (firstsmp)useleft=oldfrmleft,firstsmp--;
784 DimkaM 196
                   else*/ useleft = ((long)templeft + (long)oldleft) / 2;
716 lvd 197
                oldleft = templeft;
784 DimkaM 198
                int tempright = int(s2_r + val_r);
716 lvd 199
                /*olduseright = useright;
200
                if (firstsmp)useright=oldfrmright,firstsmp--;
784 DimkaM 201
                   else*/ useright = ((long)tempright + (long)oldright) / 2;
716 lvd 202
                oldright = tempright;
784 DimkaM 203
                sample_value = unsigned((useleft >> 16) + int(unsigned(useright) & 0xFFFF0000));
716 lvd 204
                /**/
205
            }
206
            else
207
            {
208
                sample_value = ((s2_l + val_l) >> 16) +
784 DimkaM 209
                    ((s2_r + val_r) & 0xFFFF0000); // save s2+val
716 lvd 210
            }
211
 
784 DimkaM 212
#ifdef SND_EXTERNAL_BUFFER
716 lvd 213
            SND_EXTERNAL_BUFFER[dstpos].sample += sample_value;
784 DimkaM 214
            dstpos = (dstpos + 1) & (SND_EXTERNAL_BUFFER_SIZE - 1);
215
#else
716 lvd 216
            dstpos->sample = sample_value;
217
            dstpos++;
784 DimkaM 218
#endif
716 lvd 219
 
220
            tick += TICK_F;
784 DimkaM 221
            s2_l = val_l;
222
            s2_r = val_r; // s2=s1, s1=0;
716 lvd 223
 
784 DimkaM 224
        } while((endtick ^ tick) & ~(TICK_F - 1)); // (endtick / TICK_F) != (tick / TICK_F)
225
    }
716 lvd 226
 
784 DimkaM 227
    tick = endtick;
716 lvd 228
 
784 DimkaM 229
    scale = filter_diff[(endtick & (TICK_F - 1)) + TICK_F] - filter_sum_half_u; // filter_sum_half_u = filter_diff[TICK_F - 1]
230
    s2_l += mix_l * scale;
231
    s2_r += mix_r * scale;
716 lvd 232
 
784 DimkaM 233
    scale = filter_diff[endtick & (TICK_F - 1)];
234
    s1_l = mix_l * scale;
235
    s1_r = mix_r * scale;
716 lvd 236
}
237
 
784 DimkaM 238
// bw = 1*(10^-2)*pi rad/smp (-3dB)
239
// bw = 2*(10^-2)*pi rad/smp (-10dB)
240
// bw = 20 kHz (fs=44100 * 64 = 2822400)
241
// matlab: fvtool(filter_coeff)
242
 
243
// Параметры синтеза фильтра:
244
// matlab: (fdatool/filterDesigner)
245
// FIR: Window (Hamming)
246
// order: 127
247
// Fs: 2822400
248
// Fc: 11025
249
 
716 lvd 250
const double filter_coeff[TICK_F*2] =
251
{
252
   // filter designed with Matlab's DSP toolbox
253
   0.000797243121022152, 0.000815206499600866, 0.000844792477531490, 0.000886460636664257,
254
   0.000940630171246217, 0.001007677515787512, 0.001087934129054332, 0.001181684445143001,
255
   0.001289164001921830, 0.001410557756409498, 0.001545998595893740, 0.001695566052785407,
256
   0.001859285230354019, 0.002037125945605404, 0.002229002094643918, 0.002434771244914945,
257
   0.002654234457752337, 0.002887136343664226, 0.003133165351783907, 0.003391954293894633,
258
   0.003663081102412781, 0.003946069820687711, 0.004240391822953223, 0.004545467260249598,
259
   0.004860666727631453, 0.005185313146989532, 0.005518683858848785, 0.005860012915564928,
260
   0.006208493567431684, 0.006563280932335042, 0.006923494838753613, 0.007288222831108771,
261
   0.007656523325719262, 0.008027428904915214, 0.008399949736219575, 0.008773077102914008,
262
   0.009145787031773989, 0.009517044003286715, 0.009885804729257883, 0.010251021982371376,
263
   0.010611648461991030, 0.010966640680287394, 0.011314962852635887, 0.011655590776166550,
264
   0.011987515680350414, 0.012309748033583185, 0.012621321289873522, 0.012921295559959939,
265
   0.013208761191466523, 0.013482842243062109, 0.013742699838008606, 0.013987535382970279,
266
   0.014216593638504731, 0.014429165628265581, 0.014624591374614174, 0.014802262449059521,
267
   0.014961624326719471, 0.015102178534818147, 0.015223484586101132, 0.015325161688957322,
268
   0.015406890226980602, 0.015468413001680802, 0.015509536233058410, 0.015530130313785910,
269
   0.015530130313785910, 0.015509536233058410, 0.015468413001680802, 0.015406890226980602,
270
   0.015325161688957322, 0.015223484586101132, 0.015102178534818147, 0.014961624326719471,
271
   0.014802262449059521, 0.014624591374614174, 0.014429165628265581, 0.014216593638504731,
272
   0.013987535382970279, 0.013742699838008606, 0.013482842243062109, 0.013208761191466523,
273
   0.012921295559959939, 0.012621321289873522, 0.012309748033583185, 0.011987515680350414,
274
   0.011655590776166550, 0.011314962852635887, 0.010966640680287394, 0.010611648461991030,
275
   0.010251021982371376, 0.009885804729257883, 0.009517044003286715, 0.009145787031773989,
276
   0.008773077102914008, 0.008399949736219575, 0.008027428904915214, 0.007656523325719262,
277
   0.007288222831108771, 0.006923494838753613, 0.006563280932335042, 0.006208493567431684,
278
   0.005860012915564928, 0.005518683858848785, 0.005185313146989532, 0.004860666727631453,
279
   0.004545467260249598, 0.004240391822953223, 0.003946069820687711, 0.003663081102412781,
280
   0.003391954293894633, 0.003133165351783907, 0.002887136343664226, 0.002654234457752337,
281
   0.002434771244914945, 0.002229002094643918, 0.002037125945605404, 0.001859285230354019,
282
   0.001695566052785407, 0.001545998595893740, 0.001410557756409498, 0.001289164001921830,
283
   0.001181684445143001, 0.001087934129054332, 0.001007677515787512, 0.000940630171246217,
284
   0.000886460636664257, 0.000844792477531490, 0.000815206499600866, 0.000797243121022152
285
};
286
 
784 DimkaM 287
// h - impulse response
288
// s - step response
289
// h[n] = s[n] - s[n-1]
290
 
291
// y[n] = sum(x[k]*h[n-k]) = sum(h[k]*x[n-k])
292
//         k                  k
293
// Для кусочно постоянного сигнала применима оптимизация в вычислениях (нет необходимости вычислять промежуточные точки)
294
// y[n] = y[k] + x*(s[n] - s[k])
295
// где n и k - концы интервала, на котором сигнал x постоянен
296
 
297
// Общие формулы:
298
// u - unit step
299
// s - step response
300
//                        inf
301
// x[n] = x[-inf] + sum((x[k]-x[k-1])u[n-k])
302
//                       -inf
303
//
304
//                        inf
305
// y[n] = x[-inf]s[inf] + sum(x[k]-x[k-1])s[n-k]
306
//                       -inf
307
// Из формкл видно, что значения имеют только фронты сигнала, там где сигнал постоянный слагаеые обращаются в ноль
308
// отсюда становится возможна кусочно-постоянная оптимизация
309
 
310
// Для YM (значения берутся из конфига)
311
// для примера:
312
// clock_rate = 1750000 / 8 = 218750
313
//              1774400 / 8 = 221800
314
// sample_rate = 44100
315
// ПЧ = sample_rate * 64 = 2822400
316
// Перенос входного сигнала на ПЧ делается домножением на (sample_rate*64)/clock_rate = 
317
// 12.9024 (для clock_rate = 1.7500) и 12.724977 (для clock_rate = 1.7744)
318
// На ПЧ делается фильтрация и децимация в 64 раза до sample_rate
319
 
716 lvd 320
SNDRENDER::SNDRENDER()
321
{
322
   set_timings(SNDR_DEFAULT_SYSTICK_RATE, SNDR_DEFAULT_SAMPLE_RATE);
323
 
324
   static char diff_ready = 0;
325
   if (!diff_ready) {
326
      double sum = 0;
784 DimkaM 327
      for (unsigned i = 0; i < TICK_F*2; i++) { // calculate discrete-time step response
328
         filter_diff[i] = unsigned(sum * 0x10000);
329
         sum += filter_coeff[i]; // Тут ошибка, сумму надо вычислять до построения переходной характеристики, чтобы filter_diff[0] == filter_coeff[0]
330
                                 // filter_diff[TICK_F - 1] == 0.5, filter_diff[2*TICK_F - 1] == 1.0
716 lvd 331
      }
332
      diff_ready = 1;
333
   }
334
}