| version 1.7, 2003/10/25 19:10:37 | version 1.17, 2004/07/03 17:25:39 | 
| Line 1 | Line 1 | 
 | #include        "compiler.h" | #include        "compiler.h" | 
 |  | #include        "wavefile.h" | 
 |  | #include        "dosio.h" | 
 | #include        "soundmng.h" | #include        "soundmng.h" | 
| #include        "i286.h" | #include        "cpucore.h" | 
 | #include        "pccore.h" | #include        "pccore.h" | 
 | #include        "iocore.h" | #include        "iocore.h" | 
 | #include        "sound.h" | #include        "sound.h" | 
 | #include        "sndcsec.h" | #include        "sndcsec.h" | 
 | #include        "beep.h" | #include        "beep.h" | 
 |  | #include        "getsnd.h" | 
 |  |  | 
 |  |  | 
 | SOUNDCFG        soundcfg; | SOUNDCFG        soundcfg; | 
| Line 24  typedef struct { | Line 27  typedef struct { | 
 | UINT    samples; | UINT    samples; | 
 | UINT    reserve; | UINT    reserve; | 
 | UINT    remain; | UINT    remain; | 
 |  | #if defined(SUPPORT_WAVEREC) | 
 |  | WAVEWR  rec; | 
 |  | #endif | 
 | CBTBL   *cbreg; | CBTBL   *cbreg; | 
 | CBTBL   cb[STREAM_CBMAX]; | CBTBL   cb[STREAM_CBMAX]; | 
 | } SNDSTREAM; | } SNDSTREAM; | 
