move more globals to PicoInterface
[picodrive.git] / pico / pico / xpcm.c
1 /*
2  * PicoDrive
3  * (C) notaz, 2008
4  *
5  * This work is licensed under the terms of MAME license.
6  * See COPYING file in the top-level directory.
7  *
8  * The following ADPCM algorithm was stolen from MAME aica driver.
9  * I'm quite sure it's not the right one, but it's the
10  * best sounding of the ones that I tried.
11  */
12
13 #include "../pico_int.h"
14
15 #define ADPCMSHIFT      8
16 #define ADFIX(f)        (int) ((double)f * (double)(1<<ADPCMSHIFT))
17
18 /* limitter */
19 #define Limit(val, max, min) { \
20         if ( val > max )      val = max; \
21         else if ( val < min ) val = min; \
22 }
23
24 static const int TableQuant[8] =
25 {
26   ADFIX(0.8984375),
27   ADFIX(0.8984375),
28   ADFIX(0.8984375),
29   ADFIX(0.8984375),
30   ADFIX(1.19921875),
31   ADFIX(1.59765625),
32   ADFIX(2.0),
33   ADFIX(2.3984375)
34 };
35
36 // changed using trial and error..
37 //static const int quant_mul[16] = { 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15 };
38 static const int quant_mul[16]   = { 1, 3, 5, 7, 9, 11, 13, -1, -1, -3, -5, -7, -9, -11, -13, -15 };
39
40 static int sample = 0, quant = 0, sgn = 0;
41 static int stepsamples = (44100<<10)/16000;
42
43
44 PICO_INTERNAL void PicoPicoPCMReset(void)
45 {
46   sample = sgn = 0;
47   quant = 0x7f;
48   memset(PicoPicohw.xpcm_buffer, 0, sizeof(PicoPicohw.xpcm_buffer));
49 }
50
51 PICO_INTERNAL void PicoPicoPCMRerate(int xpcm_rate)
52 {
53   stepsamples = (PicoIn.sndRate<<10)/xpcm_rate;
54 }
55
56 #define XSHIFT 6
57
58 #define do_sample() \
59 { \
60   int delta = quant * quant_mul[srcval] >> XSHIFT; \
61   sample += delta - (delta >> 2); /* 3/4 */ \
62   quant = (quant * TableQuant[srcval&7]) >> ADPCMSHIFT; \
63   Limit(quant, 0x6000, 0x7f); \
64   Limit(sample, 32767*3/4, -32768*3/4); \
65 }
66
67 PICO_INTERNAL void PicoPicoPCMUpdate(short *buffer, int length, int stereo)
68 {
69   unsigned char *src = PicoPicohw.xpcm_buffer;
70   unsigned char *lim = PicoPicohw.xpcm_ptr;
71   int srcval, needsamples = 0;
72
73   if (src == lim) goto end;
74
75   for (; length > 0 && src < lim; src++)
76   {
77     srcval = *src >> 4;
78     do_sample();
79
80     for (needsamples += stepsamples; needsamples > (1<<10) && length > 0; needsamples -= (1<<10), length--) {
81       *buffer++ += sample;
82       if (stereo) { buffer[0] = buffer[-1]; buffer++; }
83     }
84
85     srcval = *src & 0xf;
86     do_sample();
87
88     for (needsamples += stepsamples; needsamples > (1<<10) && length > 0; needsamples -= (1<<10), length--) {
89       *buffer++ += sample;
90       if (stereo) { buffer[0] = buffer[-1]; buffer++; }
91     }
92
93     // lame normalization stuff, needed due to wrong adpcm algo
94     sgn += (sample < 0) ? -1 : 1;
95     if (sgn < -16 || sgn > 16) sample -= sample >> 5;
96   }
97
98   if (src < lim) {
99     int di = lim - src;
100     memmove(PicoPicohw.xpcm_buffer, src, di);
101     PicoPicohw.xpcm_ptr = PicoPicohw.xpcm_buffer + di;
102     elprintf(EL_PICOHW, "xpcm update: over %i", di);
103     // adjust fifo
104     PicoPicohw.fifo_bytes = di;
105     return;
106   }
107
108   elprintf(EL_PICOHW, "xpcm update: under %i", length);
109   PicoPicohw.xpcm_ptr = PicoPicohw.xpcm_buffer;
110
111 end:
112   if (stereo)
113     // still must expand SN76496 to stereo
114     for (; length > 0; buffer+=2, length--)
115       buffer[1] = buffer[0];
116
117   sample = sgn = 0;
118   quant = 0x7f;
119 }
120