diff --git a/apps/beep.c b/apps/beep.c index 25b5e0e391..62ebf2c3f9 100644 --- a/apps/beep.c +++ b/apps/beep.c @@ -97,7 +97,7 @@ void beep_play(unsigned int frequency, unsigned int duration, beep_get_more(&start, &size); mixer_channel_set_amplitude(PCM_MIXER_CHAN_BEEP, MIX_AMP_UNITY); - mixer_channel_play_data(PCM_MIXER_CHAN_BEEP, - beep_count ? beep_get_more : NULL, - start, size); + static struct mixer_play_cbs cbs; + cbs.get_more = beep_count ? beep_get_more : NULL; + mixer_channel_play_data(PCM_MIXER_CHAN_BEEP, &cbs, start, size); } diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index 6bd39d4dc0..e9e05bc5c0 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c @@ -29,6 +29,7 @@ #include "pcmbuf.h" #include "dsp-util.h" #include "playback.h" +#include "dsp_core.h" #include "codec_thread.h" /* Define LOGF_ENABLE to enable logf output in this file */ @@ -836,6 +837,12 @@ static void pcmbuf_pcm_callback(const void **start, size_t *size) } } +static void pcmbuf_sampr_callback(uint32_t sampr) +{ + struct dsp_config* dsp = dsp_get_config(CODEC_IDX_AUDIO); + dsp_configure(dsp, DSP_SET_OUT_FREQUENCY, sampr); +} + /* Force playback */ void pcmbuf_play_start(void) { @@ -845,8 +852,11 @@ void pcmbuf_play_start(void) chunk_widx != chunk_ridx) { current_desc = NULL; - mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, pcmbuf_pcm_callback, - NULL, 0); + static const struct mixer_play_cbs cbs = { + .get_more = pcmbuf_pcm_callback, + .sampr_changed = pcmbuf_sampr_callback, + }; + mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, &cbs, NULL, 0); } } diff --git a/apps/plugin.h b/apps/plugin.h index 4eb83fbad5..f0491f4ece 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -782,7 +782,7 @@ struct plugin_api { void (*mixer_channel_calculate_peaks)(enum pcm_mixer_channel channel, struct pcm_peaks *peaks); void (*mixer_channel_play_data)(enum pcm_mixer_channel channel, - pcm_play_callback_type get_more, + const struct mixer_play_cbs* cbs, const void *start, size_t size); void (*mixer_channel_play_pause)(enum pcm_mixer_channel channel, bool play); void (*mixer_channel_stop)(enum pcm_mixer_channel channel); diff --git a/apps/plugins/doom/i_sound.c b/apps/plugins/doom/i_sound.c index 78780dd9b3..068aa915c5 100644 --- a/apps/plugins/doom/i_sound.c +++ b/apps/plugins/doom/i_sound.c @@ -466,7 +466,10 @@ void I_SubmitSound(void) if (!enable_sound) return; - rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, &get_more, NULL, 0); + static const struct mixer_play_cbs cbs = { + .get_more = get_more, + }; + rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, &cbs, NULL, 0); } void I_ShutdownSound(void) diff --git a/apps/plugins/midi/midiplay.c b/apps/plugins/midi/midiplay.c index d19ff7888b..2a6e579b9c 100644 --- a/apps/plugins/midi/midiplay.c +++ b/apps/plugins/midi/midiplay.c @@ -507,6 +507,10 @@ UNUSED_ATTR static int find_min_sampr_ge_22(void) return ret; } +static const struct mixer_play_cbs mixer_cbs = { + .get_more = get_more, +}; + static int midimain(const void * filename) { int a, notes_used, vol; @@ -625,7 +629,7 @@ static int midimain(const void * filename) #endif rb->pcmbuf_fade(false, true); - rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, get_more, NULL, 0); + rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, &mixer_cbs, NULL, 0); while (!quit) { @@ -684,7 +688,7 @@ static int midimain(const void * filename) #endif midi_debug("Rewind to %d:%02d\n", playing_time/60, playing_time%60); if (is_playing) - rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, get_more, NULL, 0); + rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, &mixer_cbs, NULL, 0); break; } @@ -706,7 +710,7 @@ static int midimain(const void * filename) #endif midi_debug("Skip to %d:%02d\n", playing_time/60, playing_time%60); if (is_playing) - rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, get_more, NULL, 0); + rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, &mixer_cbs, NULL, 0); break; } diff --git a/apps/plugins/mikmod/mikmod.c b/apps/plugins/mikmod/mikmod.c index 782153f8e5..a482ace68b 100644 --- a/apps/plugins/mikmod/mikmod.c +++ b/apps/plugins/mikmod/mikmod.c @@ -292,6 +292,10 @@ static void get_more(const void** start, size_t* size) #endif } +static const struct mixer_play_cbs mixer_cbs = { + .get_more = get_more, +}; + static void showinfo(void) { char statustext[LINE_LENGTH]; @@ -600,10 +604,9 @@ static void applysettings(void) } // MikMod_Reset(""); BROKEN! - rb->mixer_channel_stop(PCM_MIXER_CHAN_PLAYBACK); - rb->mixer_set_frequency(md_mixfreq); - rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, get_more, NULL, 0); + rb->mixer_set_frequency(md_mixfreq); + rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, &mixer_cbs, NULL, 0); } #ifdef HAVE_ADJUSTABLE_CPU_FREQ @@ -810,7 +813,7 @@ static int playfile(char* filename) display = DISPLAY_INFO; Player_Start(module); rb->pcmbuf_fade(false, true); - rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, get_more, NULL, 0); + rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, &mixer_cbs, NULL, 0); } #ifdef HAVE_ADJUSTABLE_CPU_FREQ diff --git a/apps/plugins/mpegplayer/pcm_output.c b/apps/plugins/mpegplayer/pcm_output.c index 5e95d16316..6ce603ac9c 100644 --- a/apps/plugins/mpegplayer/pcm_output.c +++ b/apps/plugins/mpegplayer/pcm_output.c @@ -173,6 +173,10 @@ static void get_more(const void **start, size_t *size) pcmbuf_read = pcmbuf_written; } +static const struct mixer_play_cbs mixer_cbs = { + .get_more = get_more, +}; + /** Public interface **/ /* Return a buffer pointer if at least size bytes are available and if so, @@ -236,8 +240,7 @@ void pcm_output_flush(void) /* Restart if playing state was current */ if (status == CHANNEL_PLAYING) - rb->mixer_channel_play_data(MPEG_PCM_CHANNEL, - get_more, NULL, 0); + rb->mixer_channel_play_data(MPEG_PCM_CHANNEL, &mixer_cbs, NULL, 0); } /* Seek the reference clock to the specified time - next audio data ready to @@ -318,8 +321,7 @@ void pcm_output_play_pause(bool play) if (play) { rb->mixer_channel_set_amplitude(MPEG_PCM_CHANNEL, MIX_AMP_UNITY); - rb->mixer_channel_play_data(MPEG_PCM_CHANNEL, - get_more, NULL, 0); + rb->mixer_channel_play_data(MPEG_PCM_CHANNEL, &mixer_cbs, NULL, 0); } } } diff --git a/apps/plugins/pacbox/pacbox.c b/apps/plugins/pacbox/pacbox.c index 34f103039d..e024c6d493 100644 --- a/apps/plugins/pacbox/pacbox.c +++ b/apps/plugins/pacbox/pacbox.c @@ -407,8 +407,11 @@ static void start_sound(void) wsg3_set_sampling_rate(caps->samprs[sr_index]); + static const struct mixer_play_cbs cbs = { + .get_more = get_more, + }; rb->mixer_set_frequency(caps->samprs[sr_index]); - rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, get_more, NULL, 0); + rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, &cbs, NULL, 0); sound_playing = true; } diff --git a/apps/plugins/pdbox/PDa/src/s_audio_rockbox.c b/apps/plugins/pdbox/PDa/src/s_audio_rockbox.c index 5f82f6d393..fd3c764645 100644 --- a/apps/plugins/pdbox/PDa/src/s_audio_rockbox.c +++ b/apps/plugins/pdbox/PDa/src/s_audio_rockbox.c @@ -181,7 +181,10 @@ int rockbox_send_dacs(void) if(!playing && outbuf_fill > 0) { /* Start playing. */ - rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, pdbox_get_more, NULL, 0); + static const struct mixer_play_cbs cbs = { + .get_more = pdbox_get_more, + }; + rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, &cbs, NULL, 0); /* Set status flag. */ playing = true; diff --git a/apps/plugins/rockboy/rbsound.c b/apps/plugins/rockboy/rbsound.c index 60f877471e..7d10dbdb83 100644 --- a/apps/plugins/rockboy/rbsound.c +++ b/apps/plugins/rockboy/rbsound.c @@ -73,7 +73,10 @@ int rockboy_pcm_submit(void) if(newly_started) { - rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, &get_more, NULL, 0); + static const struct mixer_play_cbs cbs = { + .get_more = get_more, + }; + rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, &cbs, NULL, 0); newly_started = false; } diff --git a/apps/plugins/sdl/src/audio/rockbox/SDL_rockboxaudio.c b/apps/plugins/sdl/src/audio/rockbox/SDL_rockboxaudio.c index bfa5802ddf..2ffcda6b46 100644 --- a/apps/plugins/sdl/src/audio/rockbox/SDL_rockboxaudio.c +++ b/apps/plugins/sdl/src/audio/rockbox/SDL_rockboxaudio.c @@ -288,7 +288,10 @@ static int ROCKBOXAUD_OpenAudio(_THIS, SDL_AudioSpec *spec) rbaud_underruns = 0; - rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, get_more, NULL, 0); + static const struct mixer_play_cbs cbs = { + .get_more = get_more, + }; + rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, &cbs, NULL, 0); /* We're ready to rock and roll. :-) */ return(0); diff --git a/apps/plugins/test_sampr.c b/apps/plugins/test_sampr.c index 4c39ba3515..dfaea58183 100644 --- a/apps/plugins/test_sampr.c +++ b/apps/plugins/test_sampr.c @@ -237,7 +237,10 @@ static void play_tone(bool volume_set) IF_PRIO(, PRIORITY_PLAYBACK) IF_COP(, CPU)); - rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, get_more, NULL, 0); + static const struct mixer_play_cbs cbs = { + .get_more = get_more, + }; + rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, &cbs, NULL, 0); #ifndef HAVE_VOLUME_IN_LIST if (volume_set) diff --git a/apps/plugins/xrick/system/syssnd_rockbox.c b/apps/plugins/xrick/system/syssnd_rockbox.c index 74edd98140..ec8886f881 100644 --- a/apps/plugins/xrick/system/syssnd_rockbox.c +++ b/apps/plugins/xrick/system/syssnd_rockbox.c @@ -222,8 +222,11 @@ void syssnd_update(void) if (!isAudioPlaying && fillCount > 0) { + static const struct mixer_play_cbs cbs = { + .get_more = get_more, + }; isAudioPlaying = true; - rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, get_more, NULL, 0); + rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, &cbs, NULL, 0); } } } diff --git a/apps/plugins/xworld/sys.c b/apps/plugins/xworld/sys.c index 50c0c64e0b..a8c2d695fe 100644 --- a/apps/plugins/xworld/sys.c +++ b/apps/plugins/xworld/sys.c @@ -1029,7 +1029,10 @@ void sys_startAudio(struct System* sys, AudioCallback callback, void *param) audio_param = param; audio_sys = sys; - rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, get_more, NULL, 0); + static const struct mixer_play_cbs cbs = { + .get_more = get_more, + }; + rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, &cbs, NULL, 0); } void sys_stopAudio(struct System* sys) diff --git a/apps/plugins/zxbox/spsound.c b/apps/plugins/zxbox/spsound.c index 602030361f..4b38e68171 100644 --- a/apps/plugins/zxbox/spsound.c +++ b/apps/plugins/zxbox/spsound.c @@ -212,7 +212,10 @@ static void write_buf(void){ = my_buf[j+10] = my_buf[j+11] \ = (((byte)sp_sound_buf[i])<<8) >> settings.volume; - rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, get_more, (unsigned char*)(my_buf),TMNUM*4*3*2); + static const struct mixer_play_cbs cbs = { + .get_more = get_more, + }; + rb->mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, &cbs, (unsigned char*)(my_buf),TMNUM*4*3*2); #if 0 /* can use to save and later analyze what we produce */ diff --git a/apps/voice_thread.c b/apps/voice_thread.c index b31bc5bc76..3e83138d6c 100644 --- a/apps/voice_thread.c +++ b/apps/voice_thread.c @@ -245,8 +245,10 @@ static void voice_start_playback(void) struct voice_pcm_frame *frame = &voice_buf->frames[voice_buf->frame_out % VOICE_FRAMES]; - mixer_channel_play_data(PCM_MIXER_CHAN_VOICE, voice_pcm_callback, - frame->pcm, frame->size); + static const struct mixer_play_cbs cbs = { + .get_more = voice_pcm_callback, + }; + mixer_channel_play_data(PCM_MIXER_CHAN_VOICE, &cbs, frame->pcm, frame->size); } /* Stop the voice channel */ diff --git a/docs/PLUGIN_API b/docs/PLUGIN_API index d86fcbf335..4a895cc0a3 100644 --- a/docs/PLUGIN_API +++ b/docs/PLUGIN_API @@ -1607,9 +1607,9 @@ size_t mixer_channel_get_bytes_waiting(enum pcm_mixer_channel channel) \return \description -void mixer_channel_play_data(enum pcm_mixer_channel channel, pcm_play_callback_type get_more, const void *start, size_t size) +void mixer_channel_play_data(enum pcm_mixer_channel channel, const struct mixer_play_cbs* cbs, const void *start, size_t size) \param channel - \param get_more + \param cbs \param start \param size \description diff --git a/firmware/export/pcm_mixer.h b/firmware/export/pcm_mixer.h index 6dcbb9e4d4..99ded55082 100644 --- a/firmware/export/pcm_mixer.h +++ b/firmware/export/pcm_mixer.h @@ -96,8 +96,13 @@ enum channel_status /** Public interfaces **/ /* Start playback on a channel */ +struct mixer_play_cbs { + void (*get_more)(const void **start, size_t *size); + void (*sampr_changed)(uint32_t sampr); +}; + void mixer_channel_play_data(enum pcm_mixer_channel channel, - pcm_play_callback_type get_more, + const struct mixer_play_cbs* cbs, const void *start, size_t size); /* Pause or resume a channel (when started) */ diff --git a/firmware/pcm_mixer.c b/firmware/pcm_mixer.c index a0d26fc86d..f093084572 100644 --- a/firmware/pcm_mixer.c +++ b/firmware/pcm_mixer.c @@ -42,12 +42,12 @@ static unsigned int mix_frame_size = MIX_FRAME_SAMPLES*4; /* Descriptor for each channel */ struct mixer_channel { - const void *start; /* Buffer pointer */ - size_t size; /* Bytes remaining */ - size_t last_size; /* Size of consumed data in prev. cycle */ - pcm_play_callback_type get_more; /* Registered callback */ - enum channel_status status; /* Playback status */ - uint32_t amplitude; /* Amp. factor: 0x0000 = mute, 0x10000 = unity */ + const void *start; /* Buffer pointer */ + size_t size; /* Bytes remaining */ + size_t last_size; /* Size of consumed data in prev. cycle */ + const struct mixer_play_cbs* cbs; /* Registered callbacks */ + enum channel_status status; /* Playback status */ + uint32_t amplitude; /* Amp. factor: 0x0000 = mute, 0x10000 = unity */ chan_buffer_hook_fn_type buffer_hook; /* Callback for new buffer */ }; @@ -154,9 +154,9 @@ fill_frame: if (chan->size == 0) { - if (chan->get_more) + if (chan->cbs->get_more) { - chan->get_more(&chan->start, &chan->size); + chan->cbs->get_more(&chan->start, &chan->size); ALIGN_AUDIOBUF(chan->start, chan->size); } @@ -287,14 +287,14 @@ static void mixer_start_pcm(void) /* Start playback on a channel */ void mixer_channel_play_data(enum pcm_mixer_channel channel, - pcm_play_callback_type get_more, + const struct mixer_play_cbs* cbs, const void *start, size_t size) { struct mixer_channel *chan = &channels[channel]; ALIGN_AUDIOBUF(start, size); - if (!(start && size) && get_more) + if (!(start && size) && cbs && cbs->get_more) { /* Initial buffer not passed - call the callback now */ pcm_play_lock(); @@ -304,7 +304,7 @@ void mixer_channel_play_data(enum pcm_mixer_channel channel, pcm_play_unlock(); /* Allow playback while doing callback */ size = 0; - get_more(&start, &size); + cbs->get_more(&start, &size); ALIGN_AUDIOBUF(start, size); } @@ -317,7 +317,7 @@ void mixer_channel_play_data(enum pcm_mixer_channel channel, chan->start = start; chan->size = size; chan->last_size = 0; - chan->get_more = get_more; + chan->cbs = cbs; mixer_activate_channel(chan); chan_call_buffer_hook(chan); @@ -464,11 +464,36 @@ void mixer_set_frequency(unsigned int samplerate) if (samplerate == mixer_sampr) return; - - /* All data is now invalid */ - mixer_reset(); mixer_sampr = samplerate; + for (size_t i = 0; i < ARRAYLEN(active_channels) && active_channels[i]; i += 1) + { + struct mixer_channel* chan = active_channels[i]; + + /* Notify upstreams */ + if (chan->cbs) + { + if (chan->cbs->sampr_changed) + { + chan->cbs->sampr_changed(samplerate); + } + if (chan->cbs->get_more) + { + /* Remake buffer */ + const void *start = NULL; + size_t size; + chan->cbs->get_more(&start, &size); + if (start && size) { + chan->start = start; + chan->size = size; + chan->last_size = 0; + } else { + channel_stopped(chan); + } + } + } + } + /* Work out how much space we really need */ if (samplerate > SAMPR_96) mix_frame_size = 4; diff --git a/firmware/usbstack/usb_audio.c b/firmware/usbstack/usb_audio.c index f8d431705f..fd135cf7a3 100644 --- a/firmware/usbstack/usb_audio.c +++ b/firmware/usbstack/usb_audio.c @@ -1337,7 +1337,10 @@ bool usb_audio_fast_transfer_complete(int ep, int dir, int status, int length) logf("usbaudio: prebuffering done"); playback_audio_underflow = false; usb_rx_overflow = false; - mixer_channel_play_data(PCM_MIXER_CHAN_USBAUDIO, playback_audio_get_more, NULL, 0); + static const struct mixer_play_cbs cbs = { + .get_more = playback_audio_get_more, + }; + mixer_channel_play_data(PCM_MIXER_CHAN_USBAUDIO, &cbs, NULL, 0); } restore_irq(oldlevel); retval = true;