DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/snd_pc98/sound/sound.c
00001 #include    "np2glue.h"
00002 //#include      "compiler.h"
00003 #include        "wavefile.h"
00004 #include        "dosio.h"
00005 //#include      "soundmng.h"
00006 //#include      "cpucore.h"
00007 //#include      "pccore.h"
00008 //#include      "iocore.h"
00009 #include        "sound.h"
00010 #include        "sndcsec.h"
00011 //#include      "beep.h"
00012 #include        "getsnd.h"
00013 
00014 #if 0
00015 
00016         SOUNDCFG        soundcfg;
00017 
00018 
00019 #define STREAM_CBMAX    16
00020 
00021 typedef struct {
00022         void    *hdl;
00023         SOUNDCB cbfn;
00024 } CBTBL;
00025 
00026 typedef struct {
00027         SINT32  *buffer;
00028         SINT32  *ptr;
00029         UINT    samples;
00030         UINT    reserve;
00031         UINT    remain;
00032 #if defined(SUPPORT_WAVEREC)
00033         WAVEWR  rec;
00034 #endif
00035         CBTBL   *cbreg;
00036         CBTBL   cb[STREAM_CBMAX];
00037 } SNDSTREAM;
00038 
00039 static  SNDSTREAM       sndstream;
00040 
00041 static void streamreset(void) {
00042 
00043         SNDCSEC_ENTER;
00044         sndstream.ptr = sndstream.buffer;
00045         sndstream.remain = sndstream.samples + sndstream.reserve;
00046         sndstream.cbreg = sndstream.cb;
00047         SNDCSEC_LEAVE;
00048 }
00049 
00050 static void streamprepare(UINT samples) {
00051 
00052         CBTBL   *cb;
00053         UINT    count;
00054 
00055         count = min(sndstream.remain, samples);
00056         if (count) {
00057                 ZeroMemory(sndstream.ptr, count * 2 * sizeof(SINT32));
00058                 cb = sndstream.cb;
00059                 while(cb < sndstream.cbreg) {
00060                         cb->cbfn(cb->hdl, sndstream.ptr, count);
00061                         cb++;
00062                 }
00063                 sndstream.ptr += count * 2;
00064                 sndstream.remain -= count;
00065         }
00066 }
00067 
00068 // ---- wave rec
00069 
00070 BOOL sound_recstart(const OEMCHAR *filename) {
00071 
00072         WAVEWR  rec;
00073 
00074         sound_recstop();
00075         if (sndstream.buffer == NULL) {
00076                 return(FAILURE);
00077         }
00078         rec = wavewr_open(filename, soundcfg.rate, 16, 2);
00079         sndstream.rec = rec;
00080         if (rec) {
00081                 return(SUCCESS);
00082         }
00083         return(FAILURE);
00084 }
00085 
00086 void sound_recstop(void) {
00087 
00088         WAVEWR  rec;
00089 
00090         rec = sndstream.rec;
00091         sndstream.rec = NULL;
00092         wavewr_close(rec);
00093 }
00094 
00095 static void streamfilewrite(UINT samples) {
00096 
00097         CBTBL   *cb;
00098         UINT    count;
00099         SINT32  buf32[2*512];
00100         UINT8   buf[2*2*512];
00101         UINT    r;
00102         UINT    i;
00103         SINT32  samp;
00104 
00105         while(samples) {
00106                 count = min(samples, 512);
00107                 ZeroMemory(buf32, count * 2 * sizeof(SINT32));
00108                 cb = sndstream.cb;
00109                 while(cb < sndstream.cbreg) {
00110                         cb->cbfn(cb->hdl, buf32, count);
00111                         cb++;
00112                 }
00113                 r = min(sndstream.remain, count);
00114                 if (r) {
00115                         CopyMemory(sndstream.ptr, buf32, r * 2 * sizeof(SINT32));
00116                         sndstream.ptr += r * 2;
00117                         sndstream.remain -= r;
00118                 }
00119                 for (i=0; i<count*2; i++) {
00120                         samp = buf32[i];
00121                         if (samp > 32767) {
00122                                 samp = 32767;
00123                         }
00124                         else if (samp < -32768) {
00125                                 samp = -32768;
00126                         }
00127                         // little endianなので satuation_s16は使えない
00128                         buf[i*2+0] = (UINT8)samp;
00129                         buf[i*2+1] = (UINT8)(samp >> 8);
00130                 }
00131                 wavewr_write(sndstream.rec, buf, count * 4);
00132                 samples -= count;
00133         }
00134 }
00135 
00136 static void filltailsample(UINT count) {
00137 
00138         SINT32  *ptr;
00139         UINT    orgsize;
00140         SINT32  sampl;
00141         SINT32  sampr;
00142 
00143         count = min(sndstream.remain, count);
00144         if (count) {
00145                 ptr = sndstream.ptr;
00146                 orgsize = (ptr - sndstream.buffer) / 2;
00147                 if (orgsize == 0) {
00148                         sampl = 0;
00149                         sampr = 0;
00150                 }
00151                 else {
00152                         sampl = *(ptr - 2);
00153                         sampr = *(ptr - 1);
00154                 }
00155                 sndstream.ptr += count * 2;
00156                 sndstream.remain -= count;
00157                 do {
00158                         ptr[0] = sampl;
00159                         ptr[1] = sampr;
00160                         ptr += 2;
00161                 } while(--count);
00162         }
00163 }
00164 
00165 BOOL sound_create(UINT rate, UINT ms) {
00166 
00167         UINT    samples;
00168         UINT    reserve;
00169 
00170         ZeroMemory(&sndstream, sizeof(sndstream));
00171         switch(rate) {
00172                 case 11025:
00173                 case 22050:
00174                 case 44100:
00175                         break;
00176 
00177                 default:
00178                         return(FAILURE);
00179         }
00180         samples = soundmng_create(rate, ms);
00181         if (samples == 0) {
00182                 goto scre_err1;
00183         }
00184         soundmng_reset();
00185 
00186         soundcfg.rate = rate;
00187         sound_changeclock();
00188 
00189 #if defined(SOUNDRESERVE)
00190         reserve = rate * SOUNDRESERVE / 1000;
00191 #else
00192         reserve = 0;
00193 #endif
00194         sndstream.buffer = (SINT32 *)_MALLOC((samples + reserve) * 2 
00195                                                                                                 * sizeof(SINT32), "stream");
00196         if (sndstream.buffer == NULL) {
00197                 goto scre_err2;
00198         }
00199         sndstream.samples = samples;
00200         sndstream.reserve = reserve;
00201 
00202         SNDCSEC_INIT;
00203         streamreset();
00204         return(SUCCESS);
00205 
00206 scre_err2:
00207         soundmng_destroy();
00208 
00209 scre_err1:
00210         return(FAILURE);
00211 }
00212 #endif
00213 
00214 #if 0
00215 void sound_destroy(void) {
00216 
00217         if (sndstream.buffer) {
00218 #if defined(SUPPORT_WAVEREC)
00219                 sound_recstop();
00220 #endif
00221                 soundmng_stop();
00222                 streamreset();
00223                 soundmng_destroy();
00224                 SNDCSEC_TERM;
00225                 _MFREE(sndstream.buffer);
00226                 sndstream.buffer = NULL;
00227         }
00228 }
00229 #endif
00230 
00231 #if 0
00232 void sound_reset(void) {
00233 
00234         if (sndstream.buffer) {
00235                 soundmng_reset();
00236                 streamreset();
00237 //              soundcfg.lastclock = CPU_CLOCK;
00238                 beep_eventreset();
00239         }
00240 }
00241 #endif
00242 
00243 #if 0
00244 void sound_changeclock(void) {
00245 
00246         UINT32  clk;
00247         UINT    hz;
00248         UINT    hzmax;
00249 
00250         if (sndstream.buffer == NULL) {
00251                 return;
00252         }
00253 
00254         // とりあえず 25で割り切れる。
00255         clk = pccore.realclock / 25;
00256         hz = soundcfg.rate / 25;
00257 
00258         // で、クロック数に合せて調整。(64bit演算しろよな的)
00259         hzmax = (1 << (32 - 8)) / (clk >> 8);
00260         while(hzmax < hz) {
00261                 clk = (clk + 1) >> 1;
00262                 hz = (hz + 1) >> 1;
00263         }
00264         TRACEOUT(("hzbase/clockbase = %d/%d", hz, clk));
00265         soundcfg.hzbase = hz;
00266         soundcfg.clockbase = clk;
00267         soundcfg.minclock = 2 * clk / hz;
00268         soundcfg.lastclock = CPU_CLOCK;
00269 }
00270 #endif
00271 
00272 #if 0
00273 void sound_streamregist(void *hdl, SOUNDCB cbfn) {
00274 
00275         if (sndstream.buffer) {
00276                 if ((cbfn) &&
00277                         (sndstream.cbreg < (sndstream.cb + STREAM_CBMAX))) {
00278                         sndstream.cbreg->hdl = hdl;
00279                         sndstream.cbreg->cbfn = cbfn;
00280                         sndstream.cbreg++;
00281                 }
00282         }
00283 }
00284 #endif
00285 
00286 
00287 // ----
00288 
00289 #if 0
00290 void sound_sync(void) {
00291 
00292         UINT32  length;
00293 
00294         if (sndstream.buffer == NULL) {
00295                 return;
00296         }
00297 
00298         length = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK - soundcfg.lastclock;
00299         if (length < soundcfg.minclock) {
00300                 return;
00301         }
00302         length = (length * soundcfg.hzbase) / soundcfg.clockbase;
00303         if (length == 0) {
00304                 return;
00305         }
00306         SNDCSEC_ENTER;
00307 #if defined(SUPPORT_WAVEREC)
00308         if (sndstream.rec) {
00309                 streamfilewrite(length);
00310         }
00311         else
00312 #endif
00313                 streamprepare(length);
00314         soundcfg.lastclock += length * soundcfg.clockbase / soundcfg.hzbase;
00315         beep_eventreset();
00316         SNDCSEC_LEAVE;
00317 
00318         soundcfg.writecount += length;
00319         if (soundcfg.writecount >= 100) {
00320                 soundcfg.writecount = 0;
00321                 soundmng_sync();
00322         }
00323 }
00324 #endif
00325 
00326 #if 0
00327 static volatile int locks = 0;
00328 #endif
00329 
00330 #if 0
00331 const SINT32 *sound_pcmlock(void) {
00332 
00333 const SINT32 *ret;
00334 
00335         if (locks) {
00336                 TRACEOUT(("sound pcm lock: already locked"));
00337                 return(NULL);
00338         }
00339         locks++;
00340         ret = sndstream.buffer;
00341         if (ret) {
00342                 SNDCSEC_ENTER;
00343                 if (sndstream.remain > sndstream.reserve)
00344 #if defined(SUPPORT_WAVEREC)
00345                         if (sndstream.rec) {
00346                                 filltailsample(sndstream.remain - sndstream.reserve);
00347                         }
00348                         else
00349 #endif
00350                 {
00351                         streamprepare(sndstream.remain - sndstream.reserve);
00352                         soundcfg.lastclock = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK;
00353                         beep_eventreset();
00354                 }
00355         }
00356         else {
00357                 locks--;
00358         }
00359         return(ret);
00360 }
00361 #endif
00362 
00363 #if 0
00364 void sound_pcmunlock(const SINT32 *hdl) {
00365 
00366         int             leng;
00367 
00368         if (hdl) {
00369                 leng = sndstream.reserve - sndstream.remain;
00370                 if (leng > 0) {
00371                         CopyMemory(sndstream.buffer,
00372                                                 sndstream.buffer + (sndstream.samples * 2),
00373                                                                                                 leng * 2 * sizeof(SINT32));
00374                 }
00375                 sndstream.ptr = sndstream.buffer + (leng * 2);
00376                 sndstream.remain = sndstream.samples + sndstream.reserve - leng;
00377 //              sndstream.remain += sndstream.samples;
00378                 SNDCSEC_LEAVE;
00379                 locks--;
00380         }
00381 }
00382 #endif
00383 
00384 // ---- pcmmix
00385 
00386 BRESULT pcmmix_regist(PMIXDAT *dat, void *datptr, UINT datsize, UINT rate) {
00387 
00388         GETSND  gs;
00389         UINT8   tmp[256];
00390         UINT    size;
00391         UINT    r;
00392         SINT16  *buf;
00393 
00394         gs = getsnd_create(datptr, datsize);
00395         if (gs == NULL) {
00396                 goto pmr_err1;
00397         }
00398         if (getsnd_setmixproc(gs, rate, 1) != SUCCESS) {
00399                 goto pmr_err2;
00400         }
00401         size = 0;
00402         do {
00403                 r = getsnd_getpcmbyleng(gs, tmp, sizeof(tmp));
00404                 size += r;
00405         } while(r);
00406         getsnd_destroy(gs);
00407         if (size == 0) {
00408                 goto pmr_err1;
00409         }
00410 
00411         buf = (SINT16 *)_MALLOC(size, "PCM DATA");
00412         if (buf == NULL) {
00413                 goto pmr_err1;
00414         }
00415         gs = getsnd_create(datptr, datsize);
00416         if (gs == NULL) {
00417                 goto pmr_err1;
00418         }
00419         if (getsnd_setmixproc(gs, rate, 1) != SUCCESS) {
00420                 goto pmr_err2;
00421         }
00422         r = getsnd_getpcmbyleng(gs, buf, size);
00423         getsnd_destroy(gs);
00424         dat->sample = buf;
00425         dat->samples = r / 2;
00426         return(SUCCESS);
00427 
00428 pmr_err2:
00429         getsnd_destroy(gs);
00430 
00431 pmr_err1:
00432         return(FAILURE);
00433 }
00434 
00435 BRESULT pcmmix_regfile(PMIXDAT *dat, const OEMCHAR *fname, UINT rate) {
00436 
00437         FILEH   fh;
00438         UINT    size;
00439         UINT8   *ptr;
00440         BRESULT r;
00441 
00442         r = FAILURE;
00443         fh = file_open_rb(fname);
00444         if (fh == FILEH_INVALID) {
00445                 goto pmrf_err1;
00446         }
00447         size = file_getsize(fh);
00448         if (size == 0) {
00449                 goto pmrf_err2;
00450         }
00451         ptr = (UINT8 *)_MALLOC(size, fname);
00452         if (ptr == NULL) {
00453                 goto pmrf_err2;
00454         }
00455         file_read(fh, ptr, size);
00456         file_close(fh);
00457         r = pcmmix_regist(dat, ptr, size, rate);
00458         _MFREE(ptr);
00459         return(r);
00460 
00461 pmrf_err2:
00462         file_close(fh);
00463 
00464 pmrf_err1:
00465         return(FAILURE);
00466 }
00467 
00468 void SOUNDCALL pcmmix_getpcm(PCMMIX hdl, SINT32 *pcm, UINT count) {
00469 
00470         UINT32          bitmap;
00471         PMIXTRK         *t;
00472 const SINT16    *s;
00473         UINT            srem;
00474         SINT32          *d;
00475         UINT            drem;
00476         UINT            r;
00477         UINT            j;
00478         UINT            flag;
00479         SINT32          vol;
00480         SINT32          samp;
00481 
00482         if ((hdl->hdr.playing == 0) || (count == 0))  {
00483                 return;
00484         }
00485         t = hdl->trk;
00486         bitmap = 1;
00487         do {
00488                 if (hdl->hdr.playing & bitmap) {
00489                         s = t->pcm;
00490                         srem = t->remain;
00491                         d = pcm;
00492                         drem = count;
00493                         flag = t->flag;
00494                         vol = t->volume;
00495                         do {
00496                                 r = min(srem, drem);
00497                                 switch(flag & (PMIXFLAG_L | PMIXFLAG_R)) {
00498                                         case PMIXFLAG_L:
00499                                                 for (j=0; j<r; j++) {
00500                                                         d[j*2+0] += (s[j] * vol) >> 12;
00501                                                 }
00502                                                 break;
00503 
00504                                         case PMIXFLAG_R:
00505                                                 for (j=0; j<r; j++) {
00506                                                         d[j*2+1] += (s[j] * vol) >> 12;
00507                                                 }
00508                                                 break;
00509 
00510                                         case PMIXFLAG_L | PMIXFLAG_R:
00511                                                 for (j=0; j<r; j++) {
00512                                                         samp = (s[j] * vol) >> 12;
00513                                                         d[j*2+0] += samp;
00514                                                         d[j*2+1] += samp;
00515                                                 }
00516                                                 break;
00517                                 }
00518                                 s += r;
00519                                 d += r*2;
00520                                 srem -= r;
00521                                 if (srem == 0) {
00522                                         if (flag & PMIXFLAG_LOOP) {
00523                                                 s = t->data.sample;
00524                                                 srem = t->data.samples;
00525                                         }
00526                                         else {
00527                                                 hdl->hdr.playing &= ~bitmap;
00528                                                 break;
00529                                         }
00530                                 }
00531                                 drem -= r;
00532                         } while(drem);
00533                         t->pcm = s;
00534                         t->remain = srem;
00535                 }
00536                 t++;
00537                 bitmap <<= 1;
00538         } while(bitmap < hdl->hdr.enable);
00539 }
00540