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/codec_thread.c b/apps/codec_thread.c index f3c95abdd3..2b109235c5 100644 --- a/apps/codec_thread.c +++ b/apps/codec_thread.c @@ -26,6 +26,7 @@ #include "kernel.h" #include "codecs.h" #include "codec_thread.h" +#include "pcm_mixer.h" #include "pcmbuf.h" #include "audio_thread.h" #include "playback.h" @@ -518,7 +519,7 @@ static void run_codec(void) codec_queue_ack(Q_CODEC_RUN); trigger_cpu_boost(); - dsp_configure(ci.dsp, DSP_SET_OUT_FREQUENCY, pcmbuf_get_frequency()); + dsp_configure(ci.dsp, DSP_SET_OUT_FREQUENCY, mixer_get_frequency()); if (!encoder) { diff --git a/apps/lang/bulgarian.lang b/apps/lang/bulgarian.lang index a7f1d9cbe9..05400fa4d5 100644 --- a/apps/lang/bulgarian.lang +++ b/apps/lang/bulgarian.lang @@ -5902,7 +5902,7 @@ *: none - hibylinux: "~U S B" + hibylinux: "Ю Ес Би" multivolume: "~H D 1" sansac200*,sansaclipplus,sansae200*,sansafuze*: "микро S D" xduoox3: "микро S D 2" @@ -7004,7 +7004,7 @@ *: none - usb_charging_enable: "Зареждане по време на USB връзка" + usb_charging_enable: "Зареждане по време на Ю Ес Би връзка" @@ -10103,7 +10103,7 @@ *: none - usb_hid: "Режим USB клавиатура" + usb_hid: "Режим Ю Ес Би клавиатура" @@ -10490,11 +10490,11 @@ *: none - usb_hid: "USB УЧИ" + usb_hid: "USB у-во за човешки интерфейс" *: none - usb_hid: "USB устройство за човешки интерфейс" + usb_hid: "Ю Ес Би устройство за човешки интерфейс" @@ -11230,7 +11230,7 @@ *: none - multidrive_usb: "USB скриване на вътрешната памет" + multidrive_usb: "Ю Ес Би скриване на вътрешната памет" @@ -15080,7 +15080,7 @@ *: "Влез в режим USB памет?" - *: "Влез в режим USB памет?" + *: "Влез в режим Ю Ес Би памет?" @@ -16873,11 +16873,11 @@ *: none - usbdac: "USB-ЦАП" + usbdac: "USB ЦАП" *: none - usbdac: "USB ЦАП" + usbdac: "Ю Ес Би цифрово-аналогов преобразувател" @@ -16894,7 +16894,7 @@ *: none - usbdac: "В режим USB само зареждане" + usbdac: "В режим Ю Ес Би само зареждане" @@ -16911,7 +16911,7 @@ *: none - usbdac: "В режим USB памет" + usbdac: "В режим Ю Ес Би памет" @@ -16924,11 +16924,11 @@ *: none - usbdac: "USB-ЦАП е активен" + usbdac: "USB ЦАП е активен" *: none - usbdac: "USB ЦАП е активен" + usbdac: "Ю Ес Би цифрово-аналогов преобразувател е активен" diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index 6bd39d4dc0..68b7e40602 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 */ @@ -68,17 +69,20 @@ chunks */ /* Return data level in 1/4-second increments */ -#define DATA_LEVEL(quarter_secs) (pcmbuf_sampr * (quarter_secs)) +static inline unsigned int data_level(int quarter_secs) +{ + return mixer_get_frequency() * quarter_secs; +} /* Number of bytes played per second */ -#define BYTERATE (pcmbuf_sampr * PCMBUF_SAMPLE_SIZE) +#define BYTERATE (mixer_get_frequency() * PCMBUF_SAMPLE_SIZE) #if MEMORYSIZE > 2 /* Keep watermark high for large memory target - at least (2s) */ #define PCMBUF_WATERMARK (BYTERATE * 2) #define MIN_BUFFER_SIZE (BYTERATE * 3) /* 1 seconds of buffer is low data */ -#define LOW_DATA DATA_LEVEL(4) +#define LOW_DATA data_level(4) #else #define PCMBUF_WATERMARK (BYTERATE / 4) /* 0.25 seconds */ #define MIN_BUFFER_SIZE (BYTERATE * 1) @@ -108,7 +112,6 @@ static size_t pcmbuf_size; static struct chunkdesc *pcmbuf_descriptors; static unsigned int pcmbuf_desc_count; static unsigned int position_key = 1; -static unsigned int pcmbuf_sampr = 0; static size_t chunk_ridx; static size_t chunk_widx; @@ -481,7 +484,7 @@ void * pcmbuf_request_buffer(int *count) if (low_latency_mode) { /* 1/4s latency. */ - if (remaining > DATA_LEVEL(1)) + if (remaining > data_level(1)) return NULL; } @@ -723,7 +726,7 @@ void pcmbuf_start_track_change(enum pcm_track_change_type type) else if (crossfade_setting != CROSSFADE_ENABLE_OFF) { if (crossfade_status == CROSSFADE_INACTIVE && - pcmbuf_unplayed_bytes() >= DATA_LEVEL(2) && + pcmbuf_unplayed_bytes() >= data_level(2) && !low_latency_mode) { switch (crossfade_setting) @@ -836,6 +839,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 +854,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); } } @@ -1141,7 +1153,7 @@ static void crossfade_start(void) size_t unplayed = pcmbuf_unplayed_bytes(); /* Reject crossfade if less than .5s of data */ - if (unplayed < DATA_LEVEL(2)) + if (unplayed < data_level(2)) { logf("crossfade rejected"); crossfade_cancel(); @@ -1437,13 +1449,3 @@ void pcmbuf_set_low_latency(bool state) { low_latency_mode = state; } - -void pcmbuf_update_frequency(void) -{ - pcmbuf_sampr = mixer_get_frequency(); -} - -unsigned int pcmbuf_get_frequency(void) -{ - return pcmbuf_sampr; -} diff --git a/apps/pcmbuf.h b/apps/pcmbuf.h index a9daed23cc..846a7d868f 100644 --- a/apps/pcmbuf.h +++ b/apps/pcmbuf.h @@ -80,7 +80,5 @@ void pcmbuf_sync_position_update(void); /* Misc */ bool pcmbuf_is_lowdata(void); void pcmbuf_set_low_latency(bool state); -void pcmbuf_update_frequency(void); -unsigned int pcmbuf_get_frequency(void); #endif /* PCMBUF_H */ diff --git a/apps/playback.c b/apps/playback.c index 1e21660fe6..eeb4aca86e 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -3036,7 +3036,6 @@ static void audio_start_playback(const struct audio_resume_info *resume_info, skip_resume_adjustments = id3_get(PLAYING_ID3)->skip_resume_adjustments; track_list_clear(TRACK_LIST_CLEAR_ALL); - pcmbuf_update_frequency(); } else { @@ -3049,7 +3048,6 @@ static void audio_start_playback(const struct audio_resume_info *resume_info, pcmbuf_start_track_change(TRACK_CHANGE_MANUAL); wipe_track_metadata(true); } - pcmbuf_update_frequency(); /* Set after track finish event in case skip was in progress */ skip_pending = TRACK_SKIP_NONE; @@ -3071,7 +3069,6 @@ static void audio_start_playback(const struct audio_resume_info *resume_info, #ifndef PLATFORM_HAS_VOLUME_CHANGE sound_set_volume(global_status.volume); #endif - pcmbuf_update_frequency(); /* Be sure channel is audible */ pcmbuf_fade(false, true); @@ -4315,7 +4312,6 @@ void INIT_ATTR playback_init(void) mutex_init(&id3_mutex); track_list_init(); buffering_init(); - pcmbuf_update_frequency(); #ifdef HAVE_CROSSFADE /* Set crossfade setting for next buffer init which should be about... */ pcmbuf_request_crossfade_enable(global_settings.crossfade); diff --git a/apps/plugin.h b/apps/plugin.h index 4eb83fbad5..5dcbdcaee7 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -179,7 +179,7 @@ int plugin_open(const char *plugin, const char *parameter); * when this happens please take the opportunity to sort in * any new functions "waiting" at the end of the list. */ -#define PLUGIN_API_VERSION 281 +#define PLUGIN_API_VERSION 282 /* 239 Marks the removal of ARCHOS HWCODEC and CHARCELL */ @@ -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); @@ -790,7 +790,7 @@ struct plugin_api { unsigned int amplitude); size_t (*mixer_channel_get_bytes_waiting)(enum pcm_mixer_channel channel); void (*mixer_channel_set_buffer_hook)(enum pcm_mixer_channel channel, - chan_buffer_hook_fn_type fn); + const struct mixer_buffer_cbs* cbs); void (*mixer_set_frequency)(unsigned int samplerate); unsigned int (*mixer_get_frequency)(void); void (*pcmbuf_fade)(bool fade, bool in); 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/oscilloscope.c b/apps/plugins/oscilloscope.c index 49c0aeda4e..123fee2541 100644 --- a/apps/plugins/oscilloscope.c +++ b/apps/plugins/oscilloscope.c @@ -1441,6 +1441,10 @@ static void waveform_buffer_callback(const void *start, size_t size) waveform_buffer_have = have + copy; } +static const struct mixer_buffer_cbs buf_cbs = { + .next_buffer = waveform_buffer_callback, +}; + static void waveform_buffer_reset(void) { /* only called when callback is off */ @@ -1909,7 +1913,7 @@ static void graphmode_setup(void) if (osc.graphmode == GRAPH_WAVEFORM) { rb->mixer_channel_set_buffer_hook(channel, - waveform_buffer_callback); + &buf_cbs); #ifdef HAVE_SCHEDULER_BOOSTCTRL rb->trigger_cpu_boost(); /* Just looks better */ #endif @@ -2013,7 +2017,7 @@ void switch_channel(enum pcm_mixer_channel new_channel) #ifdef OSCILLOSCOPE_GRAPHMODE if (osc.graphmode == GRAPH_WAVEFORM) - rb->mixer_channel_set_buffer_hook(channel, waveform_buffer_callback); + rb->mixer_channel_set_buffer_hook(channel, &buf_cbs); #endif } #endif /* USB_ENABLE_AUDIO */ 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..01acbe2181 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 @@ -1624,7 +1624,7 @@ void mixer_channel_set_amplitude(enum pcm_mixer_channel channel, unsigned int am \param amplitude \description -void mixer_channel_set_buffer_hook(enum pcm_mixer_channel channel, chan_buffer_hook_fn_type fn) +void mixer_channel_set_buffer_hook(enum pcm_mixer_channel channel, const struct mixer_buffer_cbs* cbs) \param channel \param fn \description diff --git a/firmware/export/pcm_mixer.h b/firmware/export/pcm_mixer.h index 6dcbb9e4d4..0607b474f6 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) */ @@ -128,12 +133,15 @@ void mixer_channel_calculate_peaks(enum pcm_mixer_channel channel, void mixer_adjust_channel_address(enum pcm_mixer_channel channel, off_t offset); -/* Set a hook that is called upon getting a new source buffer for a channel - NOTE: Called for each buffer, not each mixer chunk */ -typedef void (*chan_buffer_hook_fn_type)(const void *start, size_t size); +struct mixer_buffer_cbs { + /* Called for each buffer, not each mixer chunk */ + void (*next_buffer)(const void *start, size_t size); + void (*sampr_changed)(uint32_t sampr); +}; +/* Set a hook that is called upon getting a new source buffer for a channel */ void mixer_channel_set_buffer_hook(enum pcm_mixer_channel channel, - chan_buffer_hook_fn_type fn); + const struct mixer_buffer_cbs* cbs); /* Stop ALL channels and PCM and reset state */ void mixer_reset(void); diff --git a/firmware/pcm_mixer.c b/firmware/pcm_mixer.c index a0d26fc86d..e49e3648b0 100644 --- a/firmware/pcm_mixer.c +++ b/firmware/pcm_mixer.c @@ -33,7 +33,6 @@ before the last samples are sent to the codec and so things are done in parallel (as much as possible) with sending-out data. */ -static unsigned int mixer_sampr = -1U; static unsigned int mix_frame_size = MIX_FRAME_SAMPLES*4; /* Define this to nonzero to add a marker pulse at each frame start */ @@ -42,13 +41,13 @@ 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 */ - chan_buffer_hook_fn_type buffer_hook; /* Callback for new buffer */ + 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* play_cbs; /* Registered callbacks */ + enum channel_status status; /* Playback status */ + uint32_t amplitude; /* Amp. factor: 0x0000 = mute, 0x10000 = unity */ + const struct mixer_buffer_cbs* buf_cbs; /* Callback for new buffer */ }; #if (defined(HW_HAVE_192) || defined(HW_HAVE_176)) @@ -75,9 +74,19 @@ static struct mixer_channel channels[PCM_MIXER_NUM_CHANNELS] IBSS_ATTR; static struct mixer_channel * active_channels[PCM_MIXER_NUM_CHANNELS+1] IBSS_ATTR; /* Number of silence frames to play after all data has played */ -#define MAX_IDLE_FRAMES (mixer_sampr*3 / (mix_frame_size / 4)) static unsigned int idle_counter = 0; +#ifdef CONFIG_SAMPR_TYPES +#define SAMPR_NUM(sampr) (sampr & ~SAMPR_TYPE_MASK) +#else +#define SAMPR_NUM(sampr) (sampr) +#endif + +static inline unsigned int max_idle_frames(void) +{ + return SAMPR_NUM(pcm_get_frequency()) * 3 / (mix_frame_size / 4); +} + /** Mixing routines, CPU optmized **/ #include "asm/pcm-mixer.c" @@ -119,8 +128,8 @@ static void mixer_pcm_callback(const void **addr, size_t *size) static inline void chan_call_buffer_hook(struct mixer_channel *chan) { - if (UNLIKELY(chan->buffer_hook)) - chan->buffer_hook(chan->start, chan->size); + if (UNLIKELY(chan->buf_cbs && chan->buf_cbs->next_buffer)) + chan->buf_cbs->next_buffer(chan->start, chan->size); } /* Buffering callback - calls sub-callbacks and mixes the data for next @@ -154,9 +163,9 @@ fill_frame: if (chan->size == 0) { - if (chan->get_more) + if (chan->play_cbs->get_more) { - chan->get_more(&chan->start, &chan->size); + chan->play_cbs->get_more(&chan->start, &chan->size); ALIGN_AUDIOBUF(chan->start, chan->size); } @@ -233,7 +242,7 @@ fill_frame: goto fill_frame; } } - else if (idle_counter++ < MAX_IDLE_FRAMES) + else if (idle_counter++ < max_idle_frames()) { /* Pad incomplete frames with silence */ if (idle_counter <= 3) @@ -265,12 +274,6 @@ static void mixer_start_pcm(void) return; #endif - /* Requires a shared global sample rate for all channels */ - if (mixer_sampr == -1U) - mixer_sampr = pcm_get_frequency(); - else - pcm_set_frequency(mixer_sampr); - /* Prepare initial frames and set up the double buffer */ mixer_buffer_callback(PCM_DMAST_STARTED); @@ -287,14 +290,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 +307,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 +320,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->play_cbs = cbs; mixer_activate_channel(chan); chan_call_buffer_hook(chan); @@ -429,15 +432,14 @@ void mixer_adjust_channel_address(enum pcm_mixer_channel channel, pcm_play_unlock(); } -/* Set a hook that is called upon getting a new source buffer for a channel - NOTE: Called for each buffer, not each mixer chunk */ +/* Set a hook that is called upon getting a new source buffer for a channel */ void mixer_channel_set_buffer_hook(enum pcm_mixer_channel channel, - chan_buffer_hook_fn_type fn) + const struct mixer_buffer_cbs* cbs) { struct mixer_channel *chan = &channels[channel]; pcm_play_lock(); - chan->buffer_hook = fn; + chan->buf_cbs = cbs; pcm_play_unlock(); } @@ -455,24 +457,51 @@ void mixer_reset(void) /* Set output samplerate */ void mixer_set_frequency(unsigned int samplerate) { - pcm_set_frequency(samplerate); - samplerate = pcm_get_frequency(); - -#ifdef CONFIG_SAMPR_TYPES - samplerate &= ~SAMPR_TYPE_MASK; -#endif - - if (samplerate == mixer_sampr) + if(pcm_get_frequency() == samplerate) return; - /* All data is now invalid */ - mixer_reset(); - mixer_sampr = samplerate; + pcm_set_frequency(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->play_cbs) + { + if (chan->play_cbs->sampr_changed) + { + chan->play_cbs->sampr_changed(SAMPR_NUM(samplerate)); + } + if (chan->play_cbs->get_more) + { + /* Remake buffer */ + const void *start = NULL; + size_t size; + chan->play_cbs->get_more(&start, &size); + if (start && size) { + chan->start = start; + chan->size = size; + chan->last_size = 0; + } else { + channel_stopped(chan); + } + } + } + /* Notify buffer monitor */ + if (chan->buf_cbs) + { + if (chan->buf_cbs->sampr_changed) + { + chan->buf_cbs->sampr_changed(SAMPR_NUM(samplerate)); + } + } + } /* Work out how much space we really need */ - if (samplerate > SAMPR_96) + if (SAMPR_NUM(samplerate) > SAMPR_96) mix_frame_size = 4; - else if (samplerate > SAMPR_48) + else if (SAMPR_NUM(samplerate) > SAMPR_48) mix_frame_size = 2; else mix_frame_size = 1; @@ -486,5 +515,5 @@ void mixer_set_frequency(unsigned int samplerate) /* Get output samplerate */ unsigned int mixer_get_frequency(void) { - return mixer_sampr; + return pcm_get_frequency(); } 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;