fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

speaker: Add a generic beeper speaker implementation

+416 -1
+6
Makefile.dep
··· 2304 2304 src/devices/slip.h \ 2305 2305 src/lib/tun.h 2306 2306 2307 + src/devices/speaker.o: src/devices/speaker.c \ 2308 + src/config.h \ 2309 + src/devices/speaker.h \ 2310 + src/drivers/sound/filter.h \ 2311 + src/drivers/sound/sound.h 2312 + 2307 2313 src/devices/video/cga.o: src/devices/video/cga.c \ 2308 2314 src/chipset/e6845.h \ 2309 2315 src/devices/memory.h \
+3 -1
src/devices/Makefile.inc
··· 17 17 pci \ 18 18 pci-ata \ 19 19 serport \ 20 - slip 20 + slip \ 21 + speaker 21 22 22 23 DEV_SRC := $(foreach f,$(DEV_BAS),$(rel)/$(f).c) 23 24 DEV_OBJ := $(foreach f,$(DEV_BAS),$(rel)/$(f).o) ··· 38 39 $(rel)/pci-ata.o: $(rel)/pci-ata.c 39 40 $(rel)/serport.o: $(rel)/serport.c 40 41 $(rel)/slip.o: $(rel)/slip.c 42 + $(rel)/speaker.o: $(rel)/speaker.c
+319
src/devices/speaker.c
··· 1 + /***************************************************************************** 2 + * pce * 3 + *****************************************************************************/ 4 + 5 + /***************************************************************************** 6 + * File name: src/devices/speaker.c * 7 + * Created: 2022-02-08 by Hampa Hug <hampa@hampa.ch> * 8 + * Copyright: (C) 2021-2024 Hampa Hug <hampa@hampa.ch> * 9 + *****************************************************************************/ 10 + 11 + /***************************************************************************** 12 + * This program is free software. You can redistribute it and / or modify it * 13 + * under the terms of the GNU General Public License version 2 as published * 14 + * by the Free Software Foundation. * 15 + * * 16 + * This program is distributed in the hope that it will be useful, but * 17 + * WITHOUT ANY WARRANTY, without even the implied warranty of * 18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * 19 + * Public License for more details. * 20 + *****************************************************************************/ 21 + 22 + 23 + #include <config.h> 24 + 25 + #include <devices/speaker.h> 26 + 27 + #include <stdlib.h> 28 + 29 + #include <drivers/sound/sound.h> 30 + 31 + 32 + #ifndef DEBUG_SPEAKER 33 + #define DEBUG_SPEAKER 0 34 + #endif 35 + 36 + 37 + static void spk_flush (speaker_t *spk); 38 + 39 + 40 + void spk_init (speaker_t *spk, int level) 41 + { 42 + spk->drv = NULL; 43 + 44 + spk->srate = 44100; 45 + spk->input_clock = 1000000; 46 + spk->speed_mul = 1; 47 + 48 + spk->enabled = 0; 49 + 50 + spk->speaker_inp = level; 51 + spk->speaker_val = 0; 52 + spk->sample_acc = 0; 53 + 54 + spk->timeout_val = 0; 55 + spk->timeout_clk = 0; 56 + spk->timeout_max = 5 * spk->input_clock; 57 + 58 + spk->clk = 0; 59 + spk->rem = 0; 60 + 61 + spk->lowpass_freq = 0; 62 + 63 + snd_iir2_init (&spk->iir); 64 + 65 + spk->buf_cnt = 0; 66 + 67 + spk_set_volume (spk, 500); 68 + } 69 + 70 + void spk_free (speaker_t *spk) 71 + { 72 + spk_flush (spk); 73 + 74 + if (spk->drv != NULL) { 75 + snd_close (spk->drv); 76 + } 77 + } 78 + 79 + speaker_t *spk_new (int level) 80 + { 81 + speaker_t *spk; 82 + 83 + if ((spk = malloc (sizeof (speaker_t))) == NULL) { 84 + return (NULL); 85 + } 86 + 87 + spk_init (spk, level); 88 + 89 + return (spk); 90 + } 91 + 92 + void spk_del (speaker_t *spk) 93 + { 94 + if (spk != NULL) { 95 + spk_free (spk); 96 + free (spk); 97 + } 98 + } 99 + 100 + void spk_set_clock_fct (speaker_t *spk, void *ext, void *fct) 101 + { 102 + spk->get_clock_ext = ext; 103 + spk->get_clock = fct; 104 + } 105 + 106 + void spk_set_input_clock (speaker_t *spk, unsigned long clk) 107 + { 108 + spk->input_clock = clk; 109 + spk->timeout_max = 5 * clk; 110 + } 111 + 112 + void spk_set_speed (speaker_t *spk, unsigned mul) 113 + { 114 + if (mul > 0) { 115 + spk->speed_mul = mul; 116 + } 117 + } 118 + 119 + int spk_set_driver (speaker_t *spk, const char *driver, unsigned long srate) 120 + { 121 + if (spk->drv != NULL) { 122 + snd_close (spk->drv); 123 + } 124 + 125 + if ((spk->drv = snd_open (driver)) == NULL) { 126 + return (1); 127 + } 128 + 129 + spk->srate = srate; 130 + 131 + snd_iir2_set_lowpass (&spk->iir, spk->lowpass_freq, spk->srate); 132 + 133 + if (snd_set_params (spk->drv, 1, srate, 1)) { 134 + snd_close (spk->drv); 135 + spk->drv = NULL; 136 + return (1); 137 + } 138 + 139 + return (0); 140 + } 141 + 142 + void spk_set_lowpass (speaker_t *spk, unsigned long freq) 143 + { 144 + spk->lowpass_freq = freq; 145 + 146 + snd_iir2_set_lowpass (&spk->iir, spk->lowpass_freq, spk->srate); 147 + } 148 + 149 + void spk_set_volume (speaker_t *spk, unsigned vol) 150 + { 151 + if (vol > 1000) { 152 + vol = 1000; 153 + } 154 + 155 + vol = (32768UL * vol) / 1000; 156 + 157 + if (vol > 32767) { 158 + vol = 32767; 159 + } 160 + 161 + spk->val_p = 0x8000 + vol; 162 + spk->val_n = 0x8000 - vol; 163 + } 164 + 165 + void spk_set_input (speaker_t *spk, int val) 166 + { 167 + spk_check (spk); 168 + 169 + val = (val != 0); 170 + 171 + if (spk->speaker_inp == val) { 172 + return; 173 + } 174 + 175 + spk->speaker_inp = val; 176 + spk->speaker_val = val ? spk->val_p : spk->val_n; 177 + 178 + #if DEBUG_SPEAKER >= 1 179 + fprintf (stderr, "speaker input %d (%04X)\n", 180 + spk->speaker_inp, spk->speaker_val 181 + ); 182 + #endif 183 + } 184 + 185 + static 186 + void spk_write (speaker_t *spk, uint16_t *buf, unsigned cnt) 187 + { 188 + if (spk->lowpass_freq > 0) { 189 + snd_iir2_filter (&spk->iir, buf, buf, cnt, 1, 1); 190 + } 191 + 192 + snd_write (spk->drv, buf, cnt); 193 + } 194 + 195 + static 196 + void spk_put_sample (speaker_t *spk, uint16_t val, unsigned long cnt) 197 + { 198 + unsigned idx; 199 + 200 + if (spk->drv == NULL) { 201 + return; 202 + } 203 + 204 + idx = spk->buf_cnt; 205 + 206 + while (cnt > 0) { 207 + spk->buf[idx++] = val; 208 + 209 + if (idx >= SPEAKER_BUF) { 210 + spk_write (spk, spk->buf, idx); 211 + 212 + idx = 0; 213 + } 214 + 215 + cnt -= 1; 216 + } 217 + 218 + spk->buf_cnt = idx; 219 + } 220 + 221 + static 222 + void spk_flush (speaker_t *spk) 223 + { 224 + if (spk->buf_cnt == 0) { 225 + return; 226 + } 227 + 228 + spk_write (spk, spk->buf, spk->buf_cnt); 229 + 230 + snd_iir2_reset (&spk->iir); 231 + 232 + spk->buf_cnt = 0; 233 + } 234 + 235 + static 236 + void spk_on (speaker_t *spk) 237 + { 238 + #if DEBUG_SPEAKER >= 1 239 + fprintf (stderr, "speaker on (%lu)\n", spk->input_clock); 240 + #endif 241 + 242 + spk->enabled = 1; 243 + spk->sample_acc = 0; 244 + spk->timeout_val = spk->speaker_val; 245 + spk->timeout_clk = 0; 246 + spk->rem = 0; 247 + 248 + /* Fill the sound buffer a bit so we don't underrun immediately */ 249 + spk_put_sample (spk, 0, spk->srate / 16); 250 + } 251 + 252 + static 253 + void spk_off (speaker_t *spk) 254 + { 255 + #if DEBUG_SPEAKER >= 1 256 + fprintf (stderr, "speaker off\n"); 257 + #endif 258 + 259 + spk->enabled = 0; 260 + 261 + spk_flush (spk); 262 + } 263 + 264 + void spk_check (speaker_t *spk) 265 + { 266 + unsigned long clk, tmp, acc; 267 + 268 + tmp = spk->get_clock (spk->get_clock_ext); 269 + clk = tmp - spk->clk; 270 + spk->clk = tmp; 271 + 272 + if (spk->enabled == 0) { 273 + if (spk->timeout_val != spk->speaker_val) { 274 + spk_on (spk); 275 + } 276 + else { 277 + return; 278 + } 279 + } 280 + 281 + if (spk->timeout_val == spk->speaker_val) { 282 + spk->timeout_clk += clk; 283 + 284 + if (spk->timeout_clk > spk->timeout_max) { 285 + spk_off (spk); 286 + return; 287 + } 288 + } 289 + else { 290 + spk->timeout_val = spk->speaker_val; 291 + spk->timeout_clk = clk; 292 + } 293 + 294 + acc = spk->sample_acc; 295 + 296 + while (clk >= spk->speed_mul) { 297 + acc = ((256 - 6) * acc + 6 * spk->speaker_val) / 256; 298 + 299 + spk->rem += spk->srate; 300 + 301 + if (spk->rem >= spk->input_clock) { 302 + spk_put_sample (spk, acc ^ 0x8000, 1); 303 + spk->rem -= spk->input_clock; 304 + 305 + if (spk->speaker_val < 0x8000) { 306 + spk->speaker_val = (255UL * spk->speaker_val + 0x8000 + 255) / 256; 307 + } 308 + else { 309 + spk->speaker_val = (255UL * spk->speaker_val + 0x8000) / 256; 310 + } 311 + } 312 + 313 + clk -= spk->speed_mul; 314 + } 315 + 316 + spk->clk -= clk; 317 + 318 + spk->sample_acc = acc; 319 + }
+88
src/devices/speaker.h
··· 1 + /***************************************************************************** 2 + * pce * 3 + *****************************************************************************/ 4 + 5 + /***************************************************************************** 6 + * File name: src/devices/speaker.h * 7 + * Created: 2022-02-08 by Hampa Hug <hampa@hampa.ch> * 8 + * Copyright: (C) 2022-2024 Hampa Hug <hampa@hampa.ch> * 9 + *****************************************************************************/ 10 + 11 + /***************************************************************************** 12 + * This program is free software. You can redistribute it and / or modify it * 13 + * under the terms of the GNU General Public License version 2 as published * 14 + * by the Free Software Foundation. * 15 + * * 16 + * This program is distributed in the hope that it will be useful, but * 17 + * WITHOUT ANY WARRANTY, without even the implied warranty of * 18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * 19 + * Public License for more details. * 20 + *****************************************************************************/ 21 + 22 + 23 + #ifndef PCE_DEVICES_SPEAKER_H 24 + #define PCE_DEVICES_SPEAKER_H 1 25 + 26 + 27 + #include <drivers/sound/sound.h> 28 + 29 + 30 + #define SPEAKER_BUF 1024 31 + 32 + 33 + typedef struct { 34 + sound_drv_t *drv; 35 + 36 + unsigned long srate; 37 + unsigned long input_clock; 38 + unsigned speed_mul; 39 + 40 + char enabled; 41 + 42 + int speaker_inp; 43 + uint16_t speaker_val; 44 + uint16_t sample_acc; 45 + 46 + uint16_t val_n; 47 + uint16_t val_p; 48 + 49 + uint16_t timeout_val; 50 + unsigned long timeout_clk; 51 + unsigned long timeout_max; 52 + 53 + unsigned long clk; 54 + unsigned long rem; 55 + 56 + unsigned long lowpass_freq; 57 + sound_iir2_t iir; 58 + 59 + unsigned buf_cnt; 60 + uint16_t buf[SPEAKER_BUF]; 61 + 62 + void *get_clock_ext; 63 + unsigned long (*get_clock) (void *ext); 64 + } speaker_t; 65 + 66 + 67 + void spk_init (speaker_t *spk, int level); 68 + void spk_free (speaker_t *spk); 69 + 70 + speaker_t *_spk_new (int level); 71 + void spk_del (speaker_t *spk); 72 + 73 + void spk_set_clock_fct (speaker_t *spk, void *ext, void *fct); 74 + 75 + void spk_set_input_clock (speaker_t *spk, unsigned long clk); 76 + 77 + int spk_set_driver (speaker_t *spk, const char *driver, unsigned long srate); 78 + 79 + void spk_set_lowpass (speaker_t *spk, unsigned long freq); 80 + 81 + void spk_set_volume (speaker_t *spk, unsigned vol); 82 + 83 + void spk_set_input (speaker_t *spk, int val); 84 + 85 + void spk_check (speaker_t *spk); 86 + 87 + 88 + #endif