maug
Quick and dirty C mini-augmentation library.
Loading...
Searching...
No Matches
retrosnd.h
Go to the documentation of this file.
1
2#ifndef RETROSND_H
3#define RETROSND_H
4
32
33#ifndef RETROSND_CHANNEL_CT_MAX
34# define RETROSND_CHANNEL_CT_MAX 4
35#endif /* !RETROSND_CHANNEL_CT_MAX */
36
37#ifndef RETROSND_TRACE_LVL
38# define RETROSND_TRACE_LVL 0
39#endif /* !RETROSND_TRACE_LVL */
40
41#ifndef RETROSND_REG_TRACE_LVL
42# define RETROSND_REG_TRACE_LVL 0
43#endif /* !RETROSND_REG_TRACE_LVL */
44
45#ifndef RETROSND_SAMPLES_CT
46# define RETROSND_SAMPLES_CT 2048
47#endif /* !RETROSND_SAMPLES_CT */
48
49#ifdef RETROSND_SAMPLE_22050
50# define RETROSND_SAMPLE_RATE 22050
51#elif defined( RETROSND_SAMPLE_44100 )
52/* Specify the sample rate as a number based on existends of predefined flag.
53 */
54# define RETROSND_SAMPLE_RATE 44100
55#endif /* RETROSND_SAMPLE_44100 */
56
58 uint8_t flags;
62 int8_t voice;
66 uint8_t note;
70 uint8_t vol;
71 uint8_t noise_time;
72 int16_t noise_last;
76 uint32_t phase;
77
78 retroflat_ms_t deadline;
79};
80
88 size_t sz;
90 size_t total_sz;
91 uint8_t notes_ct;
92 int8_t current_note_idx;
93 int16_t ms_per_note;
94 retroflat_ms_t next_note_at;
95 uint8_t notes[][RETROSND_CHANNEL_CT_MAX];
96};
97
103
108#define RETROSND_FLAG_INIT 0x01
109 /* maug_retrosnd_flags */
111
112#define RETROSND_VOICE_BREATH 122
113
114#define RETROSND_VOICE_SEASHORE 123
115
116#define RETROSND_VOICE_BIRD_TWEET 124
117
118#define RETROSND_VOICE_PHONE_RING 125
119
120#define RETROSND_VOICE_HELICOPTER 126
121
122#define RETROSND_VOICE_APPLAUSE 127
123
128#define RETROSND_VOICE_GUNSHOT 128
129
130#define RETROSND_CONTROL_VOL 7
131
141
145void retrosnd_set_sf_bank( const char* filename_in );
146
147void retrosnd_set_voice( uint8_t channel, uint8_t voice );
148
149void retrosnd_set_control( uint8_t channel, uint8_t key, uint8_t val );
150
151void retrosnd_note_on( uint8_t channel, uint8_t pitch, uint8_t vel );
152
153void retrosnd_note_off( uint8_t channel, uint8_t pitch, uint8_t vel );
154
155void retrosnd_shutdown( void );
156
157void retrosnd_pump( void );
158
159void retrosnd_note_on_deadline(
160 uint8_t channel, uint8_t pitch, retroflat_ms_t after );
161
162MERROR_RETVAL retrosnd_tune_init(
163 MAUG_MHANDLE* p_tune_h, size_t notes_ct, uint16_t ms_per_note );
164
175
176void retrosnd_tune_seek( struct RETROSND_TUNE* tune, int8_t idx );
177
178MERROR_RETVAL retrosnd_tune_set_note(
179 struct RETROSND_TUNE*, int channel, int index, int8_t note );
180
181#define retrosnd_tune_get_note( tune, channel, idx ) \
182 ((tune)->notes[idx][channel])
183
190int16_t _retrosnd_generate_note( struct RETROSND_CHANNEL* channels );
191
198 struct RETROSND_CHANNEL* channel, uint8_t key, uint8_t val );
199
200#define RETROSND_TUNE_NOTE_DISABLED (255)
201
202#define RETROSND_NOTES_START (36)
203
204#define RETROSND_NOTES_OCTAVE_SZ (12)
205
206#define RETROSND_NOTES_SZ (RETROSND_NOTES_OCTAVE_SZ * 3)
207
208#define RETROSND_NOTES_OCTAVE_MIDDLE (48)
209
210#define RETROSND_NOTES_TABLE( f ) \
211 f( 36, C2 ) \
212 f( 37, D2F ) \
213 f( 38, D2 ) \
214 f( 39, E2F ) \
215 f( 40, E2 ) \
216 f( 41, F2 ) \
217 f( 42, G2F ) \
218 f( 43, G2 ) \
219 f( 44, A2F ) \
220 f( 45, A2 ) \
221 f( 46, B2F ) \
222 f( 47, B2 ) \
223 f( 48, C3 ) \
224 f( 49, D3F ) \
225 f( 50, D3 ) \
226 f( 51, E3F ) \
227 f( 52, E3 ) \
228 f( 53, F3 ) \
229 f( 54, G3F ) \
230 f( 55, G3 ) \
231 f( 56, A3F ) \
232 f( 57, A3 ) \
233 f( 58, B3F ) \
234 f( 59, B3 ) \
235 f( 60, C4 ) \
236 f( 61, D4F ) \
237 f( 62, D4 ) \
238 f( 63, E4F ) \
239 f( 64, E4 ) \
240 f( 65, F4 ) \
241 f( 66, G4F ) \
242 f( 67, G4 ) \
243 f( 68, A4F ) \
244 f( 69, A4 ) \
245 f( 70, B4F ) \
246 f( 71, B4 )
247 /* maug_retrosnd */
249
250#ifdef RETROSND_C
251
252#define RETROSND_NOTES_TABLE_CONST_NAMES( num, name ) \
253 #name,
254
255MAUG_CONST char* gc_retrosnd_note_names[RETROSND_NOTES_SZ] = {
256RETROSND_NOTES_TABLE( RETROSND_NOTES_TABLE_CONST_NAMES )
257};
258
259#define RETROSND_NOTES_TABLE_CONST_CONSTS( num, name ) \
260 MAUG_CONST int8_t RSN_ ## name = num;
261
262RETROSND_NOTES_TABLE( RETROSND_NOTES_TABLE_CONST_CONSTS )
263
264#ifdef RETROSND_SAMPLE_22050
265
266uint32_t gc_phase_inc[] = {
267 24, /* Idx: 0, Freq: 8.175799 */
268 25, /* Idx: 1, Freq: 8.661957 */
269 27, /* Idx: 2, Freq: 9.177024 */
270 28, /* Idx: 3, Freq: 9.722718 */
271 30, /* Idx: 4, Freq: 10.300861 */
272 32, /* Idx: 5, Freq: 10.913382 */
273 34, /* Idx: 6, Freq: 11.562326 */
274 36, /* Idx: 7, Freq: 12.249857 */
275 38, /* Idx: 8, Freq: 12.978272 */
276 40, /* Idx: 9, Freq: 13.750000 */
277 43, /* Idx: 10, Freq: 14.567618 */
278 45, /* Idx: 11, Freq: 15.433853 */
279 48, /* Idx: 12, Freq: 16.351598 */
280 51, /* Idx: 13, Freq: 17.323914 */
281 54, /* Idx: 14, Freq: 18.354048 */
282 57, /* Idx: 15, Freq: 19.445436 */
283 61, /* Idx: 16, Freq: 20.601722 */
284 64, /* Idx: 17, Freq: 21.826764 */
285 68, /* Idx: 18, Freq: 23.124651 */
286 72, /* Idx: 19, Freq: 24.499715 */
287 77, /* Idx: 20, Freq: 25.956544 */
288 81, /* Idx: 21, Freq: 27.500000 */
289 86, /* Idx: 22, Freq: 29.135235 */
290 91, /* Idx: 23, Freq: 30.867706 */
291 97, /* Idx: 24, Freq: 32.703196 */
292 102, /* Idx: 25, Freq: 34.647829 */
293 109, /* Idx: 26, Freq: 36.708096 */
294 115, /* Idx: 27, Freq: 38.890873 */
295 122, /* Idx: 28, Freq: 41.203445 */
296 129, /* Idx: 29, Freq: 43.653529 */
297 137, /* Idx: 30, Freq: 46.249303 */
298 145, /* Idx: 31, Freq: 48.999429 */
299 154, /* Idx: 32, Freq: 51.913087 */
300 163, /* Idx: 33, Freq: 55.000000 */
301 173, /* Idx: 34, Freq: 58.270470 */
302 183, /* Idx: 35, Freq: 61.735413 */
303 194, /* Idx: 36, Freq: 65.406391 */
304 205, /* Idx: 37, Freq: 69.295658 */
305 218, /* Idx: 38, Freq: 73.416192 */
306 231, /* Idx: 39, Freq: 77.781746 */
307 244, /* Idx: 40, Freq: 82.406889 */
308 259, /* Idx: 41, Freq: 87.307058 */
309 274, /* Idx: 42, Freq: 92.498606 */
310 291, /* Idx: 43, Freq: 97.998859 */
311 308, /* Idx: 44, Freq: 103.826174 */
312 326, /* Idx: 45, Freq: 110.000000 */
313 346, /* Idx: 46, Freq: 116.540940 */
314 366, /* Idx: 47, Freq: 123.470825 */
315 388, /* Idx: 48, Freq: 130.812783 */
316 411, /* Idx: 49, Freq: 138.591315 */
317 436, /* Idx: 50, Freq: 146.832384 */
318 462, /* Idx: 51, Freq: 155.563492 */
319 489, /* Idx: 52, Freq: 164.813778 */
320 518, /* Idx: 53, Freq: 174.614116 */
321 549, /* Idx: 54, Freq: 184.997211 */
322 582, /* Idx: 55, Freq: 195.997718 */
323 617, /* Idx: 56, Freq: 207.652349 */
324 653, /* Idx: 57, Freq: 220.000000 */
325 692, /* Idx: 58, Freq: 233.081881 */
326 733, /* Idx: 59, Freq: 246.941651 */
327 777, /* Idx: 60, Freq: 261.625565 */
328 823, /* Idx: 61, Freq: 277.182631 */
329 872, /* Idx: 62, Freq: 293.664768 */
330 924, /* Idx: 63, Freq: 311.126984 */
331 979, /* Idx: 64, Freq: 329.627557 */
332 1037, /* Idx: 65, Freq: 349.228231 */
333 1099, /* Idx: 66, Freq: 369.994423 */
334 1165, /* Idx: 67, Freq: 391.995436 */
335 1234, /* Idx: 68, Freq: 415.304698 */
336 1307, /* Idx: 69, Freq: 440.000000 */
337 1385, /* Idx: 70, Freq: 466.163762 */
338 1467, /* Idx: 71, Freq: 493.883301 */
339 1555, /* Idx: 72, Freq: 523.251131 */
340 1647, /* Idx: 73, Freq: 554.365262 */
341 1745, /* Idx: 74, Freq: 587.329536 */
342 1849, /* Idx: 75, Freq: 622.253967 */
343 1959, /* Idx: 76, Freq: 659.255114 */
344 2075, /* Idx: 77, Freq: 698.456463 */
345 2199, /* Idx: 78, Freq: 739.988845 */
346 2330, /* Idx: 79, Freq: 783.990872 */
347 2468, /* Idx: 80, Freq: 830.609395 */
348 2615, /* Idx: 81, Freq: 880.000000 */
349 2771, /* Idx: 82, Freq: 932.327523 */
350 2935, /* Idx: 83, Freq: 987.766603 */
351 3110, /* Idx: 84, Freq: 1046.502261 */
352 3295, /* Idx: 85, Freq: 1108.730524 */
353 3491, /* Idx: 86, Freq: 1174.659072 */
354 3698, /* Idx: 87, Freq: 1244.507935 */
355 3918, /* Idx: 88, Freq: 1318.510228 */
356 4151, /* Idx: 89, Freq: 1396.912926 */
357 4398, /* Idx: 90, Freq: 1479.977691 */
358 4660, /* Idx: 91, Freq: 1567.981744 */
359 4937, /* Idx: 92, Freq: 1661.218790 */
360 5230, /* Idx: 93, Freq: 1760.000000 */
361 5542, /* Idx: 94, Freq: 1864.655046 */
362 5871, /* Idx: 95, Freq: 1975.533205 */
363 6220, /* Idx: 96, Freq: 2093.004522 */
364 6590, /* Idx: 97, Freq: 2217.461048 */
365 6982, /* Idx: 98, Freq: 2349.318143 */
366 7397, /* Idx: 99, Freq: 2489.015870 */
367 7837, /* Idx: 100, Freq: 2637.020455 */
368 8303, /* Idx: 101, Freq: 2793.825851 */
369 8797, /* Idx: 102, Freq: 2959.955382 */
370 9320, /* Idx: 103, Freq: 3135.963488 */
371 9874, /* Idx: 104, Freq: 3322.437581 */
372 10461, /* Idx: 105, Freq: 3520.000000 */
373 11084, /* Idx: 106, Freq: 3729.310092 */
374 11743, /* Idx: 107, Freq: 3951.066410 */
375 12441, /* Idx: 108, Freq: 4186.009045 */
376 13181, /* Idx: 109, Freq: 4434.922096 */
377 13965, /* Idx: 110, Freq: 4698.636287 */
378 14795, /* Idx: 111, Freq: 4978.031740 */
379 15675, /* Idx: 112, Freq: 5274.040911 */
380 16607, /* Idx: 113, Freq: 5587.651703 */
381 17594, /* Idx: 114, Freq: 5919.910763 */
382 18641, /* Idx: 115, Freq: 6271.926976 */
383 19749, /* Idx: 116, Freq: 6644.875161 */
384 20923, /* Idx: 117, Freq: 7040.000000 */
385 22168, /* Idx: 118, Freq: 7458.620184 */
386 23486, /* Idx: 119, Freq: 7902.132820 */
387 24882, /* Idx: 120, Freq: 8372.018090 */
388 26362, /* Idx: 121, Freq: 8869.844191 */
389 27930, /* Idx: 122, Freq: 9397.272573 */
390 29590, /* Idx: 123, Freq: 9956.063479 */
391 31350, /* Idx: 124, Freq: 10548.081821 */
392 33214, /* Idx: 125, Freq: 11175.303406 */
393 35189, /* Idx: 126, Freq: 11839.821527 */
394 37282, /* Idx: 127, Freq: 12543.853951 */
395 39499 /* Idx: 128, Freq: 13289.750323 */
396};
397
398#elif defined( RETROSND_SAMPLE_44100 )
399
400uint32_t gc_phase_inc[] = {
401 12, /* Idx: 0, Freq: 8.175799 */
402 12, /* Idx: 1, Freq: 8.661957 */
403 13, /* Idx: 2, Freq: 9.177024 */
404 14, /* Idx: 3, Freq: 9.722718 */
405 15, /* Idx: 4, Freq: 10.300861 */
406 16, /* Idx: 5, Freq: 10.913382 */
407 17, /* Idx: 6, Freq: 11.562326 */
408 18, /* Idx: 7, Freq: 12.249857 */
409 19, /* Idx: 8, Freq: 12.978272 */
410 20, /* Idx: 9, Freq: 13.750000 */
411 21, /* Idx: 10, Freq: 14.567618 */
412 22, /* Idx: 11, Freq: 15.433853 */
413 24, /* Idx: 12, Freq: 16.351598 */
414 25, /* Idx: 13, Freq: 17.323914 */
415 27, /* Idx: 14, Freq: 18.354048 */
416 28, /* Idx: 15, Freq: 19.445436 */
417 30, /* Idx: 16, Freq: 20.601722 */
418 32, /* Idx: 17, Freq: 21.826764 */
419 34, /* Idx: 18, Freq: 23.124651 */
420 36, /* Idx: 19, Freq: 24.499715 */
421 38, /* Idx: 20, Freq: 25.956544 */
422 40, /* Idx: 21, Freq: 27.500000 */
423 43, /* Idx: 22, Freq: 29.135235 */
424 45, /* Idx: 23, Freq: 30.867706 */
425 48, /* Idx: 24, Freq: 32.703196 */
426 51, /* Idx: 25, Freq: 34.647829 */
427 54, /* Idx: 26, Freq: 36.708096 */
428 57, /* Idx: 27, Freq: 38.890873 */
429 61, /* Idx: 28, Freq: 41.203445 */
430 64, /* Idx: 29, Freq: 43.653529 */
431 68, /* Idx: 30, Freq: 46.249303 */
432 72, /* Idx: 31, Freq: 48.999429 */
433 77, /* Idx: 32, Freq: 51.913087 */
434 81, /* Idx: 33, Freq: 55.000000 */
435 86, /* Idx: 34, Freq: 58.270470 */
436 91, /* Idx: 35, Freq: 61.735413 */
437 97, /* Idx: 36, Freq: 65.406391 */
438 102, /* Idx: 37, Freq: 69.295658 */
439 109, /* Idx: 38, Freq: 73.416192 */
440 115, /* Idx: 39, Freq: 77.781746 */
441 122, /* Idx: 40, Freq: 82.406889 */
442 129, /* Idx: 41, Freq: 87.307058 */
443 137, /* Idx: 42, Freq: 92.498606 */
444 145, /* Idx: 43, Freq: 97.998859 */
445 154, /* Idx: 44, Freq: 103.826174 */
446 163, /* Idx: 45, Freq: 110.000000 */
447 173, /* Idx: 46, Freq: 116.540940 */
448 183, /* Idx: 47, Freq: 123.470825 */
449 194, /* Idx: 48, Freq: 130.812783 */
450 205, /* Idx: 49, Freq: 138.591315 */
451 218, /* Idx: 50, Freq: 146.832384 */
452 231, /* Idx: 51, Freq: 155.563492 */
453 244, /* Idx: 52, Freq: 164.813778 */
454 259, /* Idx: 53, Freq: 174.614116 */
455 274, /* Idx: 54, Freq: 184.997211 */
456 291, /* Idx: 55, Freq: 195.997718 */
457 308, /* Idx: 56, Freq: 207.652349 */
458 326, /* Idx: 57, Freq: 220.000000 */
459 346, /* Idx: 58, Freq: 233.081881 */
460 366, /* Idx: 59, Freq: 246.941651 */
461 388, /* Idx: 60, Freq: 261.625565 */
462 411, /* Idx: 61, Freq: 277.182631 */
463 436, /* Idx: 62, Freq: 293.664768 */
464 462, /* Idx: 63, Freq: 311.126984 */
465 489, /* Idx: 64, Freq: 329.627557 */
466 518, /* Idx: 65, Freq: 349.228231 */
467 549, /* Idx: 66, Freq: 369.994423 */
468 582, /* Idx: 67, Freq: 391.995436 */
469 617, /* Idx: 68, Freq: 415.304698 */
470 653, /* Idx: 69, Freq: 440.000000 */
471 692, /* Idx: 70, Freq: 466.163762 */
472 733, /* Idx: 71, Freq: 493.883301 */
473 777, /* Idx: 72, Freq: 523.251131 */
474 823, /* Idx: 73, Freq: 554.365262 */
475 872, /* Idx: 74, Freq: 587.329536 */
476 924, /* Idx: 75, Freq: 622.253967 */
477 979, /* Idx: 76, Freq: 659.255114 */
478 1037, /* Idx: 77, Freq: 698.456463 */
479 1099, /* Idx: 78, Freq: 739.988845 */
480 1165, /* Idx: 79, Freq: 783.990872 */
481 1234, /* Idx: 80, Freq: 830.609395 */
482 1307, /* Idx: 81, Freq: 880.000000 */
483 1385, /* Idx: 82, Freq: 932.327523 */
484 1467, /* Idx: 83, Freq: 987.766603 */
485 1555, /* Idx: 84, Freq: 1046.502261 */
486 1647, /* Idx: 85, Freq: 1108.730524 */
487 1745, /* Idx: 86, Freq: 1174.659072 */
488 1849, /* Idx: 87, Freq: 1244.507935 */
489 1959, /* Idx: 88, Freq: 1318.510228 */
490 2075, /* Idx: 89, Freq: 1396.912926 */
491 2199, /* Idx: 90, Freq: 1479.977691 */
492 2330, /* Idx: 91, Freq: 1567.981744 */
493 2468, /* Idx: 92, Freq: 1661.218790 */
494 2615, /* Idx: 93, Freq: 1760.000000 */
495 2771, /* Idx: 94, Freq: 1864.655046 */
496 2935, /* Idx: 95, Freq: 1975.533205 */
497 3110, /* Idx: 96, Freq: 2093.004522 */
498 3295, /* Idx: 97, Freq: 2217.461048 */
499 3491, /* Idx: 98, Freq: 2349.318143 */
500 3698, /* Idx: 99, Freq: 2489.015870 */
501 3918, /* Idx: 100, Freq: 2637.020455 */
502 4151, /* Idx: 101, Freq: 2793.825851 */
503 4398, /* Idx: 102, Freq: 2959.955382 */
504 4660, /* Idx: 103, Freq: 3135.963488 */
505 4937, /* Idx: 104, Freq: 3322.437581 */
506 5230, /* Idx: 105, Freq: 3520.000000 */
507 5542, /* Idx: 106, Freq: 3729.310092 */
508 5871, /* Idx: 107, Freq: 3951.066410 */
509 6220, /* Idx: 108, Freq: 4186.009045 */
510 6590, /* Idx: 109, Freq: 4434.922096 */
511 6982, /* Idx: 110, Freq: 4698.636287 */
512 7397, /* Idx: 111, Freq: 4978.031740 */
513 7837, /* Idx: 112, Freq: 5274.040911 */
514 8303, /* Idx: 113, Freq: 5587.651703 */
515 8797, /* Idx: 114, Freq: 5919.910763 */
516 9320, /* Idx: 115, Freq: 6271.926976 */
517 9874, /* Idx: 116, Freq: 6644.875161 */
518 10461, /* Idx: 117, Freq: 7040.000000 */
519 11084, /* Idx: 118, Freq: 7458.620184 */
520 11743, /* Idx: 119, Freq: 7902.132820 */
521 12441, /* Idx: 120, Freq: 8372.018090 */
522 13181, /* Idx: 121, Freq: 8869.844191 */
523 13965, /* Idx: 122, Freq: 9397.272573 */
524 14795, /* Idx: 123, Freq: 9956.063479 */
525 15675, /* Idx: 124, Freq: 10548.081821 */
526 16607, /* Idx: 125, Freq: 11175.303406 */
527 17594, /* Idx: 126, Freq: 11839.821527 */
528 18641, /* Idx: 127, Freq: 12543.853951 */
529 19749 /* Idx: 128, Freq: 13289.750323 */
530};
531
532#else
533# error "warning: no sample rate specified!"
534#endif /* RETROSND_SAMPLE_* */
535
536/* === */
537
538MERROR_RETVAL retrosnd_tune_init(
539 MAUG_MHANDLE* p_tune_h, size_t notes_ct, uint16_t ms_per_note
540) {
541 struct RETROSND_TUNE* tune = NULL;
542 MERROR_RETVAL retval = MERROR_OK;
543
544 maug_malloc_test( *p_tune_h, 1,
545 sizeof( struct RETROSND_TUNE ) + (notes_ct * RETROSND_CHANNEL_CT_MAX ) );
546 maug_mlock( *p_tune_h, tune );
547 maug_cleanup_if_null_lock( struct RETROSND_TUNE*, tune );
548
549 maug_mzero( tune,
550 sizeof( struct RETROSND_TUNE ) + (notes_ct * RETROSND_CHANNEL_CT_MAX ) );
551
552 memset( tune->notes, RETROSND_TUNE_NOTE_DISABLED,
553 RETROSND_CHANNEL_CT_MAX * notes_ct );
554
555 tune->sz = sizeof( struct RETROSND_TUNE );
556 tune->notes_ct = notes_ct;
557 tune->total_sz = sizeof( struct RETROSND_TUNE ) +
558 (RETROSND_CHANNEL_CT_MAX * tune->notes_ct);
559 tune->ms_per_note = ms_per_note;
560
561cleanup:
562
563 if( NULL != tune ) {
564 maug_munlock( *p_tune_h, tune );
565 }
566
567 return retval;
568}
569
570/* === */
571
573 MERROR_RETVAL retval = MERROR_OK;
574 int prev_note = 0, i = 0;
575
576 if( retroflat_get_ms() > tune->next_note_at ) {
577 /* It's time to advance the playing note in the tune! */
578 tune->next_note_at = retroflat_get_ms() + tune->ms_per_note;
579 prev_note = tune->current_note_idx;
580 tune->current_note_idx++;
581 if( tune->notes_ct <= tune->current_note_idx ) {
582 tune->current_note_idx = 0;
583 retval = MERROR_OVERFLOW;
584 }
585#if 0 < RETROSND_TUNE_TRACE_LVL
586 debug_printf( RETROSND_TUNE_TRACE_LVL, "next note index: %d\n",
587 tune->current_note_idx );
588#endif /* RETROSND_TUNE_TRACE_LVL */
589
590 /* Ensure playing blocks are playing and stopped are stopped. */
591 for( i = 0 ; RETROSND_CHANNEL_CT_MAX > i ; i++ ) {
592 if( 0 <= prev_note ) {
593 retrosnd_note_off( i, tune->notes[prev_note][i], 0 );
594 }
595 if( MERROR_OK == retval ) {
596 retrosnd_note_on( i, tune->notes[tune->current_note_idx][i], 0 );
597 }
598 }
599 }
600
601 return retval;
602}
603
604/* === */
605
606void retrosnd_tune_seek( struct RETROSND_TUNE* tune, int8_t idx ) {
607 int i = 0;
608 if( 0 <= tune->current_note_idx ) {
609 for( i = 0 ; RETROSND_CHANNEL_CT_MAX > i ; i++ ) {
610 retrosnd_note_off( i, tune->notes[tune->current_note_idx][i], 0 );
611 }
612 }
613 tune->current_note_idx = idx;
614 tune->next_note_at = 0;
615}
616
617/* === */
618
619MERROR_RETVAL retrosnd_tune_set_note(
620 struct RETROSND_TUNE* tune, int channel, int index, int8_t note
621) {
622 MERROR_RETVAL retval = MERROR_OK;
623
624 if( index >= tune->notes_ct ) {
625 error_printf( "invalid note index specified: %d", index );
626 retval = MERROR_OVERFLOW;
627 goto cleanup;
628 }
629
630 if( channel >= RETROSND_CHANNEL_CT_MAX ) {
631 error_printf( "invalid channel specified: %d", channel );
632 retval = MERROR_OVERFLOW;
633 goto cleanup;
634 }
635
636 tune->notes[index][channel] = note;
637
638cleanup:
639
640 return retval;
641}
642
643/* === */
644
645MAUG_CONST char* retrosnd_note_to_str( int8_t note ) {
646 if(
647 RETROSND_NOTES_START > note ||
648 RETROSND_NOTES_START + RETROSND_NOTES_SZ < note
649 ) {
650 return "?";
651 }
652
653 return gc_retrosnd_note_names[note - RETROSND_NOTES_START];
654}
655
656#ifndef RETROFLAT_NO_SOUND
657
658/* === */
659
660MERROR_RETVAL _retrosnd_channels_init( struct RETROSND_CHANNEL* channels ) {
661 MERROR_RETVAL retval = MERROR_OK;
662 int i = 0;
663
664 for( i = 0 ; RETROSND_CHANNEL_CT_MAX > i ; i++ ) {
665 channels[i].note = RETROSND_TUNE_NOTE_DISABLED;
666 }
667
668 /* Setup synthesizer defaults. */
669
670 retrosnd_set_voice( 0, 0 );
671 retrosnd_set_voice( 1, 0 );
672 retrosnd_set_voice( 2, 1 );
673 retrosnd_set_voice( 3, 2 );
674
675 retrosnd_set_control( 0, RETROSND_CONTROL_VOL, 128 );
676 retrosnd_set_control( 1, RETROSND_CONTROL_VOL, 128 );
677 retrosnd_set_control( 2, RETROSND_CONTROL_VOL, 128 );
678 retrosnd_set_control( 3, RETROSND_CONTROL_VOL, 128 );
679
680 return retval;
681}
682
683int16_t _retrosnd_generate_note( struct RETROSND_CHANNEL* channels ) {
684 int32_t mix = 0;
685 int i = 0;
686
687 /* Mix each of the channels into a single sample. */
688 for( i = 0 ; RETROSND_CHANNEL_CT_MAX > i ; i++ ) {
689 if( RETROSND_TUNE_NOTE_DISABLED == channels[i].note ) {
690 continue;
691 }
692
693 if(
694 channels[i].deadline > 0 && channels[i].deadline < retroflat_get_ms()
695 ) {
696#if RETROSND_TRACE_LVL > 0
697 debug_printf( RETROSND_TRACE_LVL, "note %d disabled after deadline!",
698 i );
699#endif /* RETROSND_TRACE_LVL */
700 channels[i].note = RETROSND_TUNE_NOTE_DISABLED;
701 channels[i].deadline = 0;
702 continue;
703 }
704
705 channels[i].phase += gc_phase_inc[channels[i].note];
706
707 switch( channels[i].voice ) {
708 case 0:
709 /* Triangle wave. */
710 if( 32768 > channels[i].phase ) {
711 mix += (channels[i].phase - 16384) * 2;
712 } else {
713 mix += ((uint16_t)((((65536 - channels[i].phase)
714 - 16384) * 2)) * channels[i].vol) >> 8;
715 }
716 break;
717
718 case 1:
719 /* Square wave. */
720 mix += ((INT16_MAX >= (uint16_t)(channels[i].phase) ? 30000 : -30000)
721 * channels[i].vol) >> 8;
722 break;
723
724 case 2:
725 if( 0 < channels[i].noise_time ) {
726 channels[i].noise_time--;
727 } else {
728 channels[i].noise_last = retroflat_get_rand() % INT16_MAX;
729 channels[i].noise_time = channels[i].note / 2;
730 }
731 mix += channels[i].noise_last;
732 break;
733 }
734 }
735
736 /* Clip the sample and assign it. */
737 if( INT16_MAX <= mix ) {
738 return INT16_MAX;
739 } else if( INT16_MIN > mix ) {
740 return INT16_MIN;
741 } else {
742 return mix;
743 }
744}
745
746/* === */
747
749 struct RETROSND_CHANNEL* channel, uint8_t key, uint8_t val
750) {
751 MERROR_RETVAL retval = MERROR_OK;
752
753 switch( key ) {
754 case RETROSND_CONTROL_VOL:
755 channel->vol = val;
756 break;
757
758 default:
759 error_printf( "unimplemented control message: %d!", key );
760 retval = MERROR_OVERFLOW;
761 break;
762 }
763
764 return retval;
765}
766
767#endif /* !RETROFLAT_NO_SOUND */
768
769#else
770
771#define RETROSND_NOTES_TABLE_EXT_CONSTS( num, name ) \
772 extern MAUG_CONST int8_t RSN_ ## name;
773
774RETROSND_NOTES_TABLE( RETROSND_NOTES_TABLE_EXT_CONSTS )
775
776#endif /* RETROSND_C */
777
778#endif /* !RETROSND_H */
779
uint16_t MERROR_RETVAL
Return type indicating function returns a value from this list.
Definition merror.h:28
int16_t _retrosnd_generate_note(struct RETROSND_CHANNEL *channels)
Increment synthesizer phase based on its instrument and system settings.
MERROR_RETVAL _retrosnd_set_control(struct RETROSND_CHANNEL *channel, uint8_t key, uint8_t val)
Set controls for the software synthesizer.
void retrosnd_set_sf_bank(const char *filename_in)
Set the name of the voice bank filename to use.
MERROR_RETVAL retrosnd_init(struct RETROFLAT_ARGS *args)
Initialize retrosnd engine.
MERROR_RETVAL retrosnd_tune_update(struct RETROSND_TUNE *tune)
Update the currently playing note in the given tune.
Struct containing configuration values for a RetroFlat program.
Definition retroflt.h:1035
Definition retrosnd.h:57
uint8_t note
Note for this channel to play its instrument at.
Definition retrosnd.h:66
uint8_t vol
Volume for this channel to play its instrument at.
Definition retrosnd.h:70
int8_t voice
Instrument for this channel to play.
Definition retrosnd.h:62
uint32_t phase
Current step of the waveform to generate samples for.
Definition retrosnd.h:76
Simple tune designed to be played on the software synthesizer.
Definition retrosnd.h:86
size_t total_sz
Size of the tune in bytes (including this struct header).
Definition retrosnd.h:90
size_t sz
Size of this struct (useful for serializing).
Definition retrosnd.h:88