Compare commits

...

5 commits

Author SHA1 Message Date
Vencislav Atanasov
4dbcb13f58 bulgarian: Change some USB-related voice strings
Change-Id: I4c129b3672b6ffa21a8f11ca1146ffa4933474d5
2026-04-14 08:02:51 -04:00
mojyack
cfb01cfd58 pcmbuf: remove pcmbuf_sampr
Change-Id: I5da91acbf8a3e23446d38b9e62d4e1c67d41aba9
2026-04-14 07:44:16 -04:00
mojyack
498a9fffeb pcm_mixer: remove mixer_sampr
Change-Id: I693b3c2ab639f09e918790dd6a06977991f872cc
2026-04-14 07:43:35 -04:00
mojyack
e2040cc98c pcm_mixer: introduce mixer_buffer_cbs
intended to add sampr_changed callback to buffer hook as well as mixer
playback

Change-Id: I9df6194a884cfb813342a827b7fdc3bccbe3d60c
2026-04-14 06:50:39 -04:00
mojyack
cb04b8167c 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
2026-04-14 06:47:36 -04:00
25 changed files with 199 additions and 120 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

@ -26,6 +26,7 @@
#include "kernel.h" #include "kernel.h"
#include "codecs.h" #include "codecs.h"
#include "codec_thread.h" #include "codec_thread.h"
#include "pcm_mixer.h"
#include "pcmbuf.h" #include "pcmbuf.h"
#include "audio_thread.h" #include "audio_thread.h"
#include "playback.h" #include "playback.h"
@ -518,7 +519,7 @@ static void run_codec(void)
codec_queue_ack(Q_CODEC_RUN); codec_queue_ack(Q_CODEC_RUN);
trigger_cpu_boost(); 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) if (!encoder)
{ {

View file

@ -5902,7 +5902,7 @@
</dest> </dest>
<voice> <voice>
*: none *: none
hibylinux: "~U S B" hibylinux: "Ю Ес Би"
multivolume: "~H D 1" multivolume: "~H D 1"
sansac200*,sansaclipplus,sansae200*,sansafuze*: "микро S D" sansac200*,sansaclipplus,sansae200*,sansafuze*: "микро S D"
xduoox3: "микро S D 2" xduoox3: "микро S D 2"
@ -7004,7 +7004,7 @@
</dest> </dest>
<voice> <voice>
*: none *: none
usb_charging_enable: "Зареждане по време на USB връзка" usb_charging_enable: "Зареждане по време на Ю Ес Би връзка"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -10103,7 +10103,7 @@
</dest> </dest>
<voice> <voice>
*: none *: none
usb_hid: "Режим USB клавиатура" usb_hid: "Режим Ю Ес Би клавиатура"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -10490,11 +10490,11 @@
</source> </source>
<dest> <dest>
*: none *: none
usb_hid: "USB УЧИ" usb_hid: "USB у-во за човешки интерфейс"
</dest> </dest>
<voice> <voice>
*: none *: none
usb_hid: "USB устройство за човешки интерфейс" usb_hid: "Ю Ес Би устройство за човешки интерфейс"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -11230,7 +11230,7 @@
</dest> </dest>
<voice> <voice>
*: none *: none
multidrive_usb: "USB скриване на вътрешната памет" multidrive_usb: "Ю Ес Би скриване на вътрешната памет"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -15080,7 +15080,7 @@
*: "Влез в режим USB памет?" *: "Влез в режим USB памет?"
</dest> </dest>
<voice> <voice>
*: "Влез в режим USB памет?" *: "Влез в режим Ю Ес Би памет?"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -16873,11 +16873,11 @@
</source> </source>
<dest> <dest>
*: none *: none
usbdac: "USB-ЦАП" usbdac: "USB ЦАП"
</dest> </dest>
<voice> <voice>
*: none *: none
usbdac: "USB ЦАП" usbdac: "Ю Ес Би цифрово-аналогов преобразувател"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -16894,7 +16894,7 @@
</dest> </dest>
<voice> <voice>
*: none *: none
usbdac: "В режим USB само зареждане" usbdac: "В режим Ю Ес Би само зареждане"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -16911,7 +16911,7 @@
</dest> </dest>
<voice> <voice>
*: none *: none
usbdac: "В режим USB памет" usbdac: "В режим Ю Ес Би памет"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -16924,11 +16924,11 @@
</source> </source>
<dest> <dest>
*: none *: none
usbdac: "USB-ЦАП е активен" usbdac: "USB ЦАП е активен"
</dest> </dest>
<voice> <voice>
*: none *: none
usbdac: "USB ЦАП е активен" usbdac: "Ю Ес Би цифрово-аналогов преобразувател е активен"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>

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 */
@ -68,17 +69,20 @@
chunks */ chunks */
/* Return data level in 1/4-second increments */ /* 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 */ /* Number of bytes played per second */
#define BYTERATE (pcmbuf_sampr * PCMBUF_SAMPLE_SIZE) #define BYTERATE (mixer_get_frequency() * PCMBUF_SAMPLE_SIZE)
#if MEMORYSIZE > 2 #if MEMORYSIZE > 2
/* Keep watermark high for large memory target - at least (2s) */ /* Keep watermark high for large memory target - at least (2s) */
#define PCMBUF_WATERMARK (BYTERATE * 2) #define PCMBUF_WATERMARK (BYTERATE * 2)
#define MIN_BUFFER_SIZE (BYTERATE * 3) #define MIN_BUFFER_SIZE (BYTERATE * 3)
/* 1 seconds of buffer is low data */ /* 1 seconds of buffer is low data */
#define LOW_DATA DATA_LEVEL(4) #define LOW_DATA data_level(4)
#else #else
#define PCMBUF_WATERMARK (BYTERATE / 4) /* 0.25 seconds */ #define PCMBUF_WATERMARK (BYTERATE / 4) /* 0.25 seconds */
#define MIN_BUFFER_SIZE (BYTERATE * 1) #define MIN_BUFFER_SIZE (BYTERATE * 1)
@ -108,7 +112,6 @@ static size_t pcmbuf_size;
static struct chunkdesc *pcmbuf_descriptors; static struct chunkdesc *pcmbuf_descriptors;
static unsigned int pcmbuf_desc_count; static unsigned int pcmbuf_desc_count;
static unsigned int position_key = 1; static unsigned int position_key = 1;
static unsigned int pcmbuf_sampr = 0;
static size_t chunk_ridx; static size_t chunk_ridx;
static size_t chunk_widx; static size_t chunk_widx;
@ -481,7 +484,7 @@ void * pcmbuf_request_buffer(int *count)
if (low_latency_mode) if (low_latency_mode)
{ {
/* 1/4s latency. */ /* 1/4s latency. */
if (remaining > DATA_LEVEL(1)) if (remaining > data_level(1))
return NULL; return NULL;
} }
@ -723,7 +726,7 @@ void pcmbuf_start_track_change(enum pcm_track_change_type type)
else if (crossfade_setting != CROSSFADE_ENABLE_OFF) else if (crossfade_setting != CROSSFADE_ENABLE_OFF)
{ {
if (crossfade_status == CROSSFADE_INACTIVE && if (crossfade_status == CROSSFADE_INACTIVE &&
pcmbuf_unplayed_bytes() >= DATA_LEVEL(2) && pcmbuf_unplayed_bytes() >= data_level(2) &&
!low_latency_mode) !low_latency_mode)
{ {
switch (crossfade_setting) 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 */ /* Force playback */
void pcmbuf_play_start(void) void pcmbuf_play_start(void)
{ {
@ -845,8 +854,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);
} }
} }
@ -1141,7 +1153,7 @@ static void crossfade_start(void)
size_t unplayed = pcmbuf_unplayed_bytes(); size_t unplayed = pcmbuf_unplayed_bytes();
/* Reject crossfade if less than .5s of data */ /* Reject crossfade if less than .5s of data */
if (unplayed < DATA_LEVEL(2)) if (unplayed < data_level(2))
{ {
logf("crossfade rejected"); logf("crossfade rejected");
crossfade_cancel(); crossfade_cancel();
@ -1437,13 +1449,3 @@ void pcmbuf_set_low_latency(bool state)
{ {
low_latency_mode = state; low_latency_mode = state;
} }
void pcmbuf_update_frequency(void)
{
pcmbuf_sampr = mixer_get_frequency();
}
unsigned int pcmbuf_get_frequency(void)
{
return pcmbuf_sampr;
}

View file

@ -80,7 +80,5 @@ void pcmbuf_sync_position_update(void);
/* Misc */ /* Misc */
bool pcmbuf_is_lowdata(void); bool pcmbuf_is_lowdata(void);
void pcmbuf_set_low_latency(bool state); void pcmbuf_set_low_latency(bool state);
void pcmbuf_update_frequency(void);
unsigned int pcmbuf_get_frequency(void);
#endif /* PCMBUF_H */ #endif /* PCMBUF_H */

View file

@ -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; skip_resume_adjustments = id3_get(PLAYING_ID3)->skip_resume_adjustments;
track_list_clear(TRACK_LIST_CLEAR_ALL); track_list_clear(TRACK_LIST_CLEAR_ALL);
pcmbuf_update_frequency();
} }
else else
{ {
@ -3049,7 +3048,6 @@ static void audio_start_playback(const struct audio_resume_info *resume_info,
pcmbuf_start_track_change(TRACK_CHANGE_MANUAL); pcmbuf_start_track_change(TRACK_CHANGE_MANUAL);
wipe_track_metadata(true); wipe_track_metadata(true);
} }
pcmbuf_update_frequency();
/* Set after track finish event in case skip was in progress */ /* Set after track finish event in case skip was in progress */
skip_pending = TRACK_SKIP_NONE; 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 #ifndef PLATFORM_HAS_VOLUME_CHANGE
sound_set_volume(global_status.volume); sound_set_volume(global_status.volume);
#endif #endif
pcmbuf_update_frequency();
/* Be sure channel is audible */ /* Be sure channel is audible */
pcmbuf_fade(false, true); pcmbuf_fade(false, true);
@ -4315,7 +4312,6 @@ void INIT_ATTR playback_init(void)
mutex_init(&id3_mutex); mutex_init(&id3_mutex);
track_list_init(); track_list_init();
buffering_init(); buffering_init();
pcmbuf_update_frequency();
#ifdef HAVE_CROSSFADE #ifdef HAVE_CROSSFADE
/* Set crossfade setting for next buffer init which should be about... */ /* Set crossfade setting for next buffer init which should be about... */
pcmbuf_request_crossfade_enable(global_settings.crossfade); pcmbuf_request_crossfade_enable(global_settings.crossfade);

View file

@ -179,7 +179,7 @@ int plugin_open(const char *plugin, const char *parameter);
* when this happens please take the opportunity to sort in * when this happens please take the opportunity to sort in
* any new functions "waiting" at the end of the list. * 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 */ /* 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, 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);
@ -790,7 +790,7 @@ struct plugin_api {
unsigned int amplitude); unsigned int amplitude);
size_t (*mixer_channel_get_bytes_waiting)(enum pcm_mixer_channel channel); size_t (*mixer_channel_get_bytes_waiting)(enum pcm_mixer_channel channel);
void (*mixer_channel_set_buffer_hook)(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); void (*mixer_set_frequency)(unsigned int samplerate);
unsigned int (*mixer_get_frequency)(void); unsigned int (*mixer_get_frequency)(void);
void (*pcmbuf_fade)(bool fade, bool in); void (*pcmbuf_fade)(bool fade, bool in);

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

@ -1441,6 +1441,10 @@ static void waveform_buffer_callback(const void *start, size_t size)
waveform_buffer_have = have + copy; waveform_buffer_have = have + copy;
} }
static const struct mixer_buffer_cbs buf_cbs = {
.next_buffer = waveform_buffer_callback,
};
static void waveform_buffer_reset(void) static void waveform_buffer_reset(void)
{ {
/* only called when callback is off */ /* only called when callback is off */
@ -1909,7 +1913,7 @@ static void graphmode_setup(void)
if (osc.graphmode == GRAPH_WAVEFORM) if (osc.graphmode == GRAPH_WAVEFORM)
{ {
rb->mixer_channel_set_buffer_hook(channel, rb->mixer_channel_set_buffer_hook(channel,
waveform_buffer_callback); &buf_cbs);
#ifdef HAVE_SCHEDULER_BOOSTCTRL #ifdef HAVE_SCHEDULER_BOOSTCTRL
rb->trigger_cpu_boost(); /* Just looks better */ rb->trigger_cpu_boost(); /* Just looks better */
#endif #endif
@ -2013,7 +2017,7 @@ void switch_channel(enum pcm_mixer_channel new_channel)
#ifdef OSCILLOSCOPE_GRAPHMODE #ifdef OSCILLOSCOPE_GRAPHMODE
if (osc.graphmode == GRAPH_WAVEFORM) 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
} }
#endif /* USB_ENABLE_AUDIO */ #endif /* USB_ENABLE_AUDIO */

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
@ -1624,7 +1624,7 @@ void mixer_channel_set_amplitude(enum pcm_mixer_channel channel, unsigned int am
\param amplitude \param amplitude
\description \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 channel
\param fn \param fn
\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) */
@ -128,12 +133,15 @@ void mixer_channel_calculate_peaks(enum pcm_mixer_channel channel,
void mixer_adjust_channel_address(enum pcm_mixer_channel channel, void mixer_adjust_channel_address(enum pcm_mixer_channel channel,
off_t offset); off_t offset);
/* Set a hook that is called upon getting a new source buffer for a channel struct mixer_buffer_cbs {
NOTE: Called for each buffer, not each mixer chunk */ /* Called for each buffer, not each mixer chunk */
typedef void (*chan_buffer_hook_fn_type)(const void *start, size_t size); 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, 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 */ /* Stop ALL channels and PCM and reset state */
void mixer_reset(void); void mixer_reset(void);

View file

@ -33,7 +33,6 @@
before the last samples are sent to the codec and so things are done in before the last samples are sent to the codec and so things are done in
parallel (as much as possible) with sending-out data. */ 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; static unsigned int mix_frame_size = MIX_FRAME_SAMPLES*4;
/* Define this to nonzero to add a marker pulse at each frame start */ /* 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 */ /* 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* play_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 */ const struct mixer_buffer_cbs* buf_cbs; /* Callback for new buffer */
}; };
#if (defined(HW_HAVE_192) || defined(HW_HAVE_176)) #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; static struct mixer_channel * active_channels[PCM_MIXER_NUM_CHANNELS+1] IBSS_ATTR;
/* Number of silence frames to play after all data has played */ /* 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; 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 **/ /** Mixing routines, CPU optmized **/
#include "asm/pcm-mixer.c" #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) static inline void chan_call_buffer_hook(struct mixer_channel *chan)
{ {
if (UNLIKELY(chan->buffer_hook)) if (UNLIKELY(chan->buf_cbs && chan->buf_cbs->next_buffer))
chan->buffer_hook(chan->start, chan->size); chan->buf_cbs->next_buffer(chan->start, chan->size);
} }
/* Buffering callback - calls sub-callbacks and mixes the data for next /* Buffering callback - calls sub-callbacks and mixes the data for next
@ -154,9 +163,9 @@ fill_frame:
if (chan->size == 0) 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); ALIGN_AUDIOBUF(chan->start, chan->size);
} }
@ -233,7 +242,7 @@ fill_frame:
goto fill_frame; goto fill_frame;
} }
} }
else if (idle_counter++ < MAX_IDLE_FRAMES) else if (idle_counter++ < max_idle_frames())
{ {
/* Pad incomplete frames with silence */ /* Pad incomplete frames with silence */
if (idle_counter <= 3) if (idle_counter <= 3)
@ -265,12 +274,6 @@ static void mixer_start_pcm(void)
return; return;
#endif #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 */ /* Prepare initial frames and set up the double buffer */
mixer_buffer_callback(PCM_DMAST_STARTED); mixer_buffer_callback(PCM_DMAST_STARTED);
@ -287,14 +290,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 +307,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 +320,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->play_cbs = cbs;
mixer_activate_channel(chan); mixer_activate_channel(chan);
chan_call_buffer_hook(chan); chan_call_buffer_hook(chan);
@ -429,15 +432,14 @@ void mixer_adjust_channel_address(enum pcm_mixer_channel channel,
pcm_play_unlock(); pcm_play_unlock();
} }
/* Set a hook that is called upon getting a new source buffer for a channel /* Set a hook that is called upon getting a new source buffer for a channel */
NOTE: Called for each buffer, not each mixer chunk */
void mixer_channel_set_buffer_hook(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)
{ {
struct mixer_channel *chan = &channels[channel]; struct mixer_channel *chan = &channels[channel];
pcm_play_lock(); pcm_play_lock();
chan->buffer_hook = fn; chan->buf_cbs = cbs;
pcm_play_unlock(); pcm_play_unlock();
} }
@ -455,24 +457,51 @@ void mixer_reset(void)
/* Set output samplerate */ /* Set output samplerate */
void mixer_set_frequency(unsigned int samplerate) void mixer_set_frequency(unsigned int samplerate)
{ {
pcm_set_frequency(samplerate); if(pcm_get_frequency() == samplerate)
samplerate = pcm_get_frequency();
#ifdef CONFIG_SAMPR_TYPES
samplerate &= ~SAMPR_TYPE_MASK;
#endif
if (samplerate == mixer_sampr)
return; return;
/* All data is now invalid */ pcm_set_frequency(samplerate);
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->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 */ /* Work out how much space we really need */
if (samplerate > SAMPR_96) if (SAMPR_NUM(samplerate) > SAMPR_96)
mix_frame_size = 4; mix_frame_size = 4;
else if (samplerate > SAMPR_48) else if (SAMPR_NUM(samplerate) > SAMPR_48)
mix_frame_size = 2; mix_frame_size = 2;
else else
mix_frame_size = 1; mix_frame_size = 1;
@ -486,5 +515,5 @@ void mixer_set_frequency(unsigned int samplerate)
/* Get output samplerate */ /* Get output samplerate */
unsigned int mixer_get_frequency(void) unsigned int mixer_get_frequency(void)
{ {
return mixer_sampr; return pcm_get_frequency();
} }

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;