1
0
Fork 0
forked from len0rd/rockbox

Get samplerate switching working in the sim to be similar to on target. Make all pcm functions available there as well.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13320 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Michael Sevakis 2007-05-04 15:14:56 +00:00
parent 621cf0788f
commit 2aaf45e643
5 changed files with 258 additions and 91 deletions

View file

@ -309,7 +309,7 @@ static const struct plugin_api rockbox_api = {
utf8seek, utf8seek,
/* sound */ /* sound */
#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) #if CONFIG_CODEC == SWCODEC
sound_default, sound_default,
#endif #endif
sound_set, sound_set,
@ -329,9 +329,7 @@ static const struct plugin_api rockbox_api = {
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
&audio_master_sampr_list[0], &audio_master_sampr_list[0],
&hw_freq_sampr[0], &hw_freq_sampr[0],
#ifndef SIMULATOR
pcm_apply_settings, pcm_apply_settings,
#endif
pcm_play_data, pcm_play_data,
pcm_play_stop, pcm_play_stop,
pcm_set_frequency, pcm_set_frequency,
@ -342,7 +340,6 @@ static const struct plugin_api rockbox_api = {
pcm_calculate_peaks, pcm_calculate_peaks,
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING
&rec_freq_sampr[0], &rec_freq_sampr[0],
#ifndef SIMULATOR
pcm_init_recording, pcm_init_recording,
pcm_close_recording, pcm_close_recording,
pcm_record_data, pcm_record_data,
@ -352,7 +349,6 @@ static const struct plugin_api rockbox_api = {
audio_set_recording_gain, audio_set_recording_gain,
audio_set_output_source, audio_set_output_source,
rec_set_source, rec_set_source,
#endif
#endif /* HAVE_RECORDING */ #endif /* HAVE_RECORDING */
#endif #endif

View file

@ -110,12 +110,12 @@
#define PLUGIN_MAGIC 0x526F634B /* RocK */ #define PLUGIN_MAGIC 0x526F634B /* RocK */
/* increase this every time the api struct changes */ /* increase this every time the api struct changes */
#define PLUGIN_API_VERSION 53 #define PLUGIN_API_VERSION 54
/* update this to latest version if a change to the api struct breaks /* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any backwards compatibility (and please take the opportunity to sort in any
new function which are "waiting" at the end of the function table) */ new function which are "waiting" at the end of the function table) */
#define PLUGIN_MIN_API_VERSION 52 #define PLUGIN_MIN_API_VERSION 54
/* plugin return codes */ /* plugin return codes */
enum plugin_status { enum plugin_status {
@ -404,7 +404,7 @@ struct plugin_api {
int (*utf8seek)(const unsigned char* utf8, int offset); int (*utf8seek)(const unsigned char* utf8, int offset);
/* sound */ /* sound */
#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) #if CONFIG_CODEC == SWCODEC
int (*sound_default)(int setting); int (*sound_default)(int setting);
#endif #endif
void (*sound_set)(int setting, int value); void (*sound_set)(int setting, int value);
@ -424,9 +424,7 @@ struct plugin_api {
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
const unsigned long *audio_master_sampr_list; const unsigned long *audio_master_sampr_list;
const unsigned long *hw_freq_sampr; const unsigned long *hw_freq_sampr;
#ifndef SIMULATOR
void (*pcm_apply_settings)(void); void (*pcm_apply_settings)(void);
#endif
void (*pcm_play_data)(pcm_more_callback_type get_more, void (*pcm_play_data)(pcm_more_callback_type get_more,
unsigned char* start, size_t size); unsigned char* start, size_t size);
void (*pcm_play_stop)(void); void (*pcm_play_stop)(void);
@ -438,7 +436,6 @@ struct plugin_api {
void (*pcm_calculate_peaks)(int *left, int *right); void (*pcm_calculate_peaks)(int *left, int *right);
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING
const unsigned long *rec_freq_sampr; const unsigned long *rec_freq_sampr;
#ifndef SIMULATOR
void (*pcm_init_recording)(void); void (*pcm_init_recording)(void);
void (*pcm_close_recording)(void); void (*pcm_close_recording)(void);
void (*pcm_record_data)(pcm_more_callback_type2 more_ready, void (*pcm_record_data)(pcm_more_callback_type2 more_ready,
@ -449,7 +446,6 @@ struct plugin_api {
void (*audio_set_recording_gain)(int left, int right, int type); void (*audio_set_recording_gain)(int left, int right, int type);
void (*audio_set_output_source)(int monitor); void (*audio_set_output_source)(int monitor);
void (*rec_set_source)(int source, unsigned flags); void (*rec_set_source)(int source, unsigned flags);
#endif
#endif /* HAVE_RECORDING */ #endif /* HAVE_RECORDING */
#endif #endif

View file

@ -198,10 +198,14 @@ void play_waveform(void)
rb->audio_stop(); rb->audio_stop();
rb->sound_set(SOUND_VOLUME, rb->sound_default(SOUND_VOLUME)); rb->sound_set(SOUND_VOLUME, rb->sound_default(SOUND_VOLUME));
#ifdef HAVE_RECORDING
/* Select playback */ /* Select playback */
rb->rec_set_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); rb->rec_set_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
#endif
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(true); rb->cpu_boost(true);
#endif
rb->pcm_set_frequency(rb->hw_freq_sampr[freq]); rb->pcm_set_frequency(rb->hw_freq_sampr[freq]);
@ -223,7 +227,9 @@ void play_waveform(void)
while (rb->pcm_is_playing()) while (rb->pcm_is_playing())
rb->yield(); rb->yield();
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(false); rb->cpu_boost(false);
#endif
/* restore default - user of apis is responsible for restoring /* restore default - user of apis is responsible for restoring
default state - normally playback at 44100Hz */ default state - normally playback at 44100Hz */

View file

@ -2100,6 +2100,12 @@ void audio_set_recording_gain(int left, int right, int type)
type = type; type = type;
} }
void audio_set_output_source(int source)
{
source = source;
}
void audio_record(const char *filename) void audio_record(const char *filename)
{ {
filename = filename; filename = filename;
@ -2117,19 +2123,6 @@ void audio_resume_recording(void)
{ {
} }
void pcm_calculate_rec_peaks(int *left, int *right)
{
if (left)
*left = 0;
if (right)
*right = 0;
}
unsigned long pcm_rec_status(void)
{
return 0;
}
#endif /* #ifdef SIMULATOR */ #endif /* #ifdef SIMULATOR */
#endif /* #ifdef CONFIG_CODEC == SWCODEC */ #endif /* #ifdef CONFIG_CODEC == SWCODEC */

View file

@ -25,34 +25,71 @@
#include "debug.h" #include "debug.h"
#include "kernel.h" #include "kernel.h"
#include "sound.h" #include "sound.h"
#include "pcm_sampr.h"
#include "SDL.h" #include "SDL.h"
static bool pcm_playing; static bool pcm_playing;
static bool pcm_paused; static bool pcm_paused;
static int cvt_status = -1;
static unsigned long pcm_frequency = SAMPR_44;
static unsigned long pcm_curr_frequency = SAMPR_44;
static Uint8* pcm_data; static Uint8* pcm_data;
static size_t pcm_data_size; static size_t pcm_data_size;
static size_t pcm_sample_bytes;
static size_t pcm_channel_bytes;
struct pcm_udata
{
Uint8 *stream;
Uint32 num_in;
Uint32 num_out;
FILE *debug;
} udata;
static SDL_AudioSpec obtained; static SDL_AudioSpec obtained;
static SDL_AudioCVT cvt; static SDL_AudioCVT cvt;
extern bool debug_audio; extern bool debug_audio;
static void sdl_dma_start(const void *addr, size_t size) #ifndef MIN
{ #define MIN(a, b) (((a) < (b)) ? (a) : (b))
pcm_playing = true; #endif
static void pcm_apply_settings_nolock(void)
{
cvt_status = SDL_BuildAudioCVT(&cvt, AUDIO_S16SYS, 2, pcm_frequency,
obtained.format, obtained.channels, obtained.freq);
pcm_curr_frequency = pcm_frequency;
if (cvt_status < 0) {
cvt.len_ratio = (double)obtained.freq / (double)pcm_curr_frequency;
}
}
void pcm_apply_settings(void)
{
SDL_LockAudio(); SDL_LockAudio();
pcm_apply_settings_nolock();
SDL_UnlockAudio();
}
static void sdl_dma_start_nolock(const void *addr, size_t size)
{
pcm_playing = false;
pcm_apply_settings_nolock();
pcm_data = (Uint8 *) addr; pcm_data = (Uint8 *) addr;
pcm_data_size = size; pcm_data_size = size;
SDL_UnlockAudio(); pcm_playing = true;
SDL_PauseAudio(0); SDL_PauseAudio(0);
} }
static void sdl_dma_stop(void) static void sdl_dma_stop_nolock(void)
{ {
pcm_playing = false; pcm_playing = false;
@ -65,18 +102,20 @@ static void (*callback_for_more)(unsigned char**, size_t*) = NULL;
void pcm_play_data(void (*get_more)(unsigned char** start, size_t* size), void pcm_play_data(void (*get_more)(unsigned char** start, size_t* size),
unsigned char* start, size_t size) unsigned char* start, size_t size)
{ {
SDL_LockAudio();
callback_for_more = get_more; callback_for_more = get_more;
if (!(start && size)) { if (!(start && size)) {
if (get_more) if (get_more)
get_more(&start, &size); get_more(&start, &size);
else
return;
} }
if (start && size) { if (start && size) {
sdl_dma_start(start, size); sdl_dma_start_nolock(start, size);
} }
SDL_UnlockAudio();
} }
size_t pcm_get_bytes_waiting(void) size_t pcm_get_bytes_waiting(void)
@ -91,24 +130,29 @@ void pcm_mute(bool mute)
void pcm_play_stop(void) void pcm_play_stop(void)
{ {
SDL_LockAudio();
if (pcm_playing) { if (pcm_playing) {
sdl_dma_stop(); sdl_dma_stop_nolock();
} }
SDL_UnlockAudio();
} }
void pcm_play_pause(bool play) void pcm_play_pause(bool play)
{ {
size_t next_size; size_t next_size;
Uint8 *next_start; Uint8 *next_start;
SDL_LockAudio();
if (!pcm_playing) { if (!pcm_playing) {
SDL_UnlockAudio();
return; return;
} }
if(pcm_paused && play) { if(pcm_paused && play) {
if (pcm_get_bytes_waiting()) { if (pcm_get_bytes_waiting()) {
printf("unpause\n"); printf("unpause\n");
pcm_apply_settings_nolock();
SDL_PauseAudio(0); SDL_PauseAudio(0);
} else { } else {
printf("unpause, no data waiting\n"); printf("unpause, no data waiting\n");
@ -120,9 +164,9 @@ void pcm_play_pause(bool play)
} }
if (next_start && next_size) { if (next_start && next_size) {
sdl_dma_start(next_start, next_size); sdl_dma_start_nolock(next_start, next_size);
} else { } else {
sdl_dma_stop(); sdl_dma_stop_nolock();
printf("unpause attempted, no data\n"); printf("unpause attempted, no data\n");
} }
} }
@ -133,6 +177,8 @@ void pcm_play_pause(bool play)
} }
pcm_paused = !play; pcm_paused = !play;
SDL_UnlockAudio();
} }
bool pcm_is_paused(void) bool pcm_is_paused(void)
@ -147,9 +193,26 @@ bool pcm_is_playing(void)
void pcm_set_frequency(unsigned int frequency) void pcm_set_frequency(unsigned int frequency)
{ {
// FIXME: Check return values switch (frequency)
SDL_BuildAudioCVT(&cvt, AUDIO_S16SYS, 2, frequency, {
obtained.format, obtained.channels, obtained.freq); HW_HAVE_8_( case SAMPR_8:)
HW_HAVE_11_(case SAMPR_11:)
HW_HAVE_12_(case SAMPR_12:)
HW_HAVE_16_(case SAMPR_16:)
HW_HAVE_22_(case SAMPR_22:)
HW_HAVE_24_(case SAMPR_24:)
HW_HAVE_32_(case SAMPR_32:)
/* 44100 implied */
HW_HAVE_48_(case SAMPR_48:)
HW_HAVE_64_(case SAMPR_64:)
HW_HAVE_88_(case SAMPR_88:)
HW_HAVE_96_(case SAMPR_96:)
break;
default:
frequency = SAMPR_44;
}
pcm_frequency = frequency;
} }
/* /*
@ -216,83 +279,174 @@ void pcm_calculate_peaks(int *left, int *right)
} }
} }
static long write_to_soundcard(Uint8 *stream, int len, FILE *debug) { void write_to_soundcard(struct pcm_udata *udata) {
Uint32 written = (((Uint32) len) > pcm_data_size) ? pcm_data_size : (Uint32) len;
if (cvt.needed) { if (cvt.needed) {
cvt.buf = (Uint8 *) malloc(written * cvt.len_mult); Uint32 rd = udata->num_in;
cvt.len = written; Uint32 wr = (double)rd * cvt.len_ratio;
memcpy(cvt.buf, pcm_data, written); if (wr > udata->num_out) {
wr = udata->num_out;
rd = (double)wr / cvt.len_ratio;
SDL_ConvertAudio(&cvt); if (rd > udata->num_in)
{
memcpy(stream, cvt.buf, cvt.len_cvt); rd = udata->num_in;
wr = (double)rd * cvt.len_ratio;
if (debug != NULL) { }
fwrite(cvt.buf, sizeof(Uint8), cvt.len_cvt, debug);
} }
free(cvt.buf); if (wr == 0 || rd == 0)
{
udata->num_out = udata->num_in = 0;
return;
}
if (cvt_status > 0) {
cvt.len = rd * pcm_sample_bytes;
cvt.buf = (Uint8 *) malloc(cvt.len * cvt.len_mult);
memcpy(cvt.buf, pcm_data, cvt.len);
SDL_ConvertAudio(&cvt);
memcpy(udata->stream, cvt.buf, cvt.len_cvt);
udata->num_in = cvt.len / pcm_sample_bytes;
udata->num_out = cvt.len_cvt / pcm_sample_bytes;
if (udata->debug != NULL) {
fwrite(cvt.buf, sizeof(Uint8), cvt.len_cvt, udata->debug);
}
free(cvt.buf);
}
else {
/* Convert is bad, so do silence */
Uint32 num = wr*obtained.channels;
udata->num_in = rd;
udata->num_out = wr;
switch (pcm_channel_bytes)
{
case 1:
{
Uint8 *stream = udata->stream;
while (num-- > 0)
*stream++ = obtained.silence;
break;
}
case 2:
{
Uint16 *stream = (Uint16 *)udata->stream;
while (num-- > 0)
*stream++ = obtained.silence;
break;
}
}
if (udata->debug != NULL) {
fwrite(udata->stream, sizeof(Uint8), wr, udata->debug);
}
}
} else { } else {
memcpy(stream, pcm_data, written); udata->num_in = udata->num_out = MIN(udata->num_in, udata->num_out);
memcpy(udata->stream, pcm_data, udata->num_out * pcm_sample_bytes);
if (debug != NULL) { if (udata->debug != NULL) {
fwrite(pcm_data, sizeof(Uint8), written, debug); fwrite(pcm_data, sizeof(Uint8), udata->num_out * pcm_sample_bytes,
udata->debug);
} }
} }
return written;
} }
void sdl_audio_callback(void *udata, Uint8 *stream, int len) void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len)
{ {
Uint32 have_now; udata->stream = stream;
FILE *debug = (FILE *) udata;
/* At all times we need to write a full 'len' bytes to stream. */
/* Write what we have in the PCM buffer */ /* Write what we have in the PCM buffer */
if (pcm_data_size > 0) { if (pcm_data_size > 0)
have_now = write_to_soundcard(stream, len, debug); goto start;
stream += have_now;
len -= have_now;
pcm_data += have_now;
pcm_data_size -= have_now;
}
/* Audio card wants more? Get some more then. */ /* Audio card wants more? Get some more then. */
while (len > 0) { while (len > 0) {
if (callback_for_more) { if ((ssize_t)pcm_data_size <= 0) {
callback_for_more(&pcm_data, &pcm_data_size);
} else {
pcm_data = NULL;
pcm_data_size = 0; pcm_data_size = 0;
if (callback_for_more)
callback_for_more(&pcm_data, &pcm_data_size);
} }
if (pcm_data_size > 0) { if (pcm_data_size > 0) {
have_now = write_to_soundcard(stream, len, debug); start:
udata->num_in = pcm_data_size / pcm_sample_bytes;
stream += have_now; udata->num_out = len / pcm_sample_bytes;
len -= have_now;
pcm_data += have_now; write_to_soundcard(udata);
pcm_data_size -= have_now;
udata->num_in *= pcm_sample_bytes;
udata->num_out *= pcm_sample_bytes;
pcm_data += udata->num_in;
pcm_data_size -= udata->num_in;
udata->stream += udata->num_out;
len -= udata->num_out;
} else { } else {
DEBUGF("sdl_audio_callback: No Data.\n"); DEBUGF("sdl_audio_callback: No Data.\n");
sdl_dma_stop(); sdl_dma_stop_nolock();
break; break;
} }
} }
} }
#ifdef HAVE_RECORDING
void pcm_init_recording(void)
{
}
void pcm_close_recording(void)
{
}
void pcm_record_data(void (*more_ready)(void* start, size_t size),
void *start, size_t size)
{
(void)more_ready;
(void)start;
(void)size;
}
void pcm_stop_recording(void)
{
}
void pcm_record_more(void *start, size_t size)
{
(void)start;
(void)size;
}
void pcm_calculate_rec_peaks(int *left, int *right)
{
if (left)
*left = 0;
if (right)
*right = 0;
}
unsigned long pcm_rec_status(void)
{
return 0;
}
#endif /* HAVE_RECORDING */
int pcm_init(void) int pcm_init(void)
{ {
SDL_AudioSpec wanted_spec; SDL_AudioSpec wanted_spec;
FILE *debug = NULL; udata.debug = NULL;
if (debug_audio) { if (debug_audio) {
debug = fopen("audiodebug.raw", "wb"); udata.debug = fopen("audiodebug.raw", "wb");
} }
/* Set 16-bit stereo audio at 44Khz */ /* Set 16-bit stereo audio at 44Khz */
@ -300,8 +454,10 @@ int pcm_init(void)
wanted_spec.format = AUDIO_S16SYS; wanted_spec.format = AUDIO_S16SYS;
wanted_spec.channels = 2; wanted_spec.channels = 2;
wanted_spec.samples = 2048; wanted_spec.samples = 2048;
wanted_spec.callback = sdl_audio_callback; wanted_spec.callback =
wanted_spec.userdata = debug; (void (SDLCALL *)(void *userdata,
Uint8 *stream, int len))sdl_audio_callback;
wanted_spec.userdata = &udata;
/* Open the audio device and start playing sound! */ /* Open the audio device and start playing sound! */
if(SDL_OpenAudio(&wanted_spec, &obtained) < 0) { if(SDL_OpenAudio(&wanted_spec, &obtained) < 0) {
@ -309,7 +465,29 @@ int pcm_init(void)
return -1; return -1;
} }
sdl_dma_stop(); switch (obtained.format)
{
case AUDIO_U8:
case AUDIO_S8:
pcm_channel_bytes = 1;
break;
case AUDIO_U16LSB:
case AUDIO_S16LSB:
case AUDIO_U16MSB:
case AUDIO_S16MSB:
pcm_channel_bytes = 2;
break;
default:
fprintf(stderr, "Unknown sample format obtained: %u\n",
(unsigned)obtained.format);
return -1;
}
pcm_sample_bytes = obtained.channels * pcm_channel_bytes;
pcm_apply_settings_nolock();
sdl_dma_stop_nolock();
return 0; return 0;
} }
@ -317,5 +495,3 @@ int pcm_init(void)
void pcm_postinit(void) void pcm_postinit(void)
{ {
} }