Annotation of generator/main/gensound.c, revision 1.1.1.3

1.1       root        1: /* Generator is (c) James Ponder, 1997-2001 http://www.squish.net/generator/ */
                      2: 
1.1.1.2   root        3: #include <stdlib.h>
1.1       root        4: 
                      5: #include "generator.h"
                      6: #include "gensound.h"
1.1.1.2   root        7: #include "gensoundp.h"
1.1       root        8: #include "vdp.h"
                      9: #include "ui.h"
1.1.1.2   root       10: #include "sn76496.h"
1.1       root       11: 
                     12: #ifdef JFM
                     13: #  include "jfm.h"
                     14: #else
                     15: #  include "support.h"
                     16: #  include "fm.h"
                     17: #endif
                     18: 
                     19: /*** variables externed ***/
                     20: 
1.1.1.2   root       21: int sound_debug = 0;            /* debug mode */
                     22: int sound_feedback = 0;         /* -1, running out of sound
                     23:                                    +0, lots of sound, do something */
                     24: unsigned int sound_minfields = 5;       /* min fields to try to buffer */
                     25: unsigned int sound_maxfields = 10;      /* max fields before blocking */
1.1.1.3 ! root       26: unsigned int sound_speed = SOUND_SAMPLERATE;    /* sample rate */
1.1.1.2   root       27: unsigned int sound_sampsperfield;       /* samples per field */
                     28: unsigned int sound_threshold;   /* samples in buffer aiming for */
1.1       root       29: uint8 sound_regs1[256];
                     30: uint8 sound_regs2[256];
                     31: uint8 sound_address1 = 0;
                     32: uint8 sound_address2 = 0;
                     33: uint8 sound_keys[8];
1.1.1.3 ! root       34: int sound_logsample = 0;        /* sample to log or -1 if none */
        !            35: unsigned int sound_on = 1;      /* sound enabled */
        !            36: unsigned int sound_psg = 1;     /* psg enabled */
        !            37: unsigned int sound_fm = 1;      /* fm enabled */
1.1       root       38: 
1.1.1.2   root       39: /* pal is lowest framerate */
                     40: uint16 sound_soundbuf[2][SOUND_MAXRATE / 50];
1.1       root       41: 
                     42: /*** forward references ***/
                     43: 
1.1.1.3 ! root       44: static void sound_process(void);
        !            45: static void sound_writetolog(unsigned char c);
        !            46: 
1.1       root       47: /*** file scoped variables ***/
                     48: 
                     49: static int sound_active = 0;
1.1.1.3 ! root       50: static uint8 *sound_logdata;    /* log data */
        !            51: static unsigned int sound_logdata_size; /* sound_logdata size */
        !            52: static unsigned int sound_logdata_p;    /* current log data offset */
        !            53: static unsigned int sound_fieldhassamples;      /* flag if field has samples */
1.1       root       54: 
                     55: #ifdef JFM
1.1.1.2   root       56: static t_jfm_ctx *sound_ctx;
1.1       root       57: #endif
                     58: 
                     59: /*** sound_init - initialise this sub-unit ***/
                     60: 
                     61: int sound_init(void)
                     62: {
                     63:   int ret;
                     64: 
1.1.1.2   root       65:   /* The sound_minfields parameter specifies how many fields worth of sound we
                     66:      should try and keep around (a display field is 1/50th or 1/60th of a
                     67:      second) - generator works by trying to keep sound_minfields number of
                     68:      fields worth of sound around, and drops plotting frames to keep up on slow
                     69:      machines */
                     70: 
                     71:   sound_sampsperfield = sound_speed / vdp_framerate;
                     72:   sound_threshold = sound_sampsperfield * sound_minfields;
                     73: 
1.1       root       74:   ret = sound_start();
                     75:   if (ret)
                     76:     return ret;
                     77: #ifdef JFM
1.1.1.2   root       78:   if ((sound_ctx = jfm_init(0, 2612, vdp_clock / 7, sound_speed,
                     79:                             NULL, NULL)) == NULL) {
                     80: #else
                     81:   if (YM2612Init(1, vdp_clock / 7, sound_speed, NULL, NULL)) {
                     82: #endif
                     83:     LOG_VERBOSE(("YM2612 failed init"));
                     84:     sound_stop();
                     85:     return 1;
                     86:   }
                     87:   if (SN76496Init(0, vdp_clock / 15, 0, sound_speed)) {
                     88:     LOG_VERBOSE(("SN76496 failed init"));
                     89:     sound_stop();
                     90: #ifdef JFM
                     91:     jfm_final(sound_ctx);
1.1       root       92: #else
1.1.1.2   root       93:     YM2612Shutdown();
1.1       root       94: #endif
                     95:     return 1;
                     96:   }
1.1.1.3 ! root       97:   if (sound_logdata)
        !            98:     free(sound_logdata);
        !            99:   sound_logdata_size = 8192;
        !           100:   sound_logdata = malloc(sound_logdata_size);
        !           101:   if (!sound_logdata)
        !           102:     ui_err("out of memory");
1.1       root      103:   LOG_VERBOSE(("YM2612 Initialised @ sample rate %d", sound_speed));
                    104:   return 0;
                    105: }
                    106: 
                    107: /*** sound_final - finalise this sub-unit ***/
                    108: 
                    109: void sound_final(void)
                    110: {
                    111:   sound_stop();
                    112: #ifdef JFM
                    113:   jfm_final(sound_ctx);
                    114: #else
                    115:   YM2612Shutdown();
                    116: #endif
                    117: }
                    118: 
1.1.1.2   root      119: /*** sound_start - start sound ***/
1.1       root      120: 
                    121: int sound_start(void)
                    122: {
                    123:   if (sound_active)
                    124:     sound_stop();
1.1.1.2   root      125:   LOG_VERBOSE(("Starting sound..."));
                    126:   if (soundp_start() == -1) {
                    127:     LOG_VERBOSE(("Failed to start sound hardware"));
                    128:     return -1;
1.1       root      129:   }
                    130:   sound_active = 1;
1.1.1.2   root      131:   LOG_VERBOSE(("Started sound."));
1.1       root      132:   return 0;
                    133: }
1.1.1.2   root      134: 
1.1       root      135: /*** sound_stop - stop sound ***/
                    136: 
                    137: void sound_stop(void)
                    138: {
                    139:   if (!sound_active)
                    140:     return;
                    141:   LOG_VERBOSE(("Stopping sound..."));
1.1.1.2   root      142:   soundp_stop();
1.1       root      143:   sound_active = 0;
                    144:   LOG_VERBOSE(("Stopped sound."));
                    145: }
1.1.1.2   root      146: 
1.1       root      147: /*** sound_reset - reset sound sub-unit ***/
                    148: 
                    149: int sound_reset(void)
                    150: {
                    151:   sound_final();
                    152:   return sound_init();
                    153: }
                    154: 
1.1.1.3 ! root      155: /*** sound_startfield - start of frame ***/
        !           156: 
        !           157: void sound_startfield(void)
        !           158: {
        !           159:   sound_logdata_p = 0;
        !           160:   if (gen_musiclog == musiclog_gnm) {
        !           161:     sound_writetolog(0);
        !           162:     sound_writetolog((vdp_totlines >> 8) & 0xff);
        !           163:     sound_writetolog(vdp_totlines & 0xff);
        !           164:     sound_fieldhassamples = 0;
        !           165:   }
        !           166: }
1.1       root      167: /*** sound_endfield - end frame and output sound ***/
                    168: 
                    169: void sound_endfield(void)
                    170: {
1.1.1.2   root      171:   int pending;
1.1.1.3 ! root      172:   uint8 *p, *o;
        !           173: 
        !           174:   if (gen_musiclog) {
        !           175:     if (gen_musiclog == musiclog_gym) {
        !           176:       /* GYM format ends a field with a 0 byte */
        !           177:       sound_writetolog(0);
        !           178:     } else {
        !           179:       /* GNM format requires sifting through the data */
        !           180:       if (!sound_fieldhassamples) {
        !           181:         /* we're only removing data, so we're going to write to the buffer
        !           182:            we're reading from */
        !           183:         o = sound_logdata + 3;
        !           184:         for (p = sound_logdata + 3;
        !           185:              p < (sound_logdata + sound_logdata_p); p++) {
        !           186:           if ((*p & 0xF0) != 0x00 || *p == 4)
        !           187:             ui_err("assertion of no samples failed");
        !           188:           switch (*p) {
        !           189:           case 0:
        !           190:             ui_err("field marker in middle of field data");
        !           191:           case 1:
        !           192:           case 2:
        !           193:             /* FM data, copy 2 and two bytes to output */
        !           194:             *o++ = *p++;
        !           195:             *o++ = *p++;
        !           196:             *o++ = *p;
        !           197:             break;
        !           198:           case 3:
        !           199:             /* PSG data, copy 3 and one byte to output */
        !           200:             *o++ = *p++;
        !           201:             *o++ = *p;
        !           202:             break;
        !           203:           case 5:
        !           204:             /* these are the bytes we're trying to strip */
        !           205:             /* do nothing */
        !           206:             break;
        !           207:           default:
        !           208:             ui_err("invalid data in sound log buffer");
        !           209:           }
        !           210:         }
        !           211:         /* update new end of buffer */
        !           212:         sound_logdata_p = o - sound_logdata;
        !           213:         sound_logdata[1] = 0; /* high byte number of samples */
        !           214:         sound_logdata[2] = 0; /* low byte number of samples */
        !           215:       }
        !           216:     }
        !           217:     /* write data */
        !           218:     ui_musiclog(sound_logdata, sound_logdata_p);
        !           219:     /* sound_startfield resets everything */
        !           220:   }
        !           221: 
        !           222:   if (!sound_on) {
        !           223:     /* sound is turned off - let generator continue */
        !           224:     sound_feedback = 0;
        !           225:     return;
        !           226:   }
1.1.1.2   root      227: 
                    228:   /* work out feedback from sound system */
                    229: 
                    230:   if ((pending = soundp_samplesbuffered()) == -1)
                    231:     ui_err("Failed to read pending bytes in output sound buffer");
                    232:   if ((unsigned int)pending < sound_threshold)
1.1       root      233:     sound_feedback = -1;
                    234:   else
                    235:     sound_feedback = 0;
1.1.1.2   root      236: 
1.1       root      237:   if (sound_debug) {
1.1.1.2   root      238:     LOG_VERBOSE(("End of field - sound system says %d bytes buffered",
                    239:                  pending));
                    240:     LOG_VERBOSE(("Threshold %d, therefore feedback = %d ", sound_threshold,
                    241:                  sound_feedback));
1.1       root      242:   }
1.1.1.2   root      243:   soundp_output(sound_soundbuf[0], sound_soundbuf[1], sound_sampsperfield);
1.1       root      244: }
                    245: 
                    246: /*** sound_ym2612fetch - fetch byte from ym2612 chip ***/
                    247: 
                    248: uint8 sound_ym2612fetch(uint8 addr)
                    249: {
                    250: #ifdef JFM
                    251:   return jfm_read(sound_ctx, addr);
                    252: #else
                    253:   return YM2612Read(0, addr);
                    254: #endif
                    255: }
                    256: 
                    257: /*** sound_ym2612store - store a byte to the ym2612 chip ***/
                    258: 
                    259: void sound_ym2612store(uint8 addr, uint8 data)
                    260: {
                    261:   switch (addr) {
                    262:   case 0:
                    263:     sound_address1 = data;
                    264:     break;
                    265:   case 1:
                    266:     if (sound_address1 == 0x2a) {
1.1.1.3 ! root      267:       /* sample data */
1.1       root      268:       sound_keys[7] = 0;
1.1.1.3 ! root      269:       sound_logsample = data;
        !           270:     } else {
        !           271:       if (gen_musiclog != musiclog_off) {
        !           272:         /* GYM and GNM */
        !           273:         sound_writetolog(1);
        !           274:         sound_writetolog(sound_address1);
        !           275:         sound_writetolog(data);
        !           276:       }
1.1       root      277:     }
1.1.1.3 ! root      278:     if (sound_address1 == 0x28 && (data & 3) != 3)
        !           279:       sound_keys[data & 7] = data >> 4;
1.1       root      280:     if (sound_address1 == 0x2b)
                    281:       sound_keys[7] = data & 0x80 ? 0xf : 0;
                    282:     sound_regs1[sound_address1] = data;
                    283:     break;
                    284:   case 2:
1.1.1.3 ! root      285:     if (gen_musiclog != musiclog_off) {
        !           286:       /* GYM and GNM */
        !           287:       sound_writetolog(2);
        !           288:       sound_writetolog(sound_address2);
        !           289:       sound_writetolog(data);
        !           290:     }
1.1       root      291:     sound_address2 = data;
                    292:     break;
                    293:   case 3:
                    294:     sound_regs2[sound_address2] = data;
                    295:     break;
                    296:   }
                    297: #ifdef JFM
                    298:   jfm_write(sound_ctx, addr, data);
                    299: #else
                    300:   YM2612Write(0, addr, data);
                    301: #endif
                    302: }
                    303: 
1.1.1.2   root      304: /*** sound_sn76496store - store a byte to the sn76496 chip ***/
                    305: 
                    306: void sound_sn76496store(uint8 data)
                    307: {
1.1.1.3 ! root      308:   if (gen_musiclog != musiclog_off) {
        !           309:     /* GYM and GNM */
        !           310:     sound_writetolog(3);
        !           311:     sound_writetolog(data);
        !           312:   }
1.1.1.2   root      313:   SN76496Write(0, data);
                    314: }
                    315: 
                    316: /*** sound_genreset - reset genesis sound ***/
                    317: 
                    318: void sound_genreset(void)
                    319: {
                    320: #ifdef JFM
                    321:   jfm_reset(sound_ctx);
                    322: #else
                    323:   YM2612ResetChip(0);
                    324: #endif
                    325: }
                    326: 
1.1.1.3 ! root      327: /*** sound_line - called at end of line ***/
        !           328: 
        !           329: void sound_line(void)
        !           330: {
        !           331:   if (gen_musiclog == musiclog_gnm) {
        !           332:     /* GNM log */
        !           333:     if (sound_logsample == -1) {
        !           334:       sound_writetolog(5);
        !           335:     } else {
        !           336:       if ((sound_logsample & 0xF0) == 0) {
        !           337:         sound_writetolog(4);
        !           338:       }
        !           339:       sound_writetolog(sound_logsample);
        !           340:       sound_logsample = -1;
        !           341:       /* mark the fact that we have encountered a sample this field */
        !           342:       sound_fieldhassamples = 1;
        !           343:     }
        !           344:   }
        !           345:   sound_process();
        !           346: }
        !           347: 
1.1.1.2   root      348: /*** sound_process - process sound ***/
                    349: 
1.1.1.3 ! root      350: static void sound_process(void)
1.1.1.2   root      351: {
                    352:   static sint16 *tbuf[2];
                    353:   int s1 = (sound_sampsperfield * (vdp_line)) / vdp_totlines;
                    354:   int s2 = (sound_sampsperfield * (vdp_line + 1)) / vdp_totlines;
                    355:   /* pal is lowest framerate */
                    356:   uint16 sn76496buf[SOUND_MAXRATE / 50];        /* far too much but who cares */
                    357:   unsigned int samples = s2 - s1;
                    358:   unsigned int i;
                    359: 
                    360:   tbuf[0] = sound_soundbuf[0] + s1;
                    361:   tbuf[1] = sound_soundbuf[1] + s1;
                    362: 
                    363:   if (s2 > s1) {
1.1.1.3 ! root      364:     if (sound_fm)
1.1.1.2   root      365: #ifdef JFM
1.1.1.3 ! root      366:       jfm_update(sound_ctx, (void **)tbuf, samples1);
1.1.1.2   root      367: #else
1.1.1.3 ! root      368:       YM2612UpdateOne(0, tbuf, samples);
1.1.1.2   root      369: #endif
1.1.1.3 ! root      370:     if (sound_psg)
        !           371:       SN76496Update(0, sn76496buf, samples);
1.1.1.2   root      372: 
                    373:     /* SN76496 outputs sound in range -0x4000 to 0x3fff
                    374:        YM2612 ouputs sound in range -0x8000 to 0x7fff - therefore
                    375:        we take 3/4 of the YM2612 and add half the SN76496 */
1.1.1.3 ! root      376: 
        !           377:     if (sound_fm && sound_psg) {
        !           378:       for (i = 0; i < samples; i++) {
        !           379:         sint16 snsample = sn76496buf[i] - 0x4000;
        !           380:         sint32 l = (tbuf[0][i] * 3) >> 2; /* left channel */
        !           381:         sint32 r = (tbuf[1][i] * 3) >> 2; /* right channel */
        !           382:         l += snsample >> 1;
        !           383:         r += snsample >> 1;
        !           384:         tbuf[0][i] = l;
        !           385:         tbuf[1][i] = r;
        !           386:       }
        !           387:     } else if (!sound_fm && !sound_psg) {
        !           388:       /* no sound */
        !           389:       memset(tbuf[0], 0, 2 * samples);
        !           390:       memset(tbuf[1], 0, 2 * samples);
        !           391:     } else if (sound_fm) {
        !           392:       /* fm only */
        !           393:       for (i = 0; i < samples; i++) {
        !           394:         sint32 l = (tbuf[0][i] * 3) >> 2; /* left channel */
        !           395:         sint32 r = (tbuf[1][i] * 3) >> 2; /* right channel */
        !           396:         tbuf[0][i] = l;
        !           397:         tbuf[1][i] = r;
        !           398:       }
        !           399:     } else {
        !           400:       /* psg only */
        !           401:       for (i = 0; i < samples; i++) {
        !           402:         sint16 snsample = sn76496buf[i] - 0x4000;
        !           403:         tbuf[0][i] = snsample >> 1;
        !           404:         tbuf[1][i] = snsample >> 1;
        !           405:       }
1.1.1.2   root      406:     }
                    407:   }
                    408: }
1.1.1.3 ! root      409: 
        !           410: /*** sound_writetolog - write to music log buffer ***/
        !           411: 
        !           412: static void sound_writetolog(unsigned char c)
        !           413: {
        !           414:   /* write the byte to the self-expanding memory log - when we have the whole
        !           415:      field's worth of data we then sift through the data (see the
        !           416:      documentation on the GNM log format) and then pass it to ui_writelog */
        !           417: 
        !           418:   sound_logdata[sound_logdata_p++] = c;
        !           419:   if (sound_logdata_p >= sound_logdata_size) {
        !           420:     LOG_VERBOSE(("sound log buffer limit increased"));
        !           421:     sound_logdata_size+= 8192;
        !           422:     sound_logdata = realloc(sound_logdata, sound_logdata_size);
        !           423:     if (!sound_logdata)
        !           424:       ui_err("out of memory");
        !           425:   }
        !           426: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.