|
|
1.1 root 1: /*****************************************************************************/
2: /* Generator - Sega Genesis emulation - (c) James Ponder 1997-1998 */
3: /*****************************************************************************/
4: /* */
5: /* sound.c */
6: /* */
7: /*****************************************************************************/
8:
9: #include <string.h>
10: #include <stdio.h>
11: #include <sys/types.h>
12: #include <sys/stat.h>
13: #include <fcntl.h>
14: #include <errno.h>
15: #include <sys/ioctl.h>
16: #include <unistd.h>
17: #include <math.h>
18:
19: #include "generator.h"
20: #include "gensound.h"
21: #include "vdp.h"
22: #include "ui.h"
23:
24: #ifdef JFM
25: # include "jfm.h"
26: #else
27: # include "support.h"
28: # include "fm.h"
29: #endif
30:
31: #include <sys/soundcard.h>
32:
33: /*** variables externed ***/
34:
35: int sound_feedback = 0; /* -1, running out of sound
36: +0, lots of sound, do something */
37: unsigned int sound_threshold; /* bytes in buffer we're trying to maintain */
38:
39: /* SN76489 snd_cpu; */
40:
41: /*** forward references ***/
42:
43: /* void snd_sndout(int chan, int freq, int vol); */
44:
45: /*** file scoped variables ***/
46:
47: #define SOUND_MAXRATE 44100
48: #define SOUND_FRAGMENTS 12
49: #define SOUND_THRESHOLD 10
50:
51: static unsigned int sound_sampsperfield = 0;
52: static int sound_dev = 0;
53: /* static int sound_dump = 0; */
54: static uint16 soundbuf[2][SOUND_MAXRATE/50]; /* pal is lowest framerate */
55: static int sound_format;
56: static int sound_stereo;
57: static int sound_speed;
58: static int sound_frag;
59: static int sound_fragsize;
60: static int sound_inited = 0; /* flag to say whether we've inited */
61:
62: #ifdef JFM
63: static t_jfm_ctx *sound_ctx;
64: #endif
65:
66: /*** sound_init - initialise this sub-unit ***/
67:
68: int sound_init(void)
69: {
70: audio_buf_info sound_info;
71:
72: LOG_NORMAL(("Initialising sound..."));
73: sound_sampsperfield = SOUND_SAMPLERATE / vdp_framerate;
74:
75: /* sound_dump = open("/tmp/sound_dump", O_CREAT|O_WRONLY|O_TRUNC); */
76:
77: if ((sound_dev = open(SOUND_DEVICE, O_WRONLY, 0)) == -1) {
78: LOG_CRITICAL(("open " SOUND_DEVICE " failed: %s", strerror(errno)));
79: return 1;
80: }
81: sound_frag = (SOUND_FRAGMENTS<<16 |
82: (int)(ceil(log10(sound_sampsperfield*4)/log10(2))));
83: if (ioctl(sound_dev, SNDCTL_DSP_SETFRAGMENT, &sound_frag) == -1) {
84: LOG_CRITICAL(("Error setting fragment size: %s", strerror(errno)));
85: return 1;
86: }
87: sound_format = AFMT_S16_LE;
88: if (ioctl(sound_dev, SNDCTL_DSP_SETFMT, &sound_format) == -1) {
89: LOG_CRITICAL(("Error setting sound device format: %s", strerror(errno)));
90: return 1;
91: }
92: if (sound_format != AFMT_S16_LE && sound_format != AFMT_S16_BE) {
93: LOG_CRITICAL(("Sound device format not supported (must be 16 bit)"));
94: return 1;
95: }
96: sound_stereo = 1;
97: if (ioctl(sound_dev, SNDCTL_DSP_STEREO, &sound_stereo) == -1) {
98: LOG_CRITICAL(("Error setting stereo: %s", strerror(errno)));
99: return 1;
100: }
101: if (sound_stereo != 1) {
102: LOG_CRITICAL(("Sound device does not support stereo"));
103: return 1;
104: }
105: sound_speed = SOUND_SAMPLERATE;
106: if (ioctl(sound_dev, SNDCTL_DSP_SPEED, &sound_speed) == -1) {
107: LOG_CRITICAL(("Error setting sound speed: %s", strerror(errno)));
108: return 1;
109: }
110: if (sound_speed != SOUND_SAMPLERATE) {
111: if (abs(sound_speed-SOUND_SAMPLERATE) > 50) {
112: LOG_NORMAL(("Warning: Sample rate not exactly 22050"));
113: } else {
114: LOG_CRITICAL(("Sound device does not support sample rate %d "
115: "(returned %d)", SOUND_SAMPLERATE, sound_speed));
116: return 1;
117: }
118: }
119: if (ioctl(sound_dev, SNDCTL_DSP_GETOSPACE, &sound_info) == -1) {
120: LOG_CRITICAL(("Error getting output space info", strerror(errno)));
121: return 1;
122: }
123: LOG_NORMAL(("Total allocated fragments = %d (requested %d)",
124: sound_info.fragstotal, SOUND_FRAGMENTS));
125: LOG_NORMAL(("Fragment size = %d (requested %d)", sound_info.fragsize,
126: sound_sampsperfield*4));
127: LOG_NORMAL(("Bytes free in buffer = %d", sound_info.bytes));
128: sound_threshold = sound_sampsperfield*4*SOUND_THRESHOLD;
129: LOG_NORMAL(("Theshold = %d (%d fields of sound === %dms latency)",
130: sound_threshold, SOUND_THRESHOLD,
131: (int)(1000*(float)SOUND_THRESHOLD/(float)vdp_framerate)));
132: if ((signed)sound_threshold >= sound_info.bytes) {
133: LOG_CRITICAL(("Threshold exceeds bytes free in buffer"));
134: return 1;
135: }
136: #ifdef JFM
137: if ((sound_ctx = jfm_init(0, 2612, vdp_clock/7, sound_speed,
138: NULL, NULL)) == NULL)
139: #else
140: if (YM2612Init(1, vdp_clock/7, sound_speed, NULL, NULL))
141: #endif
142: return 1;
143: LOG_NORMAL(("YM2612 Initialised @ sample rate %d", sound_speed));
144: return 0;
145: }
146:
147: /*** sound_final - finalise this sub-unit ***/
148:
149: void sound_final(void)
150: {
151: #ifdef JFM
152: jfm_final(sound_ctx);
153: #else
154: YM2612Shutdown();
155: #endif
156: if (sound_dev)
157: close(sound_dev);
158: }
159:
160: /*** sound_reset - reset sound sub-unit ***/
161:
162: int sound_reset(void)
163: {
164: sound_final();
165: return sound_init();
166: }
167:
168: /*** sound_genreset - reset genesis sound ***/
169:
170: void sound_genreset(void)
171: {
172: #ifdef JFM
173: jfm_reset(sound_ctx);
174: #else
175: YM2612ResetChip(0);
176: #endif
177: }
178:
179: /*** sound_process - process sound ***/
180:
181: void sound_process(void)
182: {
183: static uint16 *tbuf[2];
184: int s1 = (sound_sampsperfield*(vdp_line))/vdp_totlines;
185: int s2 = (sound_sampsperfield*(vdp_line+1))/vdp_totlines;
186:
187: tbuf[0] = soundbuf[0] + s1;
188: tbuf[1] = soundbuf[1] + s1;
189:
190: /* printf("YM2612: %d to %d\n", s1, s2); */
191:
192: if (s2 > s1)
193: #ifdef JFM
194: jfm_update(sound_ctx, (void **)tbuf, s2 - s1);
195: #else
196: YM2612UpdateOne(0, (void **)tbuf, s2 -s1);
197: #endif
198: }
199:
200: /*** sound_endfield - end frame and output sound ***/
201:
202: void sound_endfield(void)
203: {
204: unsigned int i;
205: uint16 buffer[(SOUND_MAXRATE/50)*2]; /* pal is slowest framerate */
206: #ifdef WORDS_BIGENDIAN
207: int endian = 1;
208: #else
209: int endian = 0;
210: #endif
211: audio_buf_info sound_info;
212: unsigned int pending;
213:
214: if (ioctl(sound_dev, SNDCTL_DSP_GETOSPACE, &sound_info) == -1)
215: ui_err("Error getting output space info", strerror(errno));
216: pending = (sound_info.fragstotal*sound_info.fragsize)-sound_info.bytes;
217: if (pending < sound_threshold)
218: sound_feedback = -1;
219: else
220: sound_feedback = 0;
221: LOG_DEBUG1(("END FIELD! 0 to %d (%d)", sound_sampsperfield, sound_feedback));
222: if (sound_format == AFMT_S16_LE && endian == 0) {
223: /* device matches endianness of host */
224: for (i = 0; i < sound_sampsperfield; i++) {
225: buffer[i*2] = soundbuf[0][i];
226: buffer[i*2+1] = soundbuf[1][i];
227: }
228: } else {
229: /* device is odd and is different to host endianness */
230: for (i = 0; i < sound_sampsperfield; i++) {
231: buffer[i*2] = (soundbuf[0][i] >> 8) | ((soundbuf[0][i] << 8) & 0xff00);
232: buffer[i*2+1] = (soundbuf[1][i] >> 8) | ((soundbuf[1][i] << 8) & 0xff00);
233: }
234: }
235: if (write(sound_dev, buffer, sound_sampsperfield*4) == -1) {
236: if (errno != EINTR)
237: ui_err("Error writing to sound device: %s", strerror(errno));
238: }
239: /*
240: if (write(sound_dump, buffer, sound_sampsperfield*4) == -1)
241: ui_err("Error writing to dump file: %s", strerror(errno));
242: */
243: }
244:
245: #ifdef JFM
246:
247: /*** sound_ym2612fetch - fetch byte from ym2612 chip ***/
248:
249: uint8 sound_ym2612fetch(uint8 addr)
250: {
251: return jfm_read(sound_ctx, addr);
252: }
253:
254: /*** sound_ym2612store - store a byte to the ym2612 chip ***/
255:
256: void sound_ym2612store(uint8 addr, uint8 data)
257: {
258: jfm_write(sound_ctx, addr, data);
259: }
260:
261: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.