pcm_mixer: introduce mixer_play_cbs

the added sampr_changed callback can be used to notify the mixer user of
frequency changes

Change-Id: I309db76576090fd5c019a1ba082af446129dd4a3
This commit is contained in:
mojyack 2026-03-31 10:42:54 +09:00 committed by Solomon Peachy
parent 86639acc5e
commit cb04b8167c
20 changed files with 128 additions and 47 deletions

View file

@ -97,7 +97,7 @@ void beep_play(unsigned int frequency, unsigned int duration,
beep_get_more(&start, &size); beep_get_more(&start, &size);
mixer_channel_set_amplitude(PCM_MIXER_CHAN_BEEP, MIX_AMP_UNITY); mixer_channel_set_amplitude(PCM_MIXER_CHAN_BEEP, MIX_AMP_UNITY);
mixer_channel_play_data(PCM_MIXER_CHAN_BEEP, static struct mixer_play_cbs cbs;
beep_count ? beep_get_more : NULL, cbs.get_more = beep_count ? beep_get_more : NULL;
start, size); mixer_channel_play_data(PCM_MIXER_CHAN_BEEP, &cbs, start, size);
} }

View file

@ -29,6 +29,7 @@
#include "pcmbuf.h" #include "pcmbuf.h"
#include "dsp-util.h" #include "dsp-util.h"
#include "playback.h" #include "playback.h"
#include "dsp_core.h"
#include "codec_thread.h" #include "codec_thread.h"
/* Define LOGF_ENABLE to enable logf output in this file */ /* 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 */ /* Force playback */
void pcmbuf_play_start(void) void pcmbuf_play_start(void)
{ {
@ -845,8 +852,11 @@ void pcmbuf_play_start(void)
chunk_widx != chunk_ridx) chunk_widx != chunk_ridx)
{ {
current_desc = NULL; current_desc = NULL;
mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, pcmbuf_pcm_callback, static const struct mixer_play_cbs cbs = {
NULL, 0); .get_more = pcmbuf_pcm_callback,
.sampr_changed = pcmbuf_sampr_callback,
};
mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, &cbs, NULL, 0);
} }
} }

View file

@ -782,7 +782,7 @@ struct plugin_api {
void (*mixer_channel_calculate_peaks)(enum pcm_mixer_channel channel, void (*mixer_channel_calculate_peaks)(enum pcm_mixer_channel channel,
struct pcm_peaks *peaks); struct pcm_peaks *peaks);
void (*mixer_channel_play_data)(enum pcm_mixer_channel 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); const void *start, size_t size);
void (*mixer_channel_play_pause)(enum pcm_mixer_channel channel, bool play); void (*mixer_channel_play_pause)(enum pcm_mixer_channel channel, bool play);
void (*mixer_channel_stop)(enum pcm_mixer_channel channel); void (*mixer_channel_stop)(enum pcm_mixer_channel channel);

View file

@ -466,7 +466,10 @@ void I_SubmitSound(void)
if (!enable_sound) if (!enable_sound)
return; 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) void I_ShutdownSound(void)

View file

@ -507,6 +507,10 @@ UNUSED_ATTR static int find_min_sampr_ge_22(void)
return ret; return ret;
} }
static const struct mixer_play_cbs mixer_cbs = {
.get_more = get_more,
};
static int midimain(const void * filename) static int midimain(const void * filename)
{ {
int a, notes_used, vol; int a, notes_used, vol;
@ -625,7 +629,7 @@ static int midimain(const void * filename)
#endif #endif
rb->pcmbuf_fade(false, true); 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) while (!quit)
{ {
@ -684,7 +688,7 @@ static int midimain(const void * filename)
#endif #endif
midi_debug("Rewind to %d:%02d\n", playing_time/60, playing_time%60); midi_debug("Rewind to %d:%02d\n", playing_time/60, playing_time%60);
if (is_playing) 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; break;
} }
@ -706,7 +710,7 @@ static int midimain(const void * filename)
#endif #endif
midi_debug("Skip to %d:%02d\n", playing_time/60, playing_time%60); midi_debug("Skip to %d:%02d\n", playing_time/60, playing_time%60);
if (is_playing) 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; break;
} }

View file

@ -292,6 +292,10 @@ static void get_more(const void** start, size_t* size)
#endif #endif
} }
static const struct mixer_play_cbs mixer_cbs = {
.get_more = get_more,
};
static void showinfo(void) static void showinfo(void)
{ {
char statustext[LINE_LENGTH]; char statustext[LINE_LENGTH];
@ -600,10 +604,9 @@ static void applysettings(void)
} }
// MikMod_Reset(""); BROKEN! // MikMod_Reset(""); BROKEN!
rb->mixer_channel_stop(PCM_MIXER_CHAN_PLAYBACK); rb->mixer_channel_stop(PCM_MIXER_CHAN_PLAYBACK);
rb->mixer_set_frequency(md_mixfreq); rb->mixer_set_frequency(md_mixfreq);
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 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
@ -810,7 +813,7 @@ static int playfile(char* filename)
display = DISPLAY_INFO; display = DISPLAY_INFO;
Player_Start(module); Player_Start(module);
rb->pcmbuf_fade(false, true); 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 #ifdef HAVE_ADJUSTABLE_CPU_FREQ

View file

@ -173,6 +173,10 @@ static void get_more(const void **start, size_t *size)
pcmbuf_read = pcmbuf_written; pcmbuf_read = pcmbuf_written;
} }
static const struct mixer_play_cbs mixer_cbs = {
.get_more = get_more,
};
/** Public interface **/ /** Public interface **/
/* Return a buffer pointer if at least size bytes are available and if so, /* 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 */ /* Restart if playing state was current */
if (status == CHANNEL_PLAYING) if (status == CHANNEL_PLAYING)
rb->mixer_channel_play_data(MPEG_PCM_CHANNEL, rb->mixer_channel_play_data(MPEG_PCM_CHANNEL, &mixer_cbs, NULL, 0);
get_more, NULL, 0);
} }
/* Seek the reference clock to the specified time - next audio data ready to /* 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) if (play)
{ {
rb->mixer_channel_set_amplitude(MPEG_PCM_CHANNEL, MIX_AMP_UNITY); rb->mixer_channel_set_amplitude(MPEG_PCM_CHANNEL, MIX_AMP_UNITY);
rb->mixer_channel_play_data(MPEG_PCM_CHANNEL, rb->mixer_channel_play_data(MPEG_PCM_CHANNEL, &mixer_cbs, NULL, 0);
get_more, NULL, 0);
} }
} }
} }

View file

@ -407,8 +407,11 @@ static void start_sound(void)
wsg3_set_sampling_rate(caps->samprs[sr_index]); 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_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; sound_playing = true;
} }

View file

@ -181,7 +181,10 @@ int rockbox_send_dacs(void)
if(!playing && outbuf_fill > 0) if(!playing && outbuf_fill > 0)
{ {
/* Start playing. */ /* 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. */ /* Set status flag. */
playing = true; playing = true;

View file

@ -73,7 +73,10 @@ int rockboy_pcm_submit(void)
if(newly_started) 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; newly_started = false;
} }

View file

@ -288,7 +288,10 @@ static int ROCKBOXAUD_OpenAudio(_THIS, SDL_AudioSpec *spec)
rbaud_underruns = 0; 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. :-) */ /* We're ready to rock and roll. :-) */
return(0); return(0);

View file

@ -237,7 +237,10 @@ static void play_tone(bool volume_set)
IF_PRIO(, PRIORITY_PLAYBACK) IF_PRIO(, PRIORITY_PLAYBACK)
IF_COP(, CPU)); 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 #ifndef HAVE_VOLUME_IN_LIST
if (volume_set) if (volume_set)

View file

@ -222,8 +222,11 @@ void syssnd_update(void)
if (!isAudioPlaying && fillCount > 0) if (!isAudioPlaying && fillCount > 0)
{ {
static const struct mixer_play_cbs cbs = {
.get_more = get_more,
};
isAudioPlaying = true; 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);
} }
} }
} }

View file

@ -1029,7 +1029,10 @@ void sys_startAudio(struct System* sys, AudioCallback callback, void *param)
audio_param = param; audio_param = param;
audio_sys = sys; 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) void sys_stopAudio(struct System* sys)

View file

@ -212,7 +212,10 @@ static void write_buf(void){
= my_buf[j+10] = my_buf[j+11] \ = my_buf[j+10] = my_buf[j+11] \
= (((byte)sp_sound_buf[i])<<8) >> settings.volume; = (((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 #if 0
/* can use to save and later analyze what we produce */ /* can use to save and later analyze what we produce */

View file

@ -245,8 +245,10 @@ static void voice_start_playback(void)
struct voice_pcm_frame *frame = struct voice_pcm_frame *frame =
&voice_buf->frames[voice_buf->frame_out % VOICE_FRAMES]; &voice_buf->frames[voice_buf->frame_out % VOICE_FRAMES];
mixer_channel_play_data(PCM_MIXER_CHAN_VOICE, voice_pcm_callback, static const struct mixer_play_cbs cbs = {
frame->pcm, frame->size); .get_more = voice_pcm_callback,
};
mixer_channel_play_data(PCM_MIXER_CHAN_VOICE, &cbs, frame->pcm, frame->size);
} }
/* Stop the voice channel */ /* Stop the voice channel */

View file

@ -1607,9 +1607,9 @@ size_t mixer_channel_get_bytes_waiting(enum pcm_mixer_channel channel)
\return \return
\description \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 channel
\param get_more \param cbs
\param start \param start
\param size \param size
\description \description

View file

@ -96,8 +96,13 @@ enum channel_status
/** Public interfaces **/ /** Public interfaces **/
/* Start playback on a channel */ /* 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, 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); const void *start, size_t size);
/* Pause or resume a channel (when started) */ /* Pause or resume a channel (when started) */

View file

@ -42,12 +42,12 @@ static unsigned int mix_frame_size = MIX_FRAME_SAMPLES*4;
/* Descriptor for each channel */ /* Descriptor for each channel */
struct mixer_channel struct mixer_channel
{ {
const void *start; /* Buffer pointer */ const void *start; /* Buffer pointer */
size_t size; /* Bytes remaining */ size_t size; /* Bytes remaining */
size_t last_size; /* Size of consumed data in prev. cycle */ size_t last_size; /* Size of consumed data in prev. cycle */
pcm_play_callback_type get_more; /* Registered callback */ const struct mixer_play_cbs* cbs; /* Registered callbacks */
enum channel_status status; /* Playback status */ enum channel_status status; /* Playback status */
uint32_t amplitude; /* Amp. factor: 0x0000 = mute, 0x10000 = unity */ uint32_t amplitude; /* Amp. factor: 0x0000 = mute, 0x10000 = unity */
chan_buffer_hook_fn_type buffer_hook; /* Callback for new buffer */ chan_buffer_hook_fn_type buffer_hook; /* Callback for new buffer */
}; };
@ -154,9 +154,9 @@ fill_frame:
if (chan->size == 0) 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); ALIGN_AUDIOBUF(chan->start, chan->size);
} }
@ -287,14 +287,14 @@ static void mixer_start_pcm(void)
/* Start playback on a channel */ /* Start playback on a channel */
void mixer_channel_play_data(enum pcm_mixer_channel 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) const void *start, size_t size)
{ {
struct mixer_channel *chan = &channels[channel]; struct mixer_channel *chan = &channels[channel];
ALIGN_AUDIOBUF(start, size); ALIGN_AUDIOBUF(start, size);
if (!(start && size) && get_more) if (!(start && size) && cbs && cbs->get_more)
{ {
/* Initial buffer not passed - call the callback now */ /* Initial buffer not passed - call the callback now */
pcm_play_lock(); 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 */ pcm_play_unlock(); /* Allow playback while doing callback */
size = 0; size = 0;
get_more(&start, &size); cbs->get_more(&start, &size);
ALIGN_AUDIOBUF(start, size); ALIGN_AUDIOBUF(start, size);
} }
@ -317,7 +317,7 @@ void mixer_channel_play_data(enum pcm_mixer_channel channel,
chan->start = start; chan->start = start;
chan->size = size; chan->size = size;
chan->last_size = 0; chan->last_size = 0;
chan->get_more = get_more; chan->cbs = cbs;
mixer_activate_channel(chan); mixer_activate_channel(chan);
chan_call_buffer_hook(chan); chan_call_buffer_hook(chan);
@ -464,11 +464,36 @@ void mixer_set_frequency(unsigned int samplerate)
if (samplerate == mixer_sampr) if (samplerate == mixer_sampr)
return; return;
/* All data is now invalid */
mixer_reset();
mixer_sampr = samplerate; 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 */ /* Work out how much space we really need */
if (samplerate > SAMPR_96) if (samplerate > SAMPR_96)
mix_frame_size = 4; mix_frame_size = 4;

View file

@ -1337,7 +1337,10 @@ bool usb_audio_fast_transfer_complete(int ep, int dir, int status, int length)
logf("usbaudio: prebuffering done"); logf("usbaudio: prebuffering done");
playback_audio_underflow = false; playback_audio_underflow = false;
usb_rx_overflow = 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); restore_irq(oldlevel);
retval = true; retval = true;