| Line 37  static void streamreset(void) { | Line 43  static void streamreset(void) { | 
 | sndstream.ptr = sndstream.buffer; | sndstream.ptr = sndstream.buffer; | 
 | sndstream.remain = sndstream.samples + sndstream.reserve; | sndstream.remain = sndstream.samples + sndstream.reserve; | 
 | sndstream.cbreg = sndstream.cb; | sndstream.cbreg = sndstream.cb; | 
| SNDCSEC_TERM; | SNDCSEC_LEAVE; | 
 | } | } | 
 |  |  | 
 | static void streamprepare(UINT samples) { | static void streamprepare(UINT samples) { | 
| Line 59  static void streamprepare(UINT samples) | Line 65  static void streamprepare(UINT samples) | 
 | } | } | 
 |  |  | 
 |  |  | 
 |  | #if defined(SUPPORT_WAVEREC) | 
 |  | // ---- wave rec | 
 |  |  | 
 |  | BOOL sound_recstart(const char *filename) { | 
 |  |  | 
 |  | WAVEWR  rec; | 
 |  |  | 
 |  | sound_recstop(); | 
 |  | if (sndstream.buffer == NULL) { | 
 |  | return(FAILURE); | 
 |  | } | 
 |  | rec = wavewr_open(filename, soundcfg.rate, 16, 2); | 
 |  | sndstream.rec = rec; | 
 |  | if (rec) { | 
 |  | return(SUCCESS); | 
 |  | } | 
 |  | return(FAILURE); | 
 |  | } | 
 |  |  | 
 |  | void sound_recstop(void) { | 
 |  |  | 
 |  | WAVEWR  rec; | 
 |  |  | 
 |  | rec = sndstream.rec; | 
 |  | sndstream.rec = NULL; | 
 |  | wavewr_close(rec); | 
 |  | } | 
 |  |  | 
 |  | static void streamfilewrite(UINT samples) { | 
 |  |  | 
 |  | CBTBL   *cb; | 
 |  | UINT    count; | 
 |  | SINT32  buf32[2*512]; | 
 |  | BYTE    buf[2*2*512]; | 
 |  | UINT    r; | 
 |  | UINT    i; | 
 |  | SINT32  samp; | 
 |  |  | 
 |  | while(samples) { | 
 |  | count = min(samples, 512); | 
 |  | ZeroMemory(buf32, count * 2 * sizeof(SINT32)); | 
 |  | cb = sndstream.cb; | 
 |  | while(cb < sndstream.cbreg) { | 
 |  | cb->cbfn(cb->hdl, buf32, count); | 
 |  | cb++; | 
 |  | } | 
 |  | r = min(sndstream.remain, count); | 
 |  | if (r) { | 
 |  | CopyMemory(sndstream.ptr, buf32, r * 2 * sizeof(SINT32)); | 
 |  | sndstream.ptr += r * 2; | 
 |  | sndstream.remain -= r; | 
 |  | } | 
 |  | for (i=0; i<count*2; i++) { | 
 |  | samp = buf32[i]; | 
 |  | if (samp > 32767) { | 
 |  | samp = 32767; | 
 |  | } | 
 |  | else if (samp < -32768) { | 
 |  | samp = -32768; | 
 |  | } | 
 |  | // little endianなので satuation_s16は使えない | 
 |  | buf[i*2+0] = (BYTE)samp; | 
 |  | buf[i*2+1] = (BYTE)(samp >> 8); | 
 |  | } | 
 |  | wavewr_write(sndstream.rec, buf, count * 4); | 
 |  | samples -= count; | 
 |  | } | 
 |  | } | 
 |  |  | 
 |  | static void filltailsample(UINT count) { | 
 |  |  | 
 |  | SINT32  *ptr; | 
 |  | UINT    orgsize; | 
 |  | SINT32  sampl; | 
 |  | SINT32  sampr; | 
 |  |  | 
 |  | count = min(sndstream.remain, count); | 
 |  | if (count) { | 
 |  | ptr = sndstream.ptr; | 
 |  | orgsize = (ptr - sndstream.buffer) / 2; | 
 |  | if (orgsize == 0) { | 
 |  | sampl = 0; | 
 |  | sampr = 0; | 
 |  | } | 
 |  | else { | 
 |  | sampl = *(ptr - 2); | 
 |  | sampr = *(ptr - 1); | 
 |  | } | 
 |  | sndstream.ptr += count * 2; | 
 |  | sndstream.remain -= count; | 
 |  | do { | 
 |  | ptr[0] = sampl; | 
 |  | ptr[1] = sampr; | 
 |  | ptr += 2; | 
 |  | } while(--count); | 
 |  | } | 
 |  | } | 
 |  | #endif | 
 |  |  | 
 |  |  | 
 | // ---- | // ---- | 
 |  |  | 
 | BOOL sound_create(UINT rate, UINT ms) { | BOOL sound_create(UINT rate, UINT ms) { | 
| Line 112  scre_err1: | Line 218  scre_err1: | 
 | void sound_destroy(void) { | void sound_destroy(void) { | 
 |  |  | 
 | if (sndstream.buffer) { | if (sndstream.buffer) { | 
 |  | #if defined(SUPPORT_WAVEREC) | 
 |  | sound_recstop(); | 
 |  | #endif | 
 | soundmng_stop(); | soundmng_stop(); | 
 | streamreset(); | streamreset(); | 
 | soundmng_destroy(); | soundmng_destroy(); | 
| Line 126  void sound_reset(void) { | Line 235  void sound_reset(void) { | 
 | if (sndstream.buffer) { | if (sndstream.buffer) { | 
 | soundmng_reset(); | soundmng_reset(); | 
 | streamreset(); | streamreset(); | 
| soundcfg.lastclock = I286_CLOCK; | soundcfg.lastclock = CPU_CLOCK; | 
 | beep_eventreset(); | beep_eventreset(); | 
 | } | } | 
 | } | } | 
| Line 142  void sound_changeclock(void) { | Line 251  void sound_changeclock(void) { | 
 | } | } | 
 |  |  | 
 | // とりあえず 25で割り切れる。 | // とりあえず 25で割り切れる。 | 
| clock = pc.realclock / 25; | clock = pccore.realclock / 25; | 
 | hz = soundcfg.rate / 25; | hz = soundcfg.rate / 25; | 
 |  |  | 
 | // で、クロック数に合せて調整。(64bit演算しろよな的) | // で、クロック数に合せて調整。(64bit演算しろよな的) | 
| Line 151  void sound_changeclock(void) { | Line 260  void sound_changeclock(void) { | 
 | clock = (clock + 1) >> 1; | clock = (clock + 1) >> 1; | 
 | hz = (hz + 1) >> 1; | hz = (hz + 1) >> 1; | 
 | } | } | 
 |  | TRACEOUT(("hzbase/clockbase = %d/%d", hz, clock)); | 
 | soundcfg.hzbase = hz; | soundcfg.hzbase = hz; | 
 | soundcfg.clockbase = clock; | soundcfg.clockbase = clock; | 
 | soundcfg.minclock = 2 * clock / hz; | soundcfg.minclock = 2 * clock / hz; | 
| soundcfg.lastclock = I286_CLOCK; | soundcfg.lastclock = CPU_CLOCK; | 
 | } | } | 
 |  |  | 
 | void sound_streamregist(void *hdl, SOUNDCB cbfn) { | void sound_streamregist(void *hdl, SOUNDCB cbfn) { | 
| Line 180  void sound_sync(void) { | Line 290  void sound_sync(void) { | 
 | return; | return; | 
 | } | } | 
 |  |  | 
| length = I286_CLOCK + I286_BASECLOCK - I286_REMCLOCK - soundcfg.lastclock; | length = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK - soundcfg.lastclock; | 
 | if (length < soundcfg.minclock) { | if (length < soundcfg.minclock) { | 
 | return; | return; | 
 | } | } | 
| Line 189  void sound_sync(void) { | Line 299  void sound_sync(void) { | 
 | return; | return; | 
 | } | } | 
 | SNDCSEC_ENTER; | SNDCSEC_ENTER; | 
 |  | #if defined(SUPPORT_WAVEREC) | 
 |  | if (sndstream.rec) { | 
 |  | streamfilewrite(length); | 
 |  | } | 
 |  | else | 
 |  | #endif | 
 | streamprepare(length); | streamprepare(length); | 
 | soundcfg.lastclock += length * soundcfg.clockbase / soundcfg.hzbase; | soundcfg.lastclock += length * soundcfg.clockbase / soundcfg.hzbase; | 
 | beep_eventreset(); | beep_eventreset(); | 
| Line 208  const SINT32 *sound_pcmlock(void) { | Line 324  const SINT32 *sound_pcmlock(void) { | 
 | const SINT32 *ret; | const SINT32 *ret; | 
 |  |  | 
 | if (locks) { | if (locks) { | 
 |  | TRACEOUT(("sound pcm lock: already locked")); | 
 | return(NULL); | return(NULL); | 
 | } | } | 
 | locks++; | locks++; | 
 | ret = sndstream.buffer; | ret = sndstream.buffer; | 
 | if (ret) { | if (ret) { | 
 | SNDCSEC_ENTER; | SNDCSEC_ENTER; | 
| if (sndstream.remain > sndstream.reserve) { | if (sndstream.remain > sndstream.reserve) | 
|  | #if defined(SUPPORT_WAVEREC) | 
|  | if (sndstream.rec) { | 
|  | filltailsample(sndstream.remain - sndstream.reserve); | 
|  | } | 
|  | else | 
|  | #endif | 
|  | { | 
 | streamprepare(sndstream.remain - sndstream.reserve); | streamprepare(sndstream.remain - sndstream.reserve); | 
| soundcfg.lastclock = I286_CLOCK + I286_BASECLOCK - I286_REMCLOCK; | soundcfg.lastclock = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK; | 
 | beep_eventreset(); | beep_eventreset(); | 
 | } | } | 
 | } | } | 
 |  | else { | 
 |  | locks--; | 
 |  | } | 
 | return(ret); | return(ret); | 
 | } | } | 
 |  |  | 
| Line 242  void sound_pcmunlock(const SINT32 *hdl) | Line 369  void sound_pcmunlock(const SINT32 *hdl) | 
 | } | } | 
 | } | } | 
 |  |  | 
 |  |  | 
 |  | // ---- pcmmix | 
 |  |  | 
 |  | BOOL pcmmix_regist(PMIXDAT *dat, void *datptr, UINT datsize, UINT rate) { | 
 |  |  | 
 |  | GETSND  gs; | 
 |  | BYTE    tmp[256]; | 
 |  | UINT    size; | 
 |  | UINT    r; | 
 |  | SINT16  *buf; | 
 |  |  | 
 |  | gs = getsnd_create(datptr, datsize); | 
 |  | if (gs == NULL) { | 
 |  | goto pmr_err1; | 
 |  | } | 
 |  | if (getsnd_setmixproc(gs, rate, 1) != SUCCESS) { | 
 |  | goto pmr_err2; | 
 |  | } | 
 |  | size = 0; | 
 |  | do { | 
 |  | r = getsnd_getpcmbyleng(gs, tmp, sizeof(tmp)); | 
 |  | size += r; | 
 |  | } while(r); | 
 |  | getsnd_destroy(gs); | 
 |  | if (size == 0) { | 
 |  | goto pmr_err1; | 
 |  | } | 
 |  |  | 
 |  | buf = (SINT16 *)_MALLOC(size, "PCM DATA"); | 
 |  | if (buf == NULL) { | 
 |  | goto pmr_err1; | 
 |  | } | 
 |  | gs = getsnd_create(datptr, datsize); | 
 |  | if (gs == NULL) { | 
 |  | goto pmr_err1; | 
 |  | } | 
 |  | if (getsnd_setmixproc(gs, rate, 1) != SUCCESS) { | 
 |  | goto pmr_err2; | 
 |  | } | 
 |  | r = getsnd_getpcmbyleng(gs, buf, size); | 
 |  | getsnd_destroy(gs); | 
 |  | dat->sample = buf; | 
 |  | dat->samples = r / 2; | 
 |  | return(SUCCESS); | 
 |  |  | 
 |  | pmr_err2: | 
 |  | getsnd_destroy(gs); | 
 |  |  | 
 |  | pmr_err1: | 
 |  | return(FAILURE); | 
 |  | } | 
 |  |  | 
 |  | BOOL pcmmix_regfile(PMIXDAT *dat, const char *fname, UINT rate) { | 
 |  |  | 
 |  | FILEH   fh; | 
 |  | UINT    size; | 
 |  | BYTE    *ptr; | 
 |  | BOOL    r; | 
 |  |  | 
 |  | r = FAILURE; | 
 |  | fh = file_open_rb(fname); | 
 |  | if (fh == FILEH_INVALID) { | 
 |  | goto pmrf_err1; | 
 |  | } | 
 |  | size = file_getsize(fh); | 
 |  | if (size == 0) { | 
 |  | goto pmrf_err2; | 
 |  | } | 
 |  | ptr = (BYTE *)_MALLOC(size, fname); | 
 |  | if (ptr == NULL) { | 
 |  | goto pmrf_err2; | 
 |  | } | 
 |  | file_read(fh, ptr, size); | 
 |  | file_close(fh); | 
 |  | r = pcmmix_regist(dat, ptr, size, rate); | 
 |  | _MFREE(ptr); | 
 |  | return(r); | 
 |  |  | 
 |  | pmrf_err2: | 
 |  | file_close(fh); | 
 |  |  | 
 |  | pmrf_err1: | 
 |  | return(FAILURE); | 
 |  | } | 
 |  |  | 
 |  | void SOUNDCALL pcmmix_getpcm(PCMMIX hdl, SINT32 *pcm, UINT count) { | 
 |  |  | 
 |  | UINT32          bitmap; | 
 |  | PMIXTRK         *t; | 
 |  | const SINT16    *s; | 
 |  | UINT            srem; | 
 |  | SINT32          *d; | 
 |  | UINT            drem; | 
 |  | UINT            r; | 
 |  | UINT            j; | 
 |  | UINT            flag; | 
 |  | SINT32          vol; | 
 |  | SINT32          samp; | 
 |  |  | 
 |  | if ((hdl->hdr.playing == 0) || (count == 0))  { | 
 |  | return; | 
 |  | } | 
 |  | t = hdl->trk; | 
 |  | bitmap = 1; | 
 |  | do { | 
 |  | if (hdl->hdr.playing & bitmap) { | 
 |  | s = t->pcm; | 
 |  | srem = t->remain; | 
 |  | d = pcm; | 
 |  | drem = count; | 
 |  | flag = t->flag; | 
 |  | vol = t->volume; | 
 |  | do { | 
 |  | r = min(srem, drem); | 
 |  | switch(flag & (PMIXFLAG_L | PMIXFLAG_R)) { | 
 |  | case PMIXFLAG_L: | 
 |  | for (j=0; j<r; j++) { | 
 |  | d[j*2+0] += (s[j] * vol) >> 12; | 
 |  | } | 
 |  | break; | 
 |  |  | 
 |  | case PMIXFLAG_R: | 
 |  | for (j=0; j<r; j++) { | 
 |  | d[j*2+1] += (s[j] * vol) >> 12; | 
 |  | } | 
 |  | break; | 
 |  |  | 
 |  | case PMIXFLAG_L | PMIXFLAG_R: | 
 |  | for (j=0; j<r; j++) { | 
 |  | samp = (s[j] * vol) >> 12; | 
 |  | d[j*2+0] += samp; | 
 |  | d[j*2+1] += samp; | 
 |  | } | 
 |  | break; | 
 |  | } | 
 |  | s += r; | 
 |  | d += r*2; | 
 |  | srem -= r; | 
 |  | if (srem == 0) { | 
 |  | if (flag & PMIXFLAG_LOOP) { | 
 |  | s = t->data.sample; | 
 |  | srem = t->data.samples; | 
 |  | } | 
 |  | else { | 
 |  | hdl->hdr.playing &= ~bitmap; | 
 |  | break; | 
 |  | } | 
 |  | } | 
 |  | drem -= r; | 
 |  | } while(drem); | 
 |  | t->pcm = s; | 
 |  | t->remain = srem; | 
 |  | } | 
 |  | t++; | 
 |  | bitmap <<= 1; | 
 |  | } while(bitmap < hdl->hdr.enable); | 
 |  | } | 
 |  |  |