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);
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);
}

View file

@ -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)
{

View file

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

View file

@ -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;
}

View file

@ -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 */

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;
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);

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
* 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);

View file

@ -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)

View file

@ -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;
}

View file

@ -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_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

View file

@ -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);
}
}
}

View file

@ -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 */

View file

@ -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;
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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);

View file

@ -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)

View file

@ -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);
}
}
}

View file

@ -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)

View file

@ -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 */

View file

@ -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 */

View file

@ -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

View file

@ -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);

View file

@ -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 */
@ -45,10 +44,10 @@ 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 */
const struct mixer_play_cbs* play_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 */
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();
}

View file

@ -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;