|
|
1.1.1.8 root 1: /*
1.1 root 2: * UAE - The Un*x Amiga Emulator
1.1.1.8 root 3: *
1.1 root 4: * Support for Linux/USS sound
1.1.1.8 root 5: *
1.1 root 6: * Copyright 1997 Bernd Schmidt
7: */
8:
9: #include "sysconfig.h"
10: #include "sysdeps.h"
11:
12: #include "options.h"
13: #include "memory.h"
1.1.1.4 root 14: #include "events.h"
1.1 root 15: #include "custom.h"
1.1.1.10! root 16: #include "newcpu.h"
1.1 root 17: #include "gensound.h"
18: #include "sounddep/sound.h"
1.1.1.9 root 19: #include "threaddep/thread.h"
1.1 root 20:
21: #include <sys/ioctl.h>
22:
23: #ifdef HAVE_SYS_SOUNDCARD_H
24: #include <sys/soundcard.h>
25: #elif defined HAVE_MACHINE_SOUNDCARD_H
26: #include <machine/soundcard.h>
27: #else
28: #error "Something went wrong during configuration."
29: #endif
30:
1.1.1.9 root 31: static smp_comm_pipe to_sound_pipe;
32: static uae_sem_t sound_comm_sem;
33:
34: static int sound_fd;
1.1.1.10! root 35: static int have_sound = 0, have_thread = 0;
1.1.1.9 root 36: static int dont_block;
1.1 root 37: static unsigned long formats;
38:
1.1.1.9 root 39: static int which_buffer;
40: static uae_u16 sndbuffer[2][44100];
41: uae_u16 *sndbufpt, *sndbuf_base;
1.1 root 42: int sndbufsize;
43:
1.1.1.2 root 44: static int exact_log2 (int v)
1.1 root 45: {
46: int l = 0;
47: while ((v >>= 1) != 0)
48: l++;
49: return l;
50: }
51:
1.1.1.9 root 52: void finish_sound_buffers (void)
53: {
1.1.1.10! root 54: dont_block = currprefs.m68k_speed == -1 && (!regs.stopped || active_fs_packets > 0);
! 55: if (!dont_block) {
! 56: write (sound_fd, sndbuffer[which_buffer], sndbufsize);
! 57: } else {
! 58: write_comm_pipe_int (&to_sound_pipe, 2, 1);
! 59: uae_sem_wait (&sound_comm_sem);
! 60: }
1.1.1.9 root 61: sndbufpt = sndbuf_base = sndbuffer[which_buffer ^= 1];
62: }
63:
1.1.1.2 root 64: void close_sound (void)
1.1 root 65: {
1.1.1.10! root 66: sync_with_sound = 0;
1.1 root 67: if (have_sound)
1.1.1.2 root 68: close (sound_fd);
1.1.1.9 root 69:
1.1.1.10! root 70: if (have_thread) {
! 71: write_comm_pipe_int (&to_sound_pipe, 1, 1);
! 72: uae_sem_wait (&sound_comm_sem);
! 73: uae_sem_destroy (&sound_comm_sem);
! 74: }
1.1 root 75: }
76:
1.1.1.3 root 77: /* Try to determine whether sound is available. This is only for GUI purposes. */
1.1.1.2 root 78: int setup_sound (void)
1.1 root 79: {
80: sound_fd = open ("/dev/dsp", O_WRONLY);
1.1.1.3 root 81:
82: sound_available = 0;
83:
84: if (sound_fd < 0) {
85: perror ("Can't open /dev/dsp");
86: if (errno == EBUSY) {
87: /* We can hope, can't we ;) */
88: sound_available = 1;
89: return 1;
90: }
1.1 root 91: return 0;
1.1.1.3 root 92: }
1.1 root 93:
94: if (ioctl (sound_fd, SNDCTL_DSP_GETFMTS, &formats) == -1) {
1.1.1.3 root 95: perror ("ioctl failed - can't use sound");
96: close (sound_fd);
1.1 root 97: return 0;
98: }
99:
100: sound_available = 1;
1.1.1.3 root 101: close (sound_fd);
1.1 root 102: return 1;
103: }
104:
1.1.1.9 root 105: static void open_sound (void)
1.1 root 106: {
107: int tmp;
108: int rate;
109: int dspbits;
110:
1.1.1.10! root 111: sync_with_sound = 0;
! 112:
1.1.1.3 root 113: sound_fd = open ("/dev/dsp", O_WRONLY);
114: have_sound = !(sound_fd < 0);
115: if (! have_sound) {
116: perror ("Can't open /dev/dsp");
117: if (errno != EBUSY)
118: sound_available = 0;
1.1.1.9 root 119: return;
1.1.1.3 root 120: }
121: if (ioctl (sound_fd, SNDCTL_DSP_GETFMTS, &formats) == -1) {
122: perror ("ioctl failed - can't use sound");
1.1.1.9 root 123: goto out_err;
1.1.1.3 root 124: }
125:
1.1 root 126: if (currprefs.sound_maxbsiz < 128 || currprefs.sound_maxbsiz > 16384) {
1.1.1.2 root 127: fprintf (stderr, "Sound buffer size %d out of range.\n", currprefs.sound_maxbsiz);
1.1.1.10! root 128: currprefs.sound_maxbsiz = 1024;
1.1 root 129: }
130:
1.1.1.9 root 131: dspbits = 16;
1.1 root 132: ioctl (sound_fd, SNDCTL_DSP_SAMPLESIZE, &dspbits);
133: ioctl (sound_fd, SOUND_PCM_READ_BITS, &dspbits);
1.1.1.9 root 134: if (dspbits != 16) {
135: fprintf (stderr, "Can't use sound with 16 bits\n");
136: goto out_err;
1.1 root 137: }
138:
1.1.1.7 root 139: tmp = currprefs.sound_stereo;
1.1 root 140: ioctl (sound_fd, SNDCTL_DSP_STEREO, &tmp);
141:
142: rate = currprefs.sound_freq;
143: ioctl (sound_fd, SNDCTL_DSP_SPEED, &rate);
144: ioctl (sound_fd, SOUND_PCM_READ_RATE, &rate);
145: /* Some soundcards have a bit of tolerance here. */
146: if (rate < currprefs.sound_freq * 90 / 100 || rate > currprefs.sound_freq * 110 / 100) {
1.1.1.2 root 147: fprintf (stderr, "Can't use sound with desired frequency %d\n", currprefs.sound_freq);
1.1.1.9 root 148: goto out_err;
1.1 root 149: }
150:
1.1.1.10! root 151: tmp = 1 << exact_log2 (currprefs.sound_maxbsiz);
! 152: while (tmp * 1000 / (rate * 2 * (currprefs.sound_stereo ? 2 : 1)) < 6)
! 153: tmp *= 2;
! 154: if (tmp != currprefs.sound_maxbsiz) {
! 155: fprintf (stderr, "Increasing sound buffer size to sane minimum of %d bytes.\n",
! 156: tmp);
! 157: }
! 158: tmp = 0x00040000 + exact_log2 (tmp);
! 159: ioctl (sound_fd, SNDCTL_DSP_SETFRAGMENT, &tmp);
! 160: ioctl (sound_fd, SNDCTL_DSP_GETBLKSIZE, &sndbufsize);
! 161:
1.1.1.9 root 162: obtainedfreq = rate;
1.1 root 163:
1.1.1.9 root 164: if (!(formats & AFMT_S16_NE))
165: goto out_err;
166: init_sound_table16 ();
167: sample_handler = currprefs.sound_stereo ? sample16s_handler : sample16_handler;
168:
169: sound_available = 1;
170: printf ("Sound driver found and configured at %d Hz, buffer is %d bytes (%d ms).\n",
171: rate, sndbufsize, sndbufsize * 1000 / (rate * 2 * (currprefs.sound_stereo ? 2 : 1)));
172: sndbufpt = sndbuf_base = sndbuffer[which_buffer = 0];
173:
1.1.1.10! root 174: sync_with_sound = 1;
1.1.1.9 root 175: return;
176:
177: out_err:
178: close (sound_fd);
179: have_sound = 0;
180: return;
181: }
182:
183: static void *sound_thread (void *dummy)
184: {
1.1.1.10! root 185: uae_u16 *base;
1.1.1.9 root 186: for (;;) {
187: int cmd = read_comm_pipe_int_blocking (&to_sound_pipe);
188: int n;
189:
190: switch (cmd) {
191: case 0:
192: open_sound ();
193: uae_sem_post (&sound_comm_sem);
194: break;
195: case 1:
196: uae_sem_post (&sound_comm_sem);
1.1 root 197: return 0;
1.1.1.9 root 198: case 2:
199: /* If trying for maximum CPU speed, don't block the main
1.1.1.10! root 200: thread, instead set the delaying_for_sound variable. If
1.1.1.9 root 201: not trying for maximum CPU speed, synchronize here by
202: delaying the sem_post until after the write. */
1.1.1.10! root 203: delaying_for_sound = dont_block;
! 204: base = sndbuf_base;
1.1.1.9 root 205: if (dont_block)
206: uae_sem_post (&sound_comm_sem);
207:
1.1.1.10! root 208: write (sound_fd, sndbuf_base, sndbufsize);
1.1.1.9 root 209: if (!dont_block)
210: uae_sem_post (&sound_comm_sem);
211:
1.1.1.10! root 212: delaying_for_sound = 0;
1.1.1.9 root 213: break;
214: }
1.1 root 215: }
1.1.1.9 root 216: }
1.1.1.8 root 217:
1.1.1.9 root 218: /* We use a thread so that we can use the time spent waiting for the sound
219: driver for executing m68k instructions, rather than just blocking. */
220: static void init_sound_thread (void)
221: {
222: uae_thread_id tid;
223:
224: init_comm_pipe (&to_sound_pipe, 20, 1);
225: uae_sem_init (&sound_comm_sem, 0, 0);
226: uae_start_thread (sound_thread, NULL, &tid);
1.1.1.10! root 227: have_thread = 1;
1.1.1.9 root 228: }
229:
230: int init_sound (void)
231: {
232: init_sound_thread ();
233: write_comm_pipe_int (&to_sound_pipe, 0, 1);
234: uae_sem_wait (&sound_comm_sem);
235:
236: return have_sound;
1.1 root 237: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.