DOSBox-X
|
00001 #include "np2glue.h" 00002 //#include "compiler.h" 00003 #include "sound.h" 00004 #include "adpcm.h" 00005 00006 00007 #define ADPCM_NBR 0x80000000 00008 00009 static const UINT adpcmdeltatable[8] = { 00010 // 0.89, 0.89, 0.89, 0.89, 1.2, 1.6, 2.0, 2.4 00011 228, 228, 228, 228, 308, 408, 512, 612}; 00012 00013 00014 REG8 SOUNDCALL adpcm_readsample(ADPCM ad) { 00015 00016 UINT32 pos; 00017 REG8 data; 00018 REG8 ret; 00019 00020 if ((ad->reg.ctrl1 & 0x60) == 0x20) { 00021 pos = ad->pos & 0x1fffff; 00022 if (!(ad->reg.ctrl2 & 2)) { 00023 data = ad->buf[pos >> 3]; 00024 pos += 8; 00025 } 00026 else { 00027 const UINT8 *ptr; 00028 REG8 bit; 00029 UINT tmp; 00030 ptr = ad->buf + ((pos >> 3) & 0x7fff); 00031 bit = 1 << (pos & 7); 00032 tmp = (ptr[0x00000] & bit); 00033 tmp += (ptr[0x08000] & bit) << 1; 00034 tmp += (ptr[0x10000] & bit) << 2; 00035 tmp += (ptr[0x18000] & bit) << 3; 00036 tmp += (ptr[0x20000] & bit) << 4; 00037 tmp += (ptr[0x28000] & bit) << 5; 00038 tmp += (ptr[0x30000] & bit) << 6; 00039 tmp += (ptr[0x38000] & bit) << 7; 00040 data = (REG8)(tmp >> (pos & 7)); 00041 pos++; 00042 } 00043 if (pos != ad->stop) { 00044 pos &= 0x1fffff; 00045 ad->status |= 4; 00046 } 00047 if (pos >= ad->limit) { 00048 pos = 0; 00049 } 00050 ad->pos = pos; 00051 } 00052 else { 00053 data = 0; 00054 } 00055 pos = ad->fifopos; 00056 ret = ad->fifo[ad->fifopos]; 00057 ad->fifo[ad->fifopos] = data; 00058 ad->fifopos ^= 1; 00059 return(ret); 00060 } 00061 00062 void SOUNDCALL adpcm_datawrite(ADPCM ad, REG8 data) { 00063 00064 UINT32 pos; 00065 00066 pos = ad->pos & 0x1fffff; 00067 if (!(ad->reg.ctrl2 & 2)) { 00068 ad->buf[pos >> 3] = data; 00069 pos += 8; 00070 } 00071 else { 00072 UINT8 *ptr; 00073 UINT8 bit; 00074 UINT8 mask; 00075 ptr = ad->buf + ((pos >> 3) & 0x7fff); 00076 bit = 1 << (pos & 7); 00077 mask = ~bit; 00078 ptr[0x00000] &= mask; 00079 if (data & 0x01) { 00080 ptr[0x00000] |= bit; 00081 } 00082 ptr[0x08000] &= mask; 00083 if (data & 0x02) { 00084 ptr[0x08000] |= bit; 00085 } 00086 ptr[0x10000] &= mask; 00087 if (data & 0x04) { 00088 ptr[0x10000] |= bit; 00089 } 00090 ptr[0x18000] &= mask; 00091 if (data & 0x08) { 00092 ptr[0x18000] |= bit; 00093 } 00094 ptr[0x20000] &= mask; 00095 if (data & 0x10) { 00096 ptr[0x20000] |= bit; 00097 } 00098 ptr[0x28000] &= mask; 00099 if (data & 0x20) { 00100 ptr[0x28000] |= bit; 00101 } 00102 ptr[0x30000] &= mask; 00103 if (data & 0x40) { 00104 ptr[0x30000] |= bit; 00105 } 00106 ptr[0x38000] &= mask; 00107 if (data & 0x80) { 00108 ptr[0x38000] |= bit; 00109 } 00110 pos++; 00111 } 00112 if (pos == ad->stop) { 00113 pos &= 0x1fffff; 00114 ad->status |= 4; 00115 } 00116 if (pos >= ad->limit) { 00117 pos = 0; 00118 } 00119 ad->pos = pos; 00120 } 00121 00122 static void SOUNDCALL getadpcmdata(ADPCM ad) { 00123 00124 UINT32 pos; 00125 UINT data; 00126 UINT dir; 00127 SINT32 dlt; 00128 SINT32 samp; 00129 00130 pos = ad->pos; 00131 if (!(ad->reg.ctrl2 & 2)) { 00132 data = ad->buf[(pos >> 3) & 0x3ffff]; 00133 if (!(pos & ADPCM_NBR)) { 00134 data >>= 4; 00135 } 00136 pos += ADPCM_NBR + 4; 00137 } 00138 else { 00139 const UINT8 *ptr; 00140 REG8 bit; 00141 UINT tmp; 00142 ptr = ad->buf + ((pos >> 3) & 0x7fff); 00143 bit = 1 << (pos & 7); 00144 if (!(pos & ADPCM_NBR)) { 00145 tmp = (ptr[0x20000] & bit); 00146 tmp += (ptr[0x28000] & bit) << 1; 00147 tmp += (ptr[0x30000] & bit) << 2; 00148 tmp += (ptr[0x38000] & bit) << 3; 00149 data = tmp >> (pos & 7); 00150 pos += ADPCM_NBR; 00151 } 00152 else { 00153 tmp = (ptr[0x00000] & bit); 00154 tmp += (ptr[0x08000] & bit) << 1; 00155 tmp += (ptr[0x10000] & bit) << 2; 00156 tmp += (ptr[0x18000] & bit) << 3; 00157 data = tmp >> (pos & 7); 00158 pos += ADPCM_NBR + 1; 00159 } 00160 } 00161 dir = data & 8; 00162 data &= 7; 00163 dlt = adpcmdeltatable[data] * ad->delta; 00164 dlt >>= 8; 00165 if (dlt < 127) { 00166 dlt = 127; 00167 } 00168 else if (dlt > 24000) { 00169 dlt = 24000; 00170 } 00171 samp = ad->delta; 00172 ad->delta = dlt; 00173 samp *= ((data * 2) + 1); 00174 samp >>= ADPCM_SHIFT; 00175 if (!dir) { 00176 samp += ad->samp; 00177 if (samp > 32767) { 00178 samp = 32767; 00179 } 00180 } 00181 else { 00182 samp = ad->samp - samp; 00183 if (samp < -32767) { 00184 samp = -32767; 00185 } 00186 } 00187 ad->samp = samp; 00188 00189 if (!(pos & ADPCM_NBR)) { 00190 if (pos == ad->stop) { 00191 if (ad->reg.ctrl1 & 0x10) { 00192 pos = ad->start; 00193 ad->samp = 0; 00194 ad->delta = 127; 00195 } 00196 else { 00197 pos &= 0x1fffff; 00198 ad->status |= 4; 00199 ad->play = 0; 00200 } 00201 } 00202 else if (pos >= ad->limit) { 00203 pos = 0; 00204 } 00205 } 00206 ad->pos = pos; 00207 samp *= ad->level; 00208 samp >>= (10 + 1); 00209 ad->out0 = ad->out1; 00210 ad->out1 = samp + ad->fb; 00211 ad->fb = samp >> 1; 00212 } 00213 00214 void SOUNDCALL adpcm_getpcm(ADPCM ad, SINT32 *pcm, UINT count) { 00215 00216 SINT32 remain; 00217 SINT32 samp; 00218 00219 if ((count == 0) || (ad->play == 0)) { 00220 return; 00221 } 00222 remain = ad->remain; 00223 if (ad->step <= ADTIMING) { 00224 do { 00225 if (remain < 0) { 00226 remain += ADTIMING; 00227 getadpcmdata(ad); 00228 if (ad->play == 0) { 00229 if (remain > 0) { 00230 do { 00231 samp = (ad->out0 * remain) >> ADTIMING_BIT; 00232 if (ad->reg.ctrl2 & 0x80) { 00233 pcm[0] += samp; 00234 } 00235 if (ad->reg.ctrl2 & 0x40) { 00236 pcm[1] += samp; 00237 } 00238 pcm += 2; 00239 remain -= ad->step; 00240 } while((remain > 0) && (--count)); 00241 } 00242 goto adpcmstop; 00243 } 00244 } 00245 samp = (ad->out0 * remain) + (ad->out1 * (ADTIMING - remain)); 00246 samp >>= ADTIMING_BIT; 00247 if (ad->reg.ctrl2 & 0x80) { 00248 pcm[0] += samp; 00249 } 00250 if (ad->reg.ctrl2 & 0x40) { 00251 pcm[1] += samp; 00252 } 00253 pcm += 2; 00254 remain -= ad->step; 00255 } while(--count); 00256 } 00257 else { 00258 do { 00259 if (remain > 0) { 00260 samp = ad->out0 * (ADTIMING - remain); 00261 do { 00262 getadpcmdata(ad); 00263 if (ad->play == 0) { 00264 goto adpcmstop; 00265 } 00266 samp += ad->out0 * min(remain, ad->pertim); 00267 remain -= ad->pertim; 00268 } while(remain > 0); 00269 } 00270 else { 00271 samp = ad->out0 * ADTIMING; 00272 } 00273 remain += ADTIMING; 00274 samp >>= ADTIMING_BIT; 00275 if (ad->reg.ctrl2 & 0x80) { 00276 pcm[0] += samp; 00277 } 00278 if (ad->reg.ctrl2 & 0x40) { 00279 pcm[1] += samp; 00280 } 00281 pcm += 2; 00282 } while(--count); 00283 } 00284 ad->remain = remain; 00285 return; 00286 00287 adpcmstop: 00288 ad->out0 = 0; 00289 ad->out1 = 0; 00290 ad->fb = 0; 00291 ad->remain = 0; 00292 } 00293