DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/snd_pc98/sound/adpcmg.c
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