33#ifndef RETROSND_CHANNEL_CT_MAX
34# define RETROSND_CHANNEL_CT_MAX 4
37#ifndef RETROSND_TRACE_LVL
38# define RETROSND_TRACE_LVL 0
41#ifndef RETROSND_REG_TRACE_LVL
42# define RETROSND_REG_TRACE_LVL 0
45#ifndef RETROSND_SAMPLES_CT
46# define RETROSND_SAMPLES_CT 2048
49#ifdef RETROSND_SAMPLE_22050
50# define RETROSND_SAMPLE_RATE 22050
51#elif defined( RETROSND_SAMPLE_44100 )
54# define RETROSND_SAMPLE_RATE 44100
78 retroflat_ms_t deadline;
92 int8_t current_note_idx;
94 retroflat_ms_t next_note_at;
95 uint8_t notes[][RETROSND_CHANNEL_CT_MAX];
108#define RETROSND_FLAG_INIT 0x01
112#define RETROSND_VOICE_BREATH 122
114#define RETROSND_VOICE_SEASHORE 123
116#define RETROSND_VOICE_BIRD_TWEET 124
118#define RETROSND_VOICE_PHONE_RING 125
120#define RETROSND_VOICE_HELICOPTER 126
122#define RETROSND_VOICE_APPLAUSE 127
128#define RETROSND_VOICE_GUNSHOT 128
130#define RETROSND_CONTROL_VOL 7
147void retrosnd_set_voice( uint8_t channel, uint8_t voice );
149void retrosnd_set_control( uint8_t channel, uint8_t key, uint8_t val );
151void retrosnd_note_on( uint8_t channel, uint8_t pitch, uint8_t vel );
153void retrosnd_note_off( uint8_t channel, uint8_t pitch, uint8_t vel );
155void retrosnd_shutdown(
void );
157void retrosnd_pump(
void );
159void retrosnd_note_on_deadline(
160 uint8_t channel, uint8_t pitch, retroflat_ms_t after );
163 MAUG_MHANDLE* p_tune_h,
size_t notes_ct, uint16_t ms_per_note );
176void retrosnd_tune_seek(
struct RETROSND_TUNE* tune, int8_t idx );
179 struct RETROSND_TUNE*,
int channel,
int index, int8_t note );
181#define retrosnd_tune_get_note( tune, channel, idx ) \
182 ((tune)->notes[idx][channel])
200#define RETROSND_TUNE_NOTE_DISABLED (255)
202#define RETROSND_NOTES_START (36)
204#define RETROSND_NOTES_OCTAVE_SZ (12)
206#define RETROSND_NOTES_SZ (RETROSND_NOTES_OCTAVE_SZ * 3)
208#define RETROSND_NOTES_OCTAVE_MIDDLE (48)
210#define RETROSND_NOTES_TABLE( f ) \
252#define RETROSND_NOTES_TABLE_CONST_NAMES( num, name ) \
255MAUG_CONST
char* gc_retrosnd_note_names[RETROSND_NOTES_SZ] = {
256RETROSND_NOTES_TABLE( RETROSND_NOTES_TABLE_CONST_NAMES )
259#define RETROSND_NOTES_TABLE_CONST_CONSTS( num, name ) \
260 MAUG_CONST int8_t RSN_ ## name = num;
262RETROSND_NOTES_TABLE( RETROSND_NOTES_TABLE_CONST_CONSTS )
264#ifdef RETROSND_SAMPLE_22050
266uint32_t gc_phase_inc[] = {
398#elif defined( RETROSND_SAMPLE_44100 )
400uint32_t gc_phase_inc[] = {
533# error "warning: no sample rate specified!"
539 MAUG_MHANDLE* p_tune_h,
size_t notes_ct, uint16_t ms_per_note
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 );
550 sizeof(
struct RETROSND_TUNE ) + (notes_ct * RETROSND_CHANNEL_CT_MAX ) );
552 memset( tune->notes, RETROSND_TUNE_NOTE_DISABLED,
553 RETROSND_CHANNEL_CT_MAX * notes_ct );
556 tune->notes_ct = notes_ct;
558 (RETROSND_CHANNEL_CT_MAX * tune->notes_ct);
559 tune->ms_per_note = ms_per_note;
564 maug_munlock( *p_tune_h, tune );
574 int prev_note = 0, i = 0;
576 if( retroflat_get_ms() > tune->next_note_at ) {
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;
585#if 0 < RETROSND_TUNE_TRACE_LVL
586 debug_printf( RETROSND_TUNE_TRACE_LVL,
"next note index: %d\n",
587 tune->current_note_idx );
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 );
595 if( MERROR_OK == retval ) {
596 retrosnd_note_on( i, tune->notes[tune->current_note_idx][i], 0 );
606void retrosnd_tune_seek(
struct RETROSND_TUNE* tune, int8_t idx ) {
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 );
613 tune->current_note_idx = idx;
614 tune->next_note_at = 0;
620 struct RETROSND_TUNE* tune,
int channel,
int index, int8_t note
624 if( index >= tune->notes_ct ) {
625 error_printf(
"invalid note index specified: %d", index );
626 retval = MERROR_OVERFLOW;
630 if( channel >= RETROSND_CHANNEL_CT_MAX ) {
631 error_printf(
"invalid channel specified: %d", channel );
632 retval = MERROR_OVERFLOW;
636 tune->notes[index][channel] = note;
645MAUG_CONST
char* retrosnd_note_to_str( int8_t note ) {
647 RETROSND_NOTES_START > note ||
648 RETROSND_NOTES_START + RETROSND_NOTES_SZ < note
653 return gc_retrosnd_note_names[note - RETROSND_NOTES_START];
656#ifndef RETROFLAT_NO_SOUND
664 for( i = 0 ; RETROSND_CHANNEL_CT_MAX > i ; i++ ) {
665 channels[i].
note = RETROSND_TUNE_NOTE_DISABLED;
670 retrosnd_set_voice( 0, 0 );
671 retrosnd_set_voice( 1, 0 );
672 retrosnd_set_voice( 2, 1 );
673 retrosnd_set_voice( 3, 2 );
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 );
688 for( i = 0 ; RETROSND_CHANNEL_CT_MAX > i ; i++ ) {
689 if( RETROSND_TUNE_NOTE_DISABLED == channels[i].note ) {
694 channels[i].deadline > 0 && channels[i].deadline < retroflat_get_ms()
696#if RETROSND_TRACE_LVL > 0
697 debug_printf( RETROSND_TRACE_LVL,
"note %d disabled after deadline!",
700 channels[i].
note = RETROSND_TUNE_NOTE_DISABLED;
701 channels[i].deadline = 0;
705 channels[i].
phase += gc_phase_inc[channels[i].
note];
707 switch( channels[i].voice ) {
710 if( 32768 > channels[i].phase ) {
711 mix += (channels[i].phase - 16384) * 2;
713 mix += ((uint16_t)((((65536 - channels[i].phase)
714 - 16384) * 2)) * channels[i].vol) >> 8;
720 mix += ((INT16_MAX >= (uint16_t)(channels[i].phase) ? 30000 : -30000)
721 * channels[i].vol) >> 8;
725 if( 0 < channels[i].noise_time ) {
726 channels[i].noise_time--;
728 channels[i].noise_last = retroflat_get_rand() % INT16_MAX;
729 channels[i].noise_time = channels[i].note / 2;
731 mix += channels[i].noise_last;
737 if( INT16_MAX <= mix ) {
739 }
else if( INT16_MIN > mix ) {
754 case RETROSND_CONTROL_VOL:
759 error_printf(
"unimplemented control message: %d!", key );
760 retval = MERROR_OVERFLOW;
771#define RETROSND_NOTES_TABLE_EXT_CONSTS( num, name ) \
772 extern MAUG_CONST int8_t RSN_ ## name;
774RETROSND_NOTES_TABLE( RETROSND_NOTES_TABLE_EXT_CONSTS )
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
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