|
|
1.1 ! root 1: /* Generator is (c) James Ponder, 1997-2001 http://www.squish.net/generator/ */ ! 2: ! 3: #include <sys/types.h> ! 4: #include <sys/stat.h> ! 5: #include <sys/ioctl.h> ! 6: #include <sys/time.h> ! 7: #include <string.h> ! 8: #include <stdio.h> ! 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: ! 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]; ! 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; ! 53: static int sound_dev = -1; ! 54: /* static int sound_dump = 0; */ ! 55: static uint16 soundbuf[2][SOUND_MAXRATE/50]; /* pal is lowest framerate */ ! 56: static int sound_active = 0; ! 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; ! 62: static unsigned int sound_threshold; /* bytes in buffer we're trying for */ ! 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: int ret; ! 73: ! 74: ret = sound_start(); ! 75: if (ret) ! 76: return ret; ! 77: #ifdef JFM ! 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: close(sound_dev); ! 84: return 1; ! 85: } ! 86: LOG_VERBOSE(("YM2612 Initialised @ sample rate %d", sound_speed)); ! 87: return 0; ! 88: } ! 89: ! 90: /*** sound_final - finalise this sub-unit ***/ ! 91: ! 92: void sound_final(void) ! 93: { ! 94: sound_stop(); ! 95: #ifdef JFM ! 96: jfm_final(sound_ctx); ! 97: #else ! 98: YM2612Shutdown(); ! 99: #endif ! 100: } ! 101: ! 102: /*** sound_start - start sound hardware ***/ ! 103: ! 104: int sound_start(void) ! 105: { ! 106: audio_buf_info sound_info; ! 107: ! 108: /* The threshold parameter specifies how many fields worth of sound we ! 109: should try and keep around (a display field is 1/50th or 1/60th of a ! 110: second) - generator works by trying to keep threshold number of fields ! 111: worth of sound around, and drops plotting frames to keep up on slow ! 112: machines */ ! 113: ! 114: if (sound_active) ! 115: sound_stop(); ! 116: LOG_VERBOSE(("Initialising sound...")); ! 117: sound_sampsperfield = SOUND_SAMPLERATE / vdp_framerate; ! 118: ! 119: /* sound_dump = open("/tmp/sound_dump", O_CREAT|O_WRONLY|O_TRUNC); */ ! 120: ! 121: if ((sound_dev = open(SOUND_DEVICE, O_WRONLY, 0)) == -1) { ! 122: LOG_CRITICAL(("open " SOUND_DEVICE " failed: %s", strerror(errno))); ! 123: return 1; ! 124: } ! 125: sound_frag = (sound_maxfields<<16 | ! 126: (int)(ceil(log10(sound_sampsperfield*4)/log10(2)))); ! 127: if (ioctl(sound_dev, SNDCTL_DSP_SETFRAGMENT, &sound_frag) == -1) { ! 128: LOG_CRITICAL(("Error setting fragment size: %s", strerror(errno))); ! 129: close(sound_dev); ! 130: return 1; ! 131: } ! 132: sound_format = AFMT_S16_LE; ! 133: if (ioctl(sound_dev, SNDCTL_DSP_SETFMT, &sound_format) == -1) { ! 134: LOG_CRITICAL(("Error setting sound device format: %s", strerror(errno))); ! 135: close(sound_dev); ! 136: return 1; ! 137: } ! 138: if (sound_format != AFMT_S16_LE && sound_format != AFMT_S16_BE) { ! 139: LOG_CRITICAL(("Sound device format not supported (must be 16 bit)")); ! 140: close(sound_dev); ! 141: return 1; ! 142: } ! 143: sound_stereo = 1; ! 144: if (ioctl(sound_dev, SNDCTL_DSP_STEREO, &sound_stereo) == -1) { ! 145: LOG_CRITICAL(("Error setting stereo: %s", strerror(errno))); ! 146: close(sound_dev); ! 147: return 1; ! 148: } ! 149: if (sound_stereo != 1) { ! 150: LOG_CRITICAL(("Sound device does not support stereo")); ! 151: close(sound_dev); ! 152: return 1; ! 153: } ! 154: sound_speed = SOUND_SAMPLERATE; ! 155: if (ioctl(sound_dev, SNDCTL_DSP_SPEED, &sound_speed) == -1) { ! 156: LOG_CRITICAL(("Error setting sound speed: %s", strerror(errno))); ! 157: close(sound_dev); ! 158: return 1; ! 159: } ! 160: if (sound_speed != SOUND_SAMPLERATE) { ! 161: if (abs(sound_speed-SOUND_SAMPLERATE) > 50) { ! 162: LOG_NORMAL(("Warning: Sample rate not exactly 22050")); ! 163: } else { ! 164: LOG_CRITICAL(("Sound device does not support sample rate %d " ! 165: "(returned %d)", SOUND_SAMPLERATE, sound_speed)); ! 166: close(sound_dev); ! 167: return 1; ! 168: } ! 169: } ! 170: if (ioctl(sound_dev, SNDCTL_DSP_GETOSPACE, &sound_info) == -1) { ! 171: LOG_CRITICAL(("Error getting output space info", strerror(errno))); ! 172: close(sound_dev); ! 173: return 1; ! 174: } ! 175: LOG_VERBOSE(("Total allocated fragments = %d (requested %d)", ! 176: sound_info.fragstotal, sound_maxfields)); ! 177: LOG_VERBOSE(("Fragment size = %d (requested %d)", sound_info.fragsize, ! 178: sound_sampsperfield*4)); ! 179: LOG_VERBOSE(("Bytes free in buffer = %d", sound_info.bytes)); ! 180: sound_threshold = sound_sampsperfield*4*sound_minfields; ! 181: LOG_VERBOSE(("Theshold = %d (%d fields of sound === %dms latency)", ! 182: sound_threshold, sound_minfields, ! 183: (int)(1000*(float)sound_minfields/(float)vdp_framerate))); ! 184: if ((signed)sound_threshold >= sound_info.bytes) { ! 185: LOG_CRITICAL(("Threshold exceeds bytes free in buffer")); ! 186: close(sound_dev); ! 187: return 1; ! 188: } ! 189: sound_active = 1; ! 190: return 0; ! 191: } ! 192: /*** sound_stop - stop sound ***/ ! 193: ! 194: void sound_stop(void) ! 195: { ! 196: if (!sound_active) ! 197: return; ! 198: LOG_VERBOSE(("Stopping sound...")); ! 199: if (sound_dev != -1) ! 200: close(sound_dev); ! 201: sound_dev = -1; ! 202: sound_active = 0; ! 203: LOG_VERBOSE(("Stopped sound.")); ! 204: } ! 205: ! 206: /*** sound_reset - reset sound sub-unit ***/ ! 207: ! 208: int sound_reset(void) ! 209: { ! 210: sound_final(); ! 211: return sound_init(); ! 212: } ! 213: ! 214: /*** sound_genreset - reset genesis sound ***/ ! 215: ! 216: void sound_genreset(void) ! 217: { ! 218: #ifdef JFM ! 219: jfm_reset(sound_ctx); ! 220: #else ! 221: YM2612ResetChip(0); ! 222: #endif ! 223: } ! 224: ! 225: /*** sound_process - process sound ***/ ! 226: ! 227: void sound_process(void) ! 228: { ! 229: static sint16 *tbuf[2]; ! 230: int s1 = (sound_sampsperfield*(vdp_line))/vdp_totlines; ! 231: int s2 = (sound_sampsperfield*(vdp_line+1))/vdp_totlines; ! 232: ! 233: tbuf[0] = soundbuf[0] + s1; ! 234: tbuf[1] = soundbuf[1] + s1; ! 235: ! 236: /* printf("YM2612: %d to %d\n", s1, s2); */ ! 237: ! 238: if (s2 > s1) ! 239: #ifdef JFM ! 240: jfm_update(sound_ctx, (void **)tbuf, s2 - s1); ! 241: #else ! 242: YM2612UpdateOne(0, (void **)tbuf, s2 -s1); ! 243: #endif ! 244: } ! 245: ! 246: /*** sound_endfield - end frame and output sound ***/ ! 247: ! 248: void sound_endfield(void) ! 249: { ! 250: unsigned int i; ! 251: uint16 buffer[(SOUND_MAXRATE/50)*2]; /* pal is slowest framerate */ ! 252: #ifdef WORDS_BIGENDIAN ! 253: int endian = 1; ! 254: #else ! 255: int endian = 0; ! 256: #endif ! 257: audio_buf_info sound_info; ! 258: unsigned int pending; ! 259: struct timeval tv; ! 260: ! 261: if (ioctl(sound_dev, SNDCTL_DSP_GETOSPACE, &sound_info) == -1) ! 262: ui_err("Error getting output space info", strerror(errno)); ! 263: pending = (sound_info.fragstotal*sound_info.fragsize)-sound_info.bytes; ! 264: if (pending < sound_threshold) ! 265: sound_feedback = -1; ! 266: else ! 267: sound_feedback = 0; ! 268: if (sound_debug) { ! 269: LOG_VERBOSE(("End of field - sound card says output buffer left = %d bytes", ! 270: sound_info.bytes)); ! 271: LOG_VERBOSE(("Sound card says %d frags @ %d bytes each = %d bytes", ! 272: sound_info.fragstotal, sound_info.fragsize, ! 273: sound_info.fragstotal*sound_info.fragsize)); ! 274: LOG_VERBOSE(("Therefore, pending = %d, compare with threshold %d = %d", ! 275: pending, sound_threshold, sound_feedback)); ! 276: } ! 277: if (sound_format == AFMT_S16_LE && endian == 0) { ! 278: /* device matches endianness of host */ ! 279: for (i = 0; i < sound_sampsperfield; i++) { ! 280: buffer[i*2] = soundbuf[0][i]; ! 281: buffer[i*2+1] = soundbuf[1][i]; ! 282: } ! 283: } else { ! 284: /* device is odd and is different to host endianness */ ! 285: for (i = 0; i < sound_sampsperfield; i++) { ! 286: buffer[i*2] = (soundbuf[0][i] >> 8) | ((soundbuf[0][i] << 8) & 0xff00); ! 287: buffer[i*2+1] = (soundbuf[1][i] >> 8) | ((soundbuf[1][i] << 8) & 0xff00); ! 288: } ! 289: } ! 290: if (sound_debug) { ! 291: gettimeofday(&tv, NULL); ! 292: LOG_REQUEST(("%ld:%ld - before write", tv.tv_sec, tv.tv_usec)); ! 293: } ! 294: if (write(sound_dev, buffer, sound_sampsperfield*4) == -1) { ! 295: if (errno != EINTR) ! 296: ui_err("Error writing to sound device: %s", strerror(errno)); ! 297: } ! 298: /* ! 299: if (write(sound_dump, buffer, sound_sampsperfield*4) == -1) ! 300: ui_err("Error writing to dump file: %s", strerror(errno)); ! 301: */ ! 302: if (sound_debug) { ! 303: gettimeofday(&tv, NULL); ! 304: LOG_REQUEST(("%ld:%ld - after write", tv.tv_sec, tv.tv_usec)); ! 305: } ! 306: } ! 307: ! 308: /*** sound_ym2612fetch - fetch byte from ym2612 chip ***/ ! 309: ! 310: uint8 sound_ym2612fetch(uint8 addr) ! 311: { ! 312: #ifdef JFM ! 313: return jfm_read(sound_ctx, addr); ! 314: #else ! 315: return YM2612Read(0, addr); ! 316: #endif ! 317: } ! 318: ! 319: /*** sound_ym2612store - store a byte to the ym2612 chip ***/ ! 320: ! 321: void sound_ym2612store(uint8 addr, uint8 data) ! 322: { ! 323: switch (addr) { ! 324: case 0: ! 325: sound_address1 = data; ! 326: break; ! 327: case 1: ! 328: if (sound_address1 == 0x28 && (data & 3) != 3) ! 329: sound_keys[data & 7] = data >> 4; ! 330: if (sound_address1 == 0x2a) { ! 331: sound_keys[7] = 0; ! 332: } ! 333: if (sound_address1 == 0x2b) ! 334: sound_keys[7] = data & 0x80 ? 0xf : 0; ! 335: sound_regs1[sound_address1] = data; ! 336: break; ! 337: case 2: ! 338: sound_address2 = data; ! 339: break; ! 340: case 3: ! 341: sound_regs2[sound_address2] = data; ! 342: break; ! 343: } ! 344: #ifdef JFM ! 345: jfm_write(sound_ctx, addr, data); ! 346: #else ! 347: YM2612Write(0, addr, data); ! 348: #endif ! 349: } ! 350:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.