From 6f1e5c578f02f7cd9881d0809bbefbb36f9f8029 Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Wed, 3 Jan 2007 12:38:01 +0000 Subject: Added test_sampr playback samplerate testing plugin. Should show a list of rates defined for the HW_SAMPR_CAPS in the config file. Currently plays sine, triangle, sawtooth and square waves at 441Hz at the default samplerate of 44.1Khz. Changing rates will raise or lower the pitch. Add test_sampr.c to apps/plugins/SOURCES to build. Tested only on ColdFire targets so far. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11889 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/test_sampr.c | 296 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 296 insertions(+) create mode 100644 apps/plugins/test_sampr.c diff --git a/apps/plugins/test_sampr.c b/apps/plugins/test_sampr.c new file mode 100644 index 0000000000..cab81d2a80 --- /dev/null +++ b/apps/plugins/test_sampr.c @@ -0,0 +1,296 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 Michael Sevakis + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "plugin.h" + +PLUGIN_HEADER + +struct plugin_api *rb; + +enum +{ + TONE_SINE = 0, + TONE_TRIANGLE, + TONE_SAWTOOTH, + TONE_SQUARE, + NUM_WAVEFORMS +}; + +static int freq = HW_FREQ_DEFAULT; +static int waveform = TONE_SINE; + +/* A441 at 44100Hz. Pitch will change with changing samplerate. + Test different waveforms to detect any aliasing in signal which + indicates duplicated/dropped samples */ +static const int16_t A441[NUM_WAVEFORMS][100] = +{ + [TONE_SINE] = + { + 0, 2057, 4106, 6139, 8148, + 10125, 12062, 13951, 15785, 17557, + 19259, 20886, 22430, 23886, 25247, + 26509, 27666, 28713, 29648, 30465, + 31163, 31737, 32186, 32508, 32702, + 32767, 32702, 32508, 32186, 31737, + 31163, 30465, 29648, 28713, 27666, + 26509, 25247, 23886, 22430, 20886, + 19259, 17557, 15785, 13951, 12062, + 10125, 8148, 6139, 4106, 2057, + 0, -2057, -4106, -6139, -8148, + -10125, -12062, -13951, -15785, -17557, + -19259, -20886, -22430, -23886, -25247, + -26509, -27666, -28713, -29648, -30465, + -31163, -31737, -32186, -32508, -32702, + -32767, -32702, -32508, -32186, -31737, + -31163, -30465, -29648, -28713, -27666, + -26509, -25247, -23886, -22430, -20886, + -19259, -17557, -15785, -13951, -12062, + -10125, -8148, -6139, -4106, -2057, + }, + [TONE_TRIANGLE] = + { + 0, 1310, 2621, 3932, 5242, + 6553, 7864, 9174, 10485, 11796, + 13106, 14417, 15728, 17038, 18349, + 19660, 20970, 22281, 23592, 24902, + 26213, 27524, 28834, 30145, 31456, + 32767, 31456, 30145, 28834, 27524, + 26213, 24902, 23592, 22281, 20970, + 19660, 18349, 17038, 15728, 14417, + 13106, 11796, 10485, 9174, 7864, + 6553, 5242, 3932, 2621, 1310, + 0, -1310, -2621, -3932, -5242, + -6553, -7864, -9174, -10485, -11796, + -13106, -14417, -15728, -17038, -18349, + -19660, -20970, -22281, -23592, -24902, + -26213, -27524, -28834, -30145, -31456, + -32767, -31456, -30145, -28834, -27524, + -26213, -24902, -23592, -22281, -20970, + -19660, -18349, -17038, -15728, -14417, + -13106, -11796, -10485, -9174, -7864, + -6553, -5242, -3932, -2621, -1310, + }, + [TONE_SAWTOOTH] = + { + -32767, -32111, -31456, -30800, -30145, + -29490, -28834, -28179, -27524, -26868, + -26213, -25558, -24902, -24247, -23592, + -22936, -22281, -21626, -20970, -20315, + -19660, -19004, -18349, -17694, -17038, + -16383, -15728, -15072, -14417, -13762, + -13106, -12451, -11796, -11140, -10485, + -9830, -9174, -8519, -7864, -7208, + -6553, -5898, -5242, -4587, -3932, + -3276, -2621, -1966, -1310, -655, + 0, 655, 1310, 1966, 2621, + 3276, 3932, 4587, 5242, 5898, + 6553, 7208, 7864, 8519, 9174, + 9830, 10485, 11140, 11796, 12451, + 13106, 13762, 14417, 15072, 15728, + 16383, 17038, 17694, 18349, 19004, + 19660, 20315, 20970, 21626, 22281, + 22936, 23592, 24247, 24902, 25558, + 26213, 26868, 27524, 28179, 28834, + 29490, 30145, 30800, 31456, 32111, + }, + [TONE_SQUARE] = + { + 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, + -32767, -32767, -32767, -32767, -32767, + -32767, -32767, -32767, -32767, -32767, + -32767, -32767, -32767, -32767, -32767, + -32767, -32767, -32767, -32767, -32767, + -32767, -32767, -32767, -32767, -32767, + -32767, -32767, -32767, -32767, -32767, + -32767, -32767, -32767, -32767, -32767, + -32767, -32767, -32767, -32767, -32767, + -32767, -32767, -32767, -32767, -32767, + -32767, -32767, -32767, -32767, -32767, + } +}; + +void play_waveform(void) +{ + static struct opt_items names[HW_NUM_FREQ] = + { + HW_HAVE_96_([HW_FREQ_96] = { "96kHz", NULL },) + HW_HAVE_88_([HW_FREQ_88] = { "88.2kHz", NULL },) + HW_HAVE_64_([HW_FREQ_64] = { "64kHz", NULL },) + HW_HAVE_48_([HW_FREQ_48] = { "48kHz", NULL },) + HW_HAVE_44_([HW_FREQ_44] = { "44.1kHz", NULL },) + HW_HAVE_32_([HW_FREQ_32] = { "32kHz", NULL },) + HW_HAVE_24_([HW_FREQ_24] = { "24kHz", NULL },) + HW_HAVE_22_([HW_FREQ_22] = { "22.05kHz", NULL },) + HW_HAVE_16_([HW_FREQ_16] = { "16kHz", NULL },) + HW_HAVE_12_([HW_FREQ_12] = { "12kHz", NULL },) + HW_HAVE_11_([HW_FREQ_11] = { "11.025kHz", NULL },) + HW_HAVE_8_( [HW_FREQ_8 ] = { "8kHz", NULL },) + }; + + /* 50 cycles of wavform */ + static int32_t audio[5000]; + + void init_audio(int type) + { + int i; + /* Signal amplitudes to adjust for somewhat equal percieved + volume */ + int amps[NUM_WAVEFORMS] = + { + [TONE_SINE] = 8191, + [TONE_TRIANGLE] = 5119, + [TONE_SAWTOOTH] = 2047, + [TONE_SQUARE] = 1535 + }; + + /* Initialize one cycle of the waveform */ + for (i = 0; i < 100; i++) + { + uint16_t val = amps[type]*A441[type][i]/32767; + audio[i] = (val << 16) | val; + } + + /* Duplicate it 49 more times */ + for (i = 1; i < 50; i++) + { + rb->memcpy(audio + i*100, audio, 100*sizeof(int32_t)); + } + } + + /* ISR handler to get next block of data */ + void get_more(unsigned char **start, size_t *size) + { + *start = (unsigned char *)audio; + *size = sizeof (audio); + } + + /* Called to switch samplerate on the fly */ + void set_frequency(int index) + { + rb->pcm_set_frequency(rb->hw_freq_sampr[index]); + rb->pcm_apply_settings(false); + } + + rb->audio_stop(); + rb->sound_set(SOUND_VOLUME, rb->sound_default(SOUND_VOLUME)); + + /* Select playback */ + rb->rec_set_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); + + rb->cpu_boost(true); + + rb->pcm_set_frequency(rb->hw_freq_sampr[freq]); + +#ifdef HAVE_RECORDING + /* Recordable targets can play back from other sources */ + rb->audio_set_output_source(AUDIO_SRC_PLAYBACK); +#endif + /* This reset parameter will likely be deleted soon and resetting be + automatic - ignore if the implementation doesn't need it */ + rb->pcm_apply_settings(true); + + init_audio(waveform); + rb->pcm_play_data(get_more, NULL, 0); + + rb->set_option("Sample Rate", &freq, INT, names, + HW_NUM_FREQ, set_frequency); + + rb->pcm_play_stop(); + + while (rb->pcm_is_playing()) + rb->yield(); + + rb->cpu_boost(false); + + /* restore default - user of apis is responsible for restoring + default state - normally playback at 44100Hz */ + rb->pcm_set_frequency(HW_FREQ_DEFAULT); +} + +void set_waveform(void) +{ + static struct opt_items names[NUM_WAVEFORMS] = + { + [TONE_SINE] = { "Sine", NULL }, + [TONE_TRIANGLE] = { "Triangle", NULL }, + [TONE_SAWTOOTH] = { "Sawtooth", NULL }, + [TONE_SQUARE] = { "Square", NULL }, + }; + + rb->set_option("Waveform", &waveform, INT, names, + NUM_WAVEFORMS, NULL); +} + +/* Tests hardware sample rate switching */ +/* TODO: needs a volume control */ +enum plugin_status plugin_start(struct plugin_api *api, void *parameter) +{ + static const struct menu_item items[] = + { + { "Set Waveform", NULL }, + { "Play Waveform", NULL }, + { "Quit", NULL }, + }; + + bool exit = false; + int m; + bool talk_menu; + + rb = api; + + /* Have to shut up voice menus or it will mess up our waveform playback */ + talk_menu = rb->global_settings->talk_menu; + rb->global_settings->talk_menu = false; + + m = rb->menu_init(items, ARRAYLEN(items), + NULL, NULL, NULL, NULL); + + while (!exit) + { + int result = rb->menu_show(m); + + switch (result) + { + case 0: + set_waveform(); + break; + case 1: + play_waveform(); + break; + case 2: + exit = true; + break; + } + } + + rb->menu_exit(m); + + rb->global_settings->talk_menu = talk_menu; + + return PLUGIN_OK; + (void)parameter; +} -- cgit