···11+Sound drivers
22+=============
33+44+The syntax of a sound driver specification is:
55+66+<driver>:<option1>=<value1>:<option2>=<value2>...
77+88+White space around option names and values is ignored. If a value contains
99+a colon, it must be escaped by repeating it.
1010+1111+1212+The following options can be used with all sound drivers:
1313+1414+ wav=<filename>
1515+ Write the sound output to a WAV file.
1616+1717+ lowpass=<frequency>
1818+ Apply a low-pass filter. If <frequency> is 0 (the default),
1919+ the low-pass filter is disabled.
2020+2121+ wavfilter=[0|1]
2222+ If true then the low-pass filter is applied before the sound
2323+ is written to the WAV file.
2424+2525+2626+The following is a list of sound drivers and their options:
2727+2828+null:
2929+ The null sound driver that discards output written to it. It can
3030+ still be written to a WAV file as a side effect.
3131+3232+3333+wav:
3434+ This is another name for the null sound driver.
···11+/*****************************************************************************
22+ * pce *
33+ *****************************************************************************/
44+55+/*****************************************************************************
66+ * File name: src/drivers/sound/sound-null.c *
77+ * Created: 2009-10-17 by Hampa Hug <hampa@hampa.ch> *
88+ * Copyright: (C) 2009 Hampa Hug <hampa@hampa.ch> *
99+ *****************************************************************************/
1010+1111+/*****************************************************************************
1212+ * This program is free software. You can redistribute it and / or modify it *
1313+ * under the terms of the GNU General Public License version 2 as published *
1414+ * by the Free Software Foundation. *
1515+ * *
1616+ * This program is distributed in the hope that it will be useful, but *
1717+ * WITHOUT ANY WARRANTY, without even the implied warranty of *
1818+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
1919+ * Public License for more details. *
2020+ *****************************************************************************/
2121+2222+2323+#include <stdlib.h>
2424+#include <stdio.h>
2525+#include <string.h>
2626+2727+#include <drivers/sound/sound.h>
2828+#include <drivers/sound/sound-null.h>
2929+3030+3131+static
3232+void snd_null_close (sound_drv_t *sdrv)
3333+{
3434+ sound_null_t *drv;
3535+3636+ drv = sdrv->ext;
3737+3838+ free (drv);
3939+}
4040+4141+static
4242+int snd_null_write (sound_drv_t *sdrv, const uint16_t *buf, unsigned cnt)
4343+{
4444+ sound_null_t *drv;
4545+4646+ drv = sdrv->ext;
4747+4848+ return (0);
4949+}
5050+5151+static
5252+int snd_null_set_params (sound_drv_t *sdrv, unsigned chn, unsigned long srate, int sign)
5353+{
5454+ sound_null_t *drv;
5555+5656+ drv = sdrv->ext;
5757+5858+ return (0);
5959+}
6060+6161+static
6262+int snd_null_init (sound_null_t *drv, const char *name)
6363+{
6464+ snd_init (&drv->sdrv, drv);
6565+6666+ drv->sdrv.close = snd_null_close;
6767+ drv->sdrv.write = snd_null_write;
6868+ drv->sdrv.set_params = snd_null_set_params;
6969+7070+ return (0);
7171+}
7272+7373+sound_drv_t *snd_null_open (const char *name)
7474+{
7575+ sound_null_t *drv;
7676+7777+ drv = malloc (sizeof (sound_null_t));
7878+7979+ if (drv == NULL) {
8080+ return (NULL);
8181+ }
8282+8383+ if (snd_null_init (drv, name)) {
8484+ free (drv);
8585+ return (NULL);
8686+ }
8787+8888+ return (&drv->sdrv);
8989+}
+35
src/drivers/sound/sound-null.h
···11+/*****************************************************************************
22+ * pce *
33+ *****************************************************************************/
44+55+/*****************************************************************************
66+ * File name: src/drivers/sound/sound-null.h *
77+ * Created: 2009-10-17 by Hampa Hug <hampa@hampa.ch> *
88+ * Copyright: (C) 2009 Hampa Hug <hampa@hampa.ch> *
99+ *****************************************************************************/
1010+1111+/*****************************************************************************
1212+ * This program is free software. You can redistribute it and / or modify it *
1313+ * under the terms of the GNU General Public License version 2 as published *
1414+ * by the Free Software Foundation. *
1515+ * *
1616+ * This program is distributed in the hope that it will be useful, but *
1717+ * WITHOUT ANY WARRANTY, without even the implied warranty of *
1818+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
1919+ * Public License for more details. *
2020+ *****************************************************************************/
2121+2222+2323+#ifndef PCE_DRIVERS_SOUND_NULL_H
2424+#define PCE_DRIVERS_SOUND_NULL_H 1
2525+2626+2727+#include <drivers/sound/sound.h>
2828+2929+3030+typedef struct sound_null_t {
3131+ sound_drv_t sdrv;
3232+} sound_null_t;
3333+3434+3535+#endif
+172
src/drivers/sound/sound-wav.c
···11+/*****************************************************************************
22+ * pce *
33+ *****************************************************************************/
44+55+/*****************************************************************************
66+ * File name: src/drivers/sound/sound-wav.c *
77+ * Created: 2009-10-18 by Hampa Hug <hampa@hampa.ch> *
88+ * Copyright: (C) 2009-2010 Hampa Hug <hampa@hampa.ch> *
99+ *****************************************************************************/
1010+1111+/*****************************************************************************
1212+ * This program is free software. You can redistribute it and / or modify it *
1313+ * under the terms of the GNU General Public License version 2 as published *
1414+ * by the Free Software Foundation. *
1515+ * *
1616+ * This program is distributed in the hope that it will be useful, but *
1717+ * WITHOUT ANY WARRANTY, without even the implied warranty of *
1818+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
1919+ * Public License for more details. *
2020+ *****************************************************************************/
2121+2222+2323+#include <stdlib.h>
2424+#include <stdio.h>
2525+#include <string.h>
2626+2727+#include <drivers/options.h>
2828+#include <drivers/sound/sound.h>
2929+#include <drivers/sound/sound-wav.h>
3030+3131+#define WAVE_RIFF 0x46464952
3232+#define WAVE_WAVE 0x45564157
3333+#define WAVE_FMT 0x20746d66
3434+#define WAVE_DATA 0x61746164
3535+3636+3737+static
3838+void wav_set_uint16 (void *buf, unsigned i, unsigned v)
3939+{
4040+ unsigned char *tmp;
4141+4242+ tmp = (unsigned char *) buf + i;
4343+4444+ tmp[0] = v & 0xff;
4545+ tmp[1] = (v >> 8) & 0xff;
4646+}
4747+4848+static
4949+void wav_set_uint32 (void *buf, unsigned i, unsigned long v)
5050+{
5151+ unsigned char *tmp;
5252+5353+ tmp = (unsigned char *) buf + i;
5454+5555+ tmp[0] = v & 0xff;
5656+ tmp[1] = (v >> 8) & 0xff;
5757+ tmp[2] = (v >> 16) & 0xff;
5858+ tmp[3] = (v >> 24) & 0xff;
5959+}
6060+6161+static
6262+int snd_wav_write_header (sound_drv_t *sdrv)
6363+{
6464+ unsigned char buf[64];
6565+6666+ if (fseek (sdrv->wav_fp, 0, SEEK_SET)) {
6767+ return (1);
6868+ }
6969+7070+ wav_set_uint32 (buf, 0, WAVE_RIFF);
7171+ wav_set_uint32 (buf, 4, sdrv->wav_cnt + 36);
7272+ wav_set_uint32 (buf, 8, WAVE_WAVE);
7373+7474+ wav_set_uint32 (buf, 12, WAVE_FMT);
7575+ wav_set_uint32 (buf, 16, 16);
7676+ wav_set_uint16 (buf, 20, 0x0001);
7777+ wav_set_uint16 (buf, 22, sdrv->channels);
7878+ wav_set_uint32 (buf, 24, sdrv->sample_rate);
7979+ wav_set_uint32 (buf, 28, 2 * sdrv->channels * sdrv->sample_rate);
8080+ wav_set_uint16 (buf, 32, 2 * sdrv->channels);
8181+ wav_set_uint16 (buf, 34, 16);
8282+8383+ wav_set_uint32 (buf, 36, WAVE_DATA);
8484+ wav_set_uint32 (buf, 40, sdrv->wav_cnt);
8585+8686+ if (fwrite (buf, 1, 44, sdrv->wav_fp) != 44) {
8787+ return (1);
8888+ }
8989+9090+ if (fseek (sdrv->wav_fp, sdrv->wav_cnt + 44, SEEK_SET)) {
9191+ return (1);
9292+ }
9393+9494+ return (0);
9595+}
9696+9797+void snd_wav_close (sound_drv_t *sdrv)
9898+{
9999+ if (sdrv->wav_fp != NULL) {
100100+ snd_wav_write_header (sdrv);
101101+ }
102102+}
103103+104104+int snd_wav_write (sound_drv_t *sdrv, const uint16_t *buf, unsigned cnt)
105105+{
106106+ unsigned long bcnt, scnt;
107107+ unsigned char *bbuf;
108108+109109+ if (sdrv->wav_fp == NULL) {
110110+ return (0);
111111+ }
112112+113113+ scnt = (unsigned long) sdrv->channels * (unsigned long) cnt;
114114+ bcnt = 2 * scnt;
115115+116116+ bbuf = snd_get_bbuf (sdrv, bcnt);
117117+118118+ if (buf == NULL) {
119119+ return (1);
120120+ }
121121+122122+ snd_set_buf (bbuf, buf, scnt, sdrv->sample_sign == 0, 0);
123123+124124+ if (fwrite (bbuf, 1, bcnt, sdrv->wav_fp) != bcnt) {
125125+ return (1);
126126+ }
127127+128128+ sdrv->wav_cnt += bcnt;
129129+130130+ return (0);
131131+}
132132+133133+int snd_wav_set_params (sound_drv_t *sdrv, unsigned chn, unsigned long srate, int sign)
134134+{
135135+ if (sdrv->wav_fp == NULL) {
136136+ return (0);
137137+ }
138138+139139+ if (snd_wav_write_header (sdrv)) {
140140+ return (1);
141141+ }
142142+143143+ return (0);
144144+}
145145+146146+int snd_wav_init (sound_drv_t *sdrv, const char *name)
147147+{
148148+ char *wav;
149149+150150+ sdrv->wav_fp = NULL;
151151+ sdrv->wav_cnt = 0;
152152+153153+ wav = drv_get_option (name, "wav");
154154+155155+ if (wav == NULL) {
156156+ return (0);
157157+ }
158158+159159+ if (*wav == 0) {
160160+ return (0);
161161+ }
162162+163163+ sdrv->wav_fp = fopen (wav, "wb");
164164+165165+ free (wav);
166166+167167+ if (sdrv->wav_fp == NULL) {
168168+ return (1);
169169+ }
170170+171171+ return (0);
172172+}
+37
src/drivers/sound/sound-wav.h
···11+/*****************************************************************************
22+ * pce *
33+ *****************************************************************************/
44+55+/*****************************************************************************
66+ * File name: src/drivers/sound/sound-wav.h *
77+ * Created: 2009-10-18 by Hampa Hug <hampa@hampa.ch> *
88+ * Copyright: (C) 2009 Hampa Hug <hampa@hampa.ch> *
99+ *****************************************************************************/
1010+1111+/*****************************************************************************
1212+ * This program is free software. You can redistribute it and / or modify it *
1313+ * under the terms of the GNU General Public License version 2 as published *
1414+ * by the Free Software Foundation. *
1515+ * *
1616+ * This program is distributed in the hope that it will be useful, but *
1717+ * WITHOUT ANY WARRANTY, without even the implied warranty of *
1818+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
1919+ * Public License for more details. *
2020+ *****************************************************************************/
2121+2222+2323+#ifndef PCE_DRIVERS_SOUND_WAV_H
2424+#define PCE_DRIVERS_SOUND_WAV_H 1
2525+2626+2727+#include <drivers/sound/sound.h>
2828+2929+3030+void snd_wav_close (sound_drv_t *sdrv);
3131+int snd_wav_write (sound_drv_t *sdrv, const uint16_t *buf, unsigned cnt);
3232+int snd_wav_set_params (sound_drv_t *sdrv, unsigned chn, unsigned long srate, int sign);
3333+int snd_wav_set_params (sound_drv_t *sdrv, unsigned chn, unsigned long srate, int sign);
3434+int snd_wav_init (sound_drv_t *sdrv, const char *name);
3535+3636+3737+#endif
+435
src/drivers/sound/sound.c
···11+/*****************************************************************************
22+ * pce *
33+ *****************************************************************************/
44+55+/*****************************************************************************
66+ * File name: src/drivers/sound/sound.c *
77+ * Created: 2009-10-17 by Hampa Hug <hampa@hampa.ch> *
88+ * Copyright: (C) 2009-2010 Hampa Hug <hampa@hampa.ch> *
99+ *****************************************************************************/
1010+1111+/*****************************************************************************
1212+ * This program is free software. You can redistribute it and / or modify it *
1313+ * under the terms of the GNU General Public License version 2 as published *
1414+ * by the Free Software Foundation. *
1515+ * *
1616+ * This program is distributed in the hope that it will be useful, but *
1717+ * WITHOUT ANY WARRANTY, without even the implied warranty of *
1818+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
1919+ * Public License for more details. *
2020+ *****************************************************************************/
2121+2222+2323+#include <config.h>
2424+2525+#include <stdlib.h>
2626+#include <string.h>
2727+#include <math.h>
2828+2929+#include <drivers/options.h>
3030+#include <drivers/sound/sound.h>
3131+#include <drivers/sound/sound-wav.h>
3232+3333+3434+#define SND_IIR_MUL 8192
3535+3636+3737+struct snd_drv_list {
3838+ const char *prefix;
3939+ sound_drv_t *(*open) (const char *name);
4040+};
4141+4242+static
4343+struct snd_drv_list drvtab[] = {
4444+ { "null", snd_null_open },
4545+ { "wav", snd_null_open },
4646+ { NULL, NULL }
4747+};
4848+4949+5050+void snd_iir2_init (sound_iir2_t *iir)
5151+{
5252+ unsigned i;
5353+5454+ for (i = 0; i < 3; i++) {
5555+ iir->a[i] = 0;
5656+ iir->b[i] = 0;
5757+ iir->x[i] = 0;
5858+ iir->y[i] = 0;
5959+ }
6060+6161+ iir->a[0] = SND_IIR_MUL;
6262+}
6363+6464+void snd_iir2_reset (sound_iir2_t *iir)
6565+{
6666+ iir->x[0] = 0;
6767+ iir->x[1] = 0;
6868+ iir->x[2] = 0;
6969+7070+ iir->y[0] = 0;
7171+ iir->y[1] = 0;
7272+ iir->y[2] = 0;
7373+}
7474+7575+void snd_iir2_set_lowpass (sound_iir2_t *iir, unsigned long freq, unsigned long srate)
7676+{
7777+ double om, b0;
7878+7979+ snd_iir2_init (iir);
8080+8181+ if ((freq == 0) || (srate == 0)) {
8282+ return;
8383+ }
8484+8585+ if ((2 * freq) >= srate) {
8686+ freq = (srate / 2) - 1;
8787+ }
8888+8989+ om = 1.0 / tan ((3.14159265358979312 * freq) / srate);
9090+ b0 = om * (om + sqrt(2.0)) + 1.0;
9191+9292+ iir->a[0] = (long) (SND_IIR_MUL * 1.0 / b0);
9393+ iir->a[1] = (long) (SND_IIR_MUL * 2.0 / b0);
9494+ iir->a[2] = (long) (SND_IIR_MUL * 1.0 / b0);
9595+9696+ iir->b[0] = (long) (SND_IIR_MUL * 1.0);
9797+ iir->b[1] = (long) (SND_IIR_MUL * 2.0 * (1.0 - om * om) / b0);
9898+ iir->b[2] = (long) (SND_IIR_MUL * (om * (om - sqrt(2.0)) + 1.0) / b0);
9999+}
100100+101101+void snd_iir2_filter (sound_iir2_t *iir, uint16_t *dst, const uint16_t *src,
102102+ unsigned cnt, unsigned ofs, int sign)
103103+{
104104+ long v;
105105+ uint16_t sig;
106106+107107+ sig = sign ? 0x8000 : 0;
108108+109109+ while (cnt > 0) {
110110+ v = *src ^ sig;
111111+ v -= 32768;
112112+113113+ iir->x[2] = iir->x[1];
114114+ iir->x[1] = iir->x[0];
115115+ iir->x[0] = v;
116116+117117+ iir->y[2] = iir->y[1];
118118+ iir->y[1] = iir->y[0];
119119+120120+ iir->y[0] = iir->a[0] * iir->x[0];
121121+ iir->y[0] += iir->a[1] * iir->x[1] + iir->a[2] * iir->x[2];
122122+ iir->y[0] -= iir->b[1] * iir->y[1] + iir->b[2] * iir->y[2];
123123+124124+ iir->y[0] = iir->y[0] / SND_IIR_MUL;
125125+126126+ v = iir->y[0];
127127+ v += 32768;
128128+129129+ if (v < 0) {
130130+ v = 0;
131131+ }
132132+ else if (v > 65535) {
133133+ v = 0xffff;
134134+ }
135135+ else {
136136+ v &= 0xffff;
137137+ }
138138+139139+ *dst = ((uint16_t) v) ^ sig;
140140+141141+ src += ofs;
142142+ dst += ofs;
143143+ cnt -= 1;
144144+ }
145145+}
146146+147147+/*
148148+ * Initialize the low-pass filter in sdrv->lowpass_iir2 with a cut-off
149149+ * frequency of sdrv->lowpass_freq.
150150+ */
151151+static
152152+void snd_fix_lowpass (sound_drv_t *sdrv)
153153+{
154154+ unsigned i;
155155+156156+ for (i = 0; i < sdrv->channels; i++) {
157157+ snd_iir2_set_lowpass (
158158+ &sdrv->lowpass_iir2[i],
159159+ sdrv->lowpass_freq, sdrv->sample_rate
160160+ );
161161+162162+ snd_iir2_reset (&sdrv->lowpass_iir2[i]);
163163+ }
164164+}
165165+166166+unsigned char *snd_get_bbuf (sound_drv_t *sdrv, unsigned long cnt)
167167+{
168168+ unsigned char *tmp;
169169+170170+ if (cnt <= sdrv->bbuf_max) {
171171+ return (sdrv->bbuf);
172172+ }
173173+174174+ tmp = realloc (sdrv->bbuf, cnt);
175175+176176+ if (tmp == NULL) {
177177+ return (NULL);
178178+ }
179179+180180+ sdrv->bbuf = tmp;
181181+ sdrv->bbuf_max = cnt;
182182+183183+ return (sdrv->bbuf);
184184+}
185185+186186+uint16_t *snd_get_sbuf (sound_drv_t *sdrv, unsigned long cnt)
187187+{
188188+ uint16_t *tmp;
189189+190190+ if (cnt <= sdrv->sbuf_max) {
191191+ return (sdrv->sbuf);
192192+ }
193193+194194+ tmp = realloc (sdrv->sbuf, cnt * sizeof (uint16_t));
195195+196196+ if (tmp == NULL) {
197197+ return (NULL);
198198+ }
199199+200200+ sdrv->sbuf = tmp;
201201+ sdrv->sbuf_max = cnt;
202202+203203+ return (sdrv->sbuf);
204204+}
205205+206206+void snd_set_buf (unsigned char *dst, const uint16_t *src, unsigned long cnt,
207207+ int sign, int be)
208208+{
209209+ unsigned long i;
210210+ uint16_t val, sig;
211211+212212+ sig = sign ? 0x8000 : 0x0000;
213213+214214+ if (be) {
215215+ for (i = 0; i < cnt; i++) {
216216+ val = *src ^ sig;
217217+218218+ dst[0] = (val >> 8) & 0xff;
219219+ dst[1] = val & 0xff;
220220+221221+ dst += 2;
222222+ src += 1;
223223+ }
224224+ }
225225+ else {
226226+ for (i = 0; i < cnt; i++) {
227227+ val = *src ^ sig;
228228+229229+ dst[0] = val & 0xff;
230230+ dst[1] = (val >> 8) & 0xff;
231231+232232+ dst += 2;
233233+ src += 1;
234234+ }
235235+ }
236236+}
237237+238238+void snd_init (sound_drv_t *sdrv, void *ext)
239239+{
240240+ sdrv->ext = ext;
241241+242242+ sdrv->channels = 0;
243243+ sdrv->sample_rate = 0;
244244+ sdrv->sample_sign = 0;
245245+246246+ sdrv->lowpass_freq = 0;
247247+248248+ sdrv->bbuf_max = 0;
249249+ sdrv->bbuf = NULL;
250250+251251+ sdrv->sbuf_max = 0;
252252+ sdrv->sbuf = NULL;
253253+254254+ sdrv->wav_fp = NULL;
255255+ sdrv->wav_cnt = 0;
256256+ sdrv->wav_filter = 1;
257257+258258+ sdrv->close = NULL;
259259+260260+ sdrv->write = NULL;
261261+262262+ sdrv->set_params = NULL;
263263+}
264264+265265+void snd_close (sound_drv_t *sdrv)
266266+{
267267+ if (sdrv == NULL) {
268268+ return;
269269+ }
270270+271271+ snd_wav_close (sdrv);
272272+273273+ if (sdrv->close != NULL) {
274274+ sdrv->close (sdrv);
275275+ }
276276+277277+ if (sdrv->sbuf != NULL) {
278278+ free (sdrv->sbuf);
279279+ }
280280+281281+ if (sdrv->bbuf != NULL) {
282282+ free (sdrv->bbuf);
283283+ }
284284+}
285285+286286+const uint16_t *snd_filter (sound_drv_t *sdrv, const uint16_t *buf, unsigned cnt)
287287+{
288288+ unsigned i;
289289+ unsigned long scnt;
290290+ uint16_t *sbuf;
291291+292292+ if (sdrv->lowpass_freq == 0) {
293293+ return (buf);
294294+ }
295295+296296+ scnt = (unsigned long) sdrv->channels * (unsigned long) cnt;
297297+298298+ sbuf = snd_get_sbuf (sdrv, scnt);
299299+300300+ if (sbuf == NULL) {
301301+ return (NULL);
302302+ }
303303+304304+ for (i = 0; i < sdrv->channels; i++) {
305305+ snd_iir2_filter (
306306+ &sdrv->lowpass_iir2[i], sbuf + i, buf + i,
307307+ cnt, sdrv->channels, sdrv->sample_sign
308308+ );
309309+ }
310310+311311+ return (sbuf);
312312+}
313313+314314+int snd_write (sound_drv_t *sdrv, const uint16_t *buf, unsigned cnt)
315315+{
316316+ int r;
317317+ const uint16_t *sbuf;
318318+319319+ if ((sdrv == NULL) || (sdrv->write == NULL)) {
320320+ return (1);
321321+ }
322322+323323+ sbuf = snd_filter (sdrv, buf, cnt);
324324+325325+ r = sdrv->write (sdrv, sbuf, cnt);
326326+327327+ snd_wav_write (sdrv, sdrv->wav_filter ? sbuf : buf, cnt);
328328+329329+ return (r);
330330+}
331331+332332+/*
333333+ * Check if new parameters differ from current parameters.
334334+ * Returns 0 if they differ.
335335+ */
336336+static
337337+int snd_check_params (sound_drv_t *sdrv, unsigned chn, unsigned long srate, int sign)
338338+{
339339+ if (sdrv->channels != chn) {
340340+ return (0);
341341+ }
342342+343343+ if (sdrv->sample_rate != srate) {
344344+ return (0);
345345+ }
346346+347347+ if (sdrv->sample_sign != sign) {
348348+ return (0);
349349+ }
350350+351351+ return (1);
352352+}
353353+354354+int snd_set_params (sound_drv_t *sdrv, unsigned chn, unsigned long srate, int sign)
355355+{
356356+ if (sdrv == NULL) {
357357+ return (1);
358358+ }
359359+360360+ if (sdrv->set_params == NULL) {
361361+ return (1);
362362+ }
363363+364364+ sign = (sign != 0);
365365+366366+ if (chn > SND_CHN_MAX) {
367367+ return (1);
368368+ }
369369+ if (snd_check_params (sdrv, chn, srate, sign)) {
370370+ return (0);
371371+ }
372372+373373+ if (sdrv->set_params (sdrv, chn, srate, sign)) {
374374+ return (1);
375375+ }
376376+377377+ sdrv->channels = chn;
378378+ sdrv->sample_rate = srate;
379379+ sdrv->sample_sign = sign;
380380+381381+ if (snd_wav_set_params (sdrv, chn, srate, sign)) {
382382+ return (1);
383383+ }
384384+385385+ snd_fix_lowpass (sdrv);
386386+387387+ return (0);
388388+}
389389+390390+static
391391+sound_drv_t *snd_open_sdrv (sound_drv_t *sdrv, const char *name)
392392+{
393393+ if (sdrv == NULL) {
394394+ return (NULL);
395395+ }
396396+397397+ if (snd_wav_init (sdrv, name)) {
398398+ snd_close (sdrv);
399399+ return (NULL);
400400+ }
401401+402402+ sdrv->wav_filter = drv_get_option_bool (name, "wavfilter", 1);
403403+404404+ sdrv->lowpass_freq = drv_get_option_uint (name, "lowpass", 0);
405405+406406+ snd_fix_lowpass (sdrv);
407407+408408+ return (sdrv);
409409+}
410410+411411+sound_drv_t *snd_open (const char *name)
412412+{
413413+ unsigned i;
414414+ const char *s, *d;
415415+416416+ i = 0;
417417+418418+ while (drvtab[i].prefix != NULL) {
419419+ s = name;
420420+ d = drvtab[i].prefix;
421421+422422+ while ((*d != 0) && (*d == *s)) {
423423+ d += 1;
424424+ s += 1;
425425+ }
426426+427427+ if ((*d == 0) && ((*s == ':') || (*s == 0))) {
428428+ return (snd_open_sdrv (drvtab[i].open (name), name));
429429+ }
430430+431431+ i += 1;
432432+ }
433433+434434+ return (NULL);
435435+}
+181
src/drivers/sound/sound.h
···11+/*****************************************************************************
22+ * pce *
33+ *****************************************************************************/
44+55+/*****************************************************************************
66+ * File name: src/drivers/sound/sound.h *
77+ * Created: 2009-10-17 by Hampa Hug <hampa@hampa.ch> *
88+ * Copyright: (C) 2009-2010 Hampa Hug <hampa@hampa.ch> *
99+ *****************************************************************************/
1010+1111+/*****************************************************************************
1212+ * This program is free software. You can redistribute it and / or modify it *
1313+ * under the terms of the GNU General Public License version 2 as published *
1414+ * by the Free Software Foundation. *
1515+ * *
1616+ * This program is distributed in the hope that it will be useful, but *
1717+ * WITHOUT ANY WARRANTY, without even the implied warranty of *
1818+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
1919+ * Public License for more details. *
2020+ *****************************************************************************/
2121+2222+2323+#ifndef PCE_DRIVERS_SOUND_SOUND_H
2424+#define PCE_DRIVERS_SOUND_SOUND_H 1
2525+2626+2727+#include <stdio.h>
2828+#include <stdint.h>
2929+3030+3131+#define SND_CHN_MAX 16
3232+3333+3434+/*!***************************************************************************
3535+ * @short A second order IIR filter
3636+ *****************************************************************************/
3737+typedef struct {
3838+ long a[3];
3939+ long b[3];
4040+ long x[3];
4141+ long y[3];
4242+} sound_iir2_t;
4343+4444+4545+/*!***************************************************************************
4646+ * @short The sound driver context
4747+ *****************************************************************************/
4848+typedef struct sound_drv_t {
4949+ void *ext;
5050+5151+ unsigned channels;
5252+ unsigned long sample_rate;
5353+ int sample_sign;
5454+5555+ unsigned long lowpass_freq;
5656+ sound_iir2_t lowpass_iir2[SND_CHN_MAX];
5757+5858+ unsigned long bbuf_max;
5959+ unsigned char *bbuf;
6060+6161+ unsigned long sbuf_max;
6262+ uint16_t *sbuf;
6363+6464+ FILE *wav_fp;
6565+ unsigned long wav_cnt;
6666+ char wav_filter;
6767+6868+ void (*close) (struct sound_drv_t *sdrv);
6969+7070+ int (*write) (struct sound_drv_t *sdrv, const uint16_t *buf, unsigned cnt);
7171+7272+ int (*set_params) (struct sound_drv_t *sdrv,
7373+ unsigned chn, unsigned long srate, int sign
7474+ );
7575+} sound_drv_t;
7676+7777+7878+/*!***************************************************************************
7979+ * @short Initialize an IIR2 filter
8080+ *****************************************************************************/
8181+void snd_iir2_init (sound_iir2_t *iir);
8282+8383+/*!***************************************************************************
8484+ * @short Reset an IIR2 filter
8585+ *****************************************************************************/
8686+void snd_iir2_reset (sound_iir2_t *iir);
8787+8888+/*!***************************************************************************
8989+ * @short Initialize a low-pass IIR filter
9090+ * @param freq The cut-off frequency
9191+ * @param srate The sample rate
9292+ *****************************************************************************/
9393+void snd_iir2_set_lowpass (sound_iir2_t *iir,
9494+ unsigned long freq, unsigned long srate
9595+);
9696+9797+/*!***************************************************************************
9898+ * @short Filter samples with an IIR2 filter
9999+ * @param dst The destination buffer
100100+ * @param src The source buffer
101101+ * @param cnt The sample count
102102+ * @param ofs The sample offset in both src and dst
103103+ * @param sign The sample signedness in both src and dst
104104+ *****************************************************************************/
105105+void snd_iir2_filter (sound_iir2_t *iir,
106106+ uint16_t *dst, const uint16_t *src, unsigned cnt, unsigned ofs, int sign
107107+);
108108+109109+110110+/*!***************************************************************************
111111+ * @short Get a temporary byte buffer
112112+ * @param cnt The requested buffer size in bytes
113113+ *
114114+ * The buffer returned is sdrv->bbuf. Subsequent calls to this function
115115+ * will invalidate the buffers returned by earlier calls.
116116+ *****************************************************************************/
117117+unsigned char *snd_get_bbuf (sound_drv_t *sdrv, unsigned long cnt);
118118+119119+/*!***************************************************************************
120120+ * @short Get a temporary sample buffer
121121+ * @param cnt The requested buffer size in samples
122122+ *
123123+ * The buffer returned is sdrv->sbuf. Subsequent calls to this function
124124+ * will invalidate the buffers returned by earlier calls.
125125+ *****************************************************************************/
126126+uint16_t *snd_get_sbuf (sound_drv_t *sdrv, unsigned long cnt);
127127+128128+/*!***************************************************************************
129129+ * @short Store samples in a byte buffer
130130+ * @param dst The destination byte buffer of size (2 * cnt)
131131+ * @param src The source sample buffer
132132+ * @param cnt The number of samples in src
133133+ * @param sign If true the sign of samples is inverted
134134+ * @param be If true samples are stored in big endian format.
135135+ *****************************************************************************/
136136+void snd_set_buf (unsigned char *dst, const uint16_t *src, unsigned long cnt,
137137+ int sign, int be
138138+);
139139+140140+141141+void snd_init (sound_drv_t *sdrv, void *ext);
142142+143143+void snd_close (sound_drv_t *sdrv);
144144+145145+/*!***************************************************************************
146146+ * @short Filter samples
147147+ * @param buf The source samples
148148+ * @param cnt The number of samples in buf
149149+ *
150150+ * The samples in buf are filtered by sdrv->lowpass_iir2. The buffer returned
151151+ * is sdrv->sbuf.
152152+ *****************************************************************************/
153153+const uint16_t *snd_filter (sound_drv_t *sdrv, const uint16_t *buf, unsigned cnt);
154154+155155+/*!***************************************************************************
156156+ * @short Write samples
157157+ * @param buf The sample buffer
158158+ * @param cnt The sample count per channel
159159+ *
160160+ * The total number of samples in buf is (channels * cnt).
161161+ *****************************************************************************/
162162+int snd_write (sound_drv_t *sdrv, const uint16_t *buf, unsigned cnt);
163163+164164+/*!***************************************************************************
165165+ * @short Set the sound parameters
166166+ * @param chn The number of channels
167167+ * @param srate The sample rate in Herz
168168+ * @param sign If true, samples are signed otherwise unsigned
169169+ *
170170+ * This function must be called after snd_open() and before the first call
171171+ * to snd_write().
172172+ *****************************************************************************/
173173+int snd_set_params (sound_drv_t *sdrv, unsigned chn, unsigned long srate, int sign);
174174+175175+176176+sound_drv_t *snd_open (const char *name);
177177+178178+sound_drv_t *snd_null_open (const char *name);
179179+180180+181181+#endif