Annotation of generator/src/gensound.c, revision 1.1.1.2

1.1.1.2 ! root        1: /* Generator is (c) James Ponder, 1997-2001 http://www.squish.net/generator/ */
1.1       root        2: 
                      3: #include <sys/types.h>
                      4: #include <sys/stat.h>
1.1.1.2 ! root        5: #include <sys/ioctl.h>
        !             6: #include <sys/time.h>
        !             7: #include <string.h>
        !             8: #include <stdio.h>
1.1       root        9: #include <fcntl.h>
                     10: #include <errno.h>
                     11: #include <unistd.h>
                     12: #include <math.h>
                     13: 
                     14: #include "generator.h"
                     15: #include "gensound.h"
                     16: #include "vdp.h"
                     17: #include "ui.h"
                     18: 
                     19: #ifdef JFM
                     20: #  include "jfm.h"
                     21: #else
                     22: #  include "support.h"
                     23: #  include "fm.h"
                     24: #endif
                     25: 
                     26: #include <sys/soundcard.h>
                     27: 
                     28: /*** variables externed ***/
                     29: 
1.1.1.2 ! root       30: int sound_feedback = 0;           /* -1, running out of sound
        !            31:                                      +0, lots of sound, do something */
        !            32: int sound_debug = 0;              /* 0 for no debug, 1 for debug */
        !            33: int sound_minfields = 5;          /* minimum fields to try to keep buffered */
        !            34: int sound_maxfields = 10;         /* max fields to buffer before blocking */
        !            35: uint8 sound_regs1[256];
        !            36: uint8 sound_regs2[256];
        !            37: uint8 sound_address1 = 0;
        !            38: uint8 sound_address2 = 0;
        !            39: uint8 sound_keys[8];
1.1       root       40: 
                     41: /* SN76489 snd_cpu; */
                     42: 
                     43: /*** forward references ***/
                     44: 
                     45: /* void snd_sndout(int chan, int freq, int vol); */
                     46: 
                     47: /*** file scoped variables ***/
                     48: 
                     49: #define SOUND_MAXRATE 44100
                     50: #define SOUND_FRAGMENTS 12
                     51: 
                     52: static unsigned int sound_sampsperfield = 0;
1.1.1.2 ! root       53: static int sound_dev = -1;
1.1       root       54: /* static int sound_dump = 0; */
                     55: static uint16 soundbuf[2][SOUND_MAXRATE/50]; /* pal is lowest framerate */
1.1.1.2 ! root       56: static int sound_active = 0;
1.1       root       57: static int sound_format;
                     58: static int sound_stereo;
                     59: static int sound_speed;
                     60: static int sound_frag;
                     61: static int sound_fragsize;
1.1.1.2 ! root       62: static unsigned int sound_threshold; /* bytes in buffer we're trying for */
1.1       root       63: 
                     64: #ifdef JFM
                     65:   static t_jfm_ctx *sound_ctx;
                     66: #endif
                     67: 
                     68: /*** sound_init - initialise this sub-unit ***/
                     69: 
                     70: int sound_init(void)
                     71: {
                     72:   audio_buf_info sound_info;
                     73: 
1.1.1.2 ! root       74:   /* The threshold parameter specifies how many fields worth of sound we
        !            75:      should try and keep around (a display field is 1/50th or 1/60th of a
        !            76:      second) - generator works by trying to keep threshold number of fields
        !            77:      worth of sound around, and drops plotting frames to keep up on slow
        !            78:      machines */
        !            79: 
        !            80:   if (sound_active)
        !            81:     sound_final();
        !            82:   LOG_VERBOSE(("Initialising sound..."));
1.1       root       83:   sound_sampsperfield = SOUND_SAMPLERATE / vdp_framerate;
                     84: 
                     85:   /* sound_dump = open("/tmp/sound_dump", O_CREAT|O_WRONLY|O_TRUNC); */
                     86: 
                     87:   if ((sound_dev = open(SOUND_DEVICE, O_WRONLY, 0)) == -1) {
                     88:     LOG_CRITICAL(("open " SOUND_DEVICE " failed: %s", strerror(errno)));
                     89:     return 1;
                     90:   }
1.1.1.2 ! root       91:   sound_frag = (sound_maxfields<<16 |
1.1       root       92:                (int)(ceil(log10(sound_sampsperfield*4)/log10(2))));
                     93:   if (ioctl(sound_dev, SNDCTL_DSP_SETFRAGMENT, &sound_frag) == -1) {
                     94:     LOG_CRITICAL(("Error setting fragment size: %s", strerror(errno)));
1.1.1.2 ! root       95:     close(sound_dev);
1.1       root       96:     return 1;
                     97:   }
                     98:   sound_format = AFMT_S16_LE;
                     99:   if (ioctl(sound_dev, SNDCTL_DSP_SETFMT, &sound_format) == -1) {
                    100:     LOG_CRITICAL(("Error setting sound device format: %s", strerror(errno)));
1.1.1.2 ! root      101:     close(sound_dev);
1.1       root      102:     return 1;
                    103:   }
                    104:   if (sound_format != AFMT_S16_LE && sound_format != AFMT_S16_BE) {
                    105:     LOG_CRITICAL(("Sound device format not supported (must be 16 bit)"));
1.1.1.2 ! root      106:     close(sound_dev);
1.1       root      107:     return 1;
                    108:   }
                    109:   sound_stereo = 1;
                    110:   if (ioctl(sound_dev, SNDCTL_DSP_STEREO, &sound_stereo) == -1) {
                    111:     LOG_CRITICAL(("Error setting stereo: %s", strerror(errno)));
1.1.1.2 ! root      112:     close(sound_dev);
1.1       root      113:     return 1;
                    114:   }
                    115:   if (sound_stereo != 1) {
                    116:     LOG_CRITICAL(("Sound device does not support stereo"));
1.1.1.2 ! root      117:     close(sound_dev);
1.1       root      118:     return 1;
                    119:   }
                    120:   sound_speed = SOUND_SAMPLERATE;
                    121:   if (ioctl(sound_dev, SNDCTL_DSP_SPEED, &sound_speed) == -1) {
                    122:     LOG_CRITICAL(("Error setting sound speed: %s",  strerror(errno)));
1.1.1.2 ! root      123:     close(sound_dev);
1.1       root      124:     return 1;
                    125:   }
                    126:   if (sound_speed != SOUND_SAMPLERATE) {
                    127:     if (abs(sound_speed-SOUND_SAMPLERATE) > 50) {
                    128:       LOG_NORMAL(("Warning: Sample rate not exactly 22050"));
                    129:     } else {
                    130:       LOG_CRITICAL(("Sound device does not support sample rate %d "
                    131:                    "(returned %d)", SOUND_SAMPLERATE, sound_speed));
1.1.1.2 ! root      132:       close(sound_dev);
1.1       root      133:       return 1;
                    134:     }
                    135:   }
                    136:   if (ioctl(sound_dev, SNDCTL_DSP_GETOSPACE, &sound_info) == -1) {
                    137:     LOG_CRITICAL(("Error getting output space info", strerror(errno)));
1.1.1.2 ! root      138:     close(sound_dev);
1.1       root      139:     return 1;
                    140:   }
1.1.1.2 ! root      141:   LOG_VERBOSE(("Total allocated fragments = %d (requested %d)",
        !           142:               sound_info.fragstotal, sound_maxfields));
        !           143:   LOG_VERBOSE(("Fragment size = %d (requested %d)", sound_info.fragsize,
        !           144:               sound_sampsperfield*4));
        !           145:   LOG_VERBOSE(("Bytes free in buffer = %d", sound_info.bytes));
        !           146:   sound_threshold = sound_sampsperfield*4*sound_minfields;
        !           147:   LOG_VERBOSE(("Theshold = %d (%d fields of sound === %dms latency)",
        !           148:               sound_threshold, sound_minfields,
        !           149:               (int)(1000*(float)sound_minfields/(float)vdp_framerate)));
1.1       root      150:   if ((signed)sound_threshold >= sound_info.bytes) {
                    151:     LOG_CRITICAL(("Threshold exceeds bytes free in buffer"));
1.1.1.2 ! root      152:     close(sound_dev);
1.1       root      153:     return 1;
                    154:   }
                    155: #ifdef JFM
                    156:   if ((sound_ctx = jfm_init(0, 2612, vdp_clock/7, sound_speed,
1.1.1.2 ! root      157:                            NULL, NULL)) == NULL) {
1.1       root      158: #else
1.1.1.2 ! root      159:   if (YM2612Init(1, vdp_clock/7, sound_speed, NULL, NULL)) {
1.1       root      160: #endif
1.1.1.2 ! root      161:     close(sound_dev);
1.1       root      162:     return 1;
1.1.1.2 ! root      163:   }
        !           164:   LOG_VERBOSE(("YM2612 Initialised @ sample rate %d", sound_speed));
        !           165:   sound_active = 1;
1.1       root      166:   return 0;
                    167: }
                    168: 
                    169: /*** sound_final - finalise this sub-unit ***/
                    170: 
                    171: void sound_final(void)
                    172: {
1.1.1.2 ! root      173:   if (!sound_active)
        !           174:     return;
        !           175:   LOG_VERBOSE(("Finalising sound..."));
1.1       root      176: #ifdef JFM
                    177:   jfm_final(sound_ctx);
                    178: #else
                    179:   YM2612Shutdown();
                    180: #endif
1.1.1.2 ! root      181:   if (sound_dev != -1)
1.1       root      182:     close(sound_dev);
1.1.1.2 ! root      183:   sound_dev = -1;
        !           184:   sound_active = 0;
        !           185:   LOG_VERBOSE(("Finalised sound."));
1.1       root      186: }
                    187: 
                    188: /*** sound_reset - reset sound sub-unit ***/
                    189: 
                    190: int sound_reset(void)
                    191: {
                    192:   sound_final();
                    193:   return sound_init();
                    194: }
                    195: 
                    196: /*** sound_genreset - reset genesis sound ***/
                    197: 
                    198: void sound_genreset(void)
                    199: {
                    200: #ifdef JFM
                    201:   jfm_reset(sound_ctx);
                    202: #else
                    203:   YM2612ResetChip(0);
                    204: #endif
                    205: }
                    206: 
                    207: /*** sound_process - process sound ***/
                    208: 
                    209: void sound_process(void)
                    210: {
                    211:   static uint16 *tbuf[2];
                    212:   int s1 = (sound_sampsperfield*(vdp_line))/vdp_totlines;
                    213:   int s2 = (sound_sampsperfield*(vdp_line+1))/vdp_totlines;
                    214: 
                    215:   tbuf[0] = soundbuf[0] + s1;
                    216:   tbuf[1] = soundbuf[1] + s1;
                    217: 
                    218:   /* printf("YM2612: %d to %d\n", s1, s2); */
                    219: 
                    220:   if (s2 > s1)
                    221: #ifdef JFM
                    222:     jfm_update(sound_ctx, (void **)tbuf, s2 - s1);
                    223: #else
                    224:     YM2612UpdateOne(0, (void **)tbuf, s2 -s1);
                    225: #endif
                    226: }
                    227: 
                    228: /*** sound_endfield - end frame and output sound ***/
                    229: 
                    230: void sound_endfield(void)
                    231: {
                    232:   unsigned int i;
                    233:   uint16 buffer[(SOUND_MAXRATE/50)*2]; /* pal is slowest framerate */
                    234: #ifdef WORDS_BIGENDIAN
                    235:   int endian = 1;
                    236: #else
                    237:   int endian = 0;
                    238: #endif
                    239:   audio_buf_info sound_info;
                    240:   unsigned int pending;
1.1.1.2 ! root      241:   struct timeval tv;
1.1       root      242: 
                    243:   if (ioctl(sound_dev, SNDCTL_DSP_GETOSPACE, &sound_info) == -1)
                    244:     ui_err("Error getting output space info", strerror(errno));
                    245:   pending = (sound_info.fragstotal*sound_info.fragsize)-sound_info.bytes;
                    246:   if (pending < sound_threshold)
                    247:     sound_feedback = -1;
                    248:   else
                    249:     sound_feedback = 0;
1.1.1.2 ! root      250:   if (sound_debug) {
        !           251:     LOG_VERBOSE(("End of field - sound card says output buffer left = %d bytes",
        !           252:                  sound_info.bytes));
        !           253:     LOG_VERBOSE(("Sound card says %d frags @ %d bytes each = %d bytes",
        !           254:                  sound_info.fragstotal, sound_info.fragsize,
        !           255:                  sound_info.fragstotal*sound_info.fragsize));
        !           256:     LOG_VERBOSE(("Therefore, pending = %d, compare with threshold %d = %d",
        !           257:                  pending, sound_threshold, sound_feedback));
        !           258:   }
1.1       root      259:   if (sound_format == AFMT_S16_LE && endian == 0) {
                    260:     /* device matches endianness of host */
                    261:     for (i = 0; i < sound_sampsperfield; i++) {
                    262:       buffer[i*2] = soundbuf[0][i];
                    263:       buffer[i*2+1] = soundbuf[1][i];
                    264:     }
                    265:   } else {
                    266:     /* device is odd and is different to host endianness */
                    267:     for (i = 0; i < sound_sampsperfield; i++) {
                    268:       buffer[i*2] = (soundbuf[0][i] >> 8) | ((soundbuf[0][i] << 8) & 0xff00);
                    269:       buffer[i*2+1] = (soundbuf[1][i] >> 8) | ((soundbuf[1][i] << 8) & 0xff00);
                    270:     }
                    271:   }
1.1.1.2 ! root      272:   if (sound_debug) {
        !           273:     gettimeofday(&tv, NULL);
        !           274:     LOG_REQUEST(("%ld:%ld - before write", tv.tv_sec, tv.tv_usec));
        !           275:   }
1.1       root      276:   if (write(sound_dev, buffer, sound_sampsperfield*4) == -1) {
                    277:     if (errno != EINTR)
                    278:       ui_err("Error writing to sound device: %s", strerror(errno));
                    279:   }
                    280:   /*
                    281:   if (write(sound_dump, buffer, sound_sampsperfield*4) == -1)
                    282:     ui_err("Error writing to dump file: %s", strerror(errno));
                    283:   */
1.1.1.2 ! root      284:   if (sound_debug) {
        !           285:     gettimeofday(&tv, NULL);
        !           286:     LOG_REQUEST(("%ld:%ld - after write", tv.tv_sec, tv.tv_usec));
        !           287:   }
1.1       root      288: }
                    289: 
                    290: /*** sound_ym2612fetch - fetch byte from ym2612 chip ***/
                    291: 
                    292: uint8 sound_ym2612fetch(uint8 addr)
                    293: {
1.1.1.2 ! root      294: #ifdef JFM
1.1       root      295:   return jfm_read(sound_ctx, addr);
1.1.1.2 ! root      296: #else
        !           297:   return YM2612Read(0, addr);
        !           298: #endif
1.1       root      299: }
                    300: 
                    301: /*** sound_ym2612store - store a byte to the ym2612 chip ***/
                    302: 
                    303: void sound_ym2612store(uint8 addr, uint8 data)
                    304: {
1.1.1.2 ! root      305:   switch (addr) {
        !           306:   case 0:
        !           307:     sound_address1 = data;
        !           308:     break;
        !           309:   case 1:
        !           310:     if (sound_address1 == 0x28 && (data & 3) != 3)
        !           311:       sound_keys[data & 7] = data >> 4;
        !           312:     if (sound_address1 == 0x2a) {
        !           313:       sound_keys[7] = 0;
        !           314:     }
        !           315:     if (sound_address1 == 0x2b)
        !           316:       sound_keys[7] = data & 0x80 ? 0xf : 0;
        !           317:     sound_regs1[sound_address1] = data;
        !           318:     break;
        !           319:   case 2:
        !           320:     sound_address2 = data;
        !           321:     break;
        !           322:   case 3:
        !           323:     sound_regs2[sound_address2] = data;
        !           324:     break;
        !           325:   }
        !           326: #ifdef JFM
1.1       root      327:   jfm_write(sound_ctx, addr, data);
1.1.1.2 ! root      328: #else
        !           329:   YM2612Write(0, addr, data);
        !           330: #endif
1.1       root      331: }
                    332: 

unix.superglobalmegacorp.com

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