1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006 Michael Sevakis
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "lib/oldmenuapi.h"
24 /* This plugin generates a 1kHz tone + noise in order to quickly verify
25 * hardware samplerate setup is operating correctly.
27 * While switching to different frequencies, the pitch of the tone should
28 * remain constant whereas the upper harmonics of the noise should vary
35 static int hw_freq IDATA_ATTR
= HW_FREQ_DEFAULT
;
36 static unsigned long hw_sampr IDATA_ATTR
= HW_SAMPR_DEFAULT
;
38 static int gen_thread_stack
[DEFAULT_STACK_SIZE
/sizeof(int)] IBSS_ATTR
;
39 static bool gen_quit IBSS_ATTR
;
40 static unsigned int gen_thread_id
;
42 #define OUTPUT_CHUNK_COUNT (1 << 1)
43 #define OUTPUT_CHUNK_MASK (OUTPUT_CHUNK_COUNT-1)
44 #define OUTPUT_CHUNK_SAMPLES 1152
45 #define OUTPUT_CHUNK_SIZE (OUTPUT_CHUNK_SAMPLES*sizeof(int16_t)*2)
46 static uint16_t output_buf
[OUTPUT_CHUNK_COUNT
][OUTPUT_CHUNK_SAMPLES
*2]
47 __attribute__((aligned(4)));
48 static int output_head IBSS_ATTR
;
49 static int output_tail IBSS_ATTR
;
50 static int output_step IBSS_ATTR
;
52 static uint32_t gen_phase_step IBSS_ATTR
;
53 static const uint32_t gen_frequency
= 1000;
55 /* fsin shamelessly stolen from signal_gen.c by Thom Johansen (preglow) */
57 /* Good quality sine calculated by linearly interpolating
58 * a 128 sample sine table. First harmonic has amplitude of about -84 dB.
59 * phase has range from 0 to 0xffffffff, representing 0 and
61 * Return value is a signed value from LONG_MIN to LONG_MAX, representing
62 * -1 and 1 respectively.
64 static int16_t ICODE_ATTR
fsin(uint32_t phase
)
66 /* 128 sixteen bit sine samples + guard point */
67 static const int16_t sinetab
[129] ICONST_ATTR
=
69 0, 1607, 3211, 4807, 6392, 7961, 9511, 11038,
70 12539, 14009, 15446, 16845, 18204, 19519, 20787, 22004,
71 23169, 24278, 25329, 26318, 27244, 28105, 28897, 29621,
72 30272, 30851, 31356, 31785, 32137, 32412, 32609, 32727,
73 32767, 32727, 32609, 32412, 32137, 31785, 31356, 30851,
74 30272, 29621, 28897, 28105, 27244, 26318, 25329, 24278,
75 23169, 22004, 20787, 19519, 18204, 16845, 15446, 14009,
76 12539, 11038, 9511, 7961, 6392, 4807, 3211, 1607,
77 0, -1607, -3211, -4807, -6392, -7961, -9511, -11038,
78 -12539, -14009, -15446, -16845, -18204, -19519, -20787, -22004,
79 -23169, -24278, -25329, -26318, -27244, -28105, -28897, -29621,
80 -30272, -30851, -31356, -31785, -32137, -32412, -32609, -32727,
81 -32767, -32727, -32609, -32412, -32137, -31785, -31356, -30851,
82 -30272, -29621, -28897, -28105, -27244, -26318, -25329, -24278,
83 -23169, -22004, -20787, -19519, -18204, -16845, -15446, -14009,
84 -12539, -11038, -9511, -7961, -6392, -4807, -3211, -1607,
88 unsigned int pos
= phase
>> 25;
89 unsigned short frac
= (phase
& 0x01ffffff) >> 9;
90 short diff
= sinetab
[pos
+ 1] - sinetab
[pos
];
92 return sinetab
[pos
] + (frac
*diff
>> 16);
95 /* ISR handler to get next block of data */
96 static void get_more(unsigned char **start
, size_t *size
)
98 /* Free previous buffer */
99 output_head
+= output_step
;
102 *start
= (unsigned char *)output_buf
[output_head
& OUTPUT_CHUNK_MASK
];
103 *size
= OUTPUT_CHUNK_SIZE
;
105 /* Keep repeating previous if source runs low */
106 if (output_head
!= output_tail
)
110 static void ICODE_ATTR
gen_thread_func(void)
112 uint32_t gen_random
= *rb
->current_tick
;
113 uint32_t gen_phase
= 0;
117 int16_t *p
= output_buf
[output_tail
& OUTPUT_CHUNK_MASK
];
118 int i
= OUTPUT_CHUNK_SAMPLES
;
120 while (output_tail
- output_head
>= OUTPUT_CHUNK_COUNT
)
129 int32_t val
= fsin(gen_phase
);
130 int32_t rnd
= (int16_t)gen_random
;
132 gen_random
= gen_random
*0x0019660dL
+ 0x3c6ef35fL
;
134 val
= (rnd
+ 2*val
) / 3;
139 gen_phase
+= gen_phase_step
;
148 static void update_gen_step(void)
150 gen_phase_step
= 0x100000000ull
*gen_frequency
/ hw_sampr
;
153 static void output_clear(void)
157 rb
->memset(output_buf
, 0, sizeof (output_buf
));
161 rb
->pcm_play_unlock();
164 /* Called to switch samplerate on the fly */
165 static void set_frequency(int index
)
168 hw_sampr
= rb
->hw_freq_sampr
[index
];
173 rb
->pcm_set_frequency(hw_sampr
);
174 rb
->pcm_apply_settings();
177 #ifndef HAVE_VOLUME_IN_LIST
178 static void set_volume(int value
)
180 rb
->global_settings
->volume
= value
;
181 rb
->sound_set(SOUND_VOLUME
, value
);
184 static void format_volume(char *buf
, size_t len
, int value
, const char *unit
)
186 rb
->snprintf(buf
, len
, "%d %s", rb
->sound_val2phys(SOUND_VOLUME
, value
),
187 rb
->sound_unit(SOUND_VOLUME
));
190 #endif /* HAVE_VOLUME_IN_LIST */
192 static void play_tone(bool volume_set
)
194 static struct opt_items names
[HW_NUM_FREQ
] =
196 HW_HAVE_96_([HW_FREQ_96
] = { "96kHz", -1 },)
197 HW_HAVE_88_([HW_FREQ_88
] = { "88.2kHz", -1 },)
198 HW_HAVE_64_([HW_FREQ_64
] = { "64kHz", -1 },)
199 HW_HAVE_48_([HW_FREQ_48
] = { "48kHz", -1 },)
200 HW_HAVE_44_([HW_FREQ_44
] = { "44.1kHz", -1 },)
201 HW_HAVE_32_([HW_FREQ_32
] = { "32kHz", -1 },)
202 HW_HAVE_24_([HW_FREQ_24
] = { "24kHz", -1 },)
203 HW_HAVE_22_([HW_FREQ_22
] = { "22.05kHz", -1 },)
204 HW_HAVE_16_([HW_FREQ_16
] = { "16kHz", -1 },)
205 HW_HAVE_12_([HW_FREQ_12
] = { "12kHz", -1 },)
206 HW_HAVE_11_([HW_FREQ_11
] = { "11.025kHz", -1 },)
207 HW_HAVE_8_( [HW_FREQ_8
] = { "8kHz", -1 },)
214 #if INPUT_SRC_CAPS != 0
215 /* Select playback */
216 rb
->audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
219 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
223 rb
->pcm_set_frequency(rb
->hw_freq_sampr
[freq
]);
225 #if INPUT_SRC_CAPS != 0
226 /* Recordable targets can play back from other sources */
227 rb
->audio_set_output_source(AUDIO_SRC_PLAYBACK
);
234 gen_thread_id
= rb
->create_thread(gen_thread_func
, gen_thread_stack
,
235 sizeof(gen_thread_stack
), 0,
236 "test_sampr generator"
237 IF_PRIO(, PRIORITY_PLAYBACK
)
240 rb
->pcm_play_data(get_more
, NULL
, 0);
242 #ifndef HAVE_VOLUME_IN_LIST
245 int volume
= rb
->global_settings
->volume
;
247 rb
->set_int("Volume", NULL
, -1, &volume
,
248 set_volume
, 1, rb
->sound_min(SOUND_VOLUME
),
249 rb
->sound_max(SOUND_VOLUME
), format_volume
);
252 #endif /* HAVE_VOLUME_IN_LIST */
254 rb
->set_option("Sample Rate", &freq
, INT
, names
,
255 HW_NUM_FREQ
, set_frequency
);
261 rb
->thread_wait(gen_thread_id
);
265 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
266 rb
->cpu_boost(false);
269 /* restore default - user of apis is responsible for restoring
270 default state - normally playback at 44100Hz */
271 rb
->pcm_set_frequency(HW_FREQ_DEFAULT
);
274 /* Tests hardware sample rate switching */
275 /* TODO: needs a volume control */
276 enum plugin_status
plugin_start(const void *parameter
)
280 __TEST_SAMPR_MENUITEM_FIRST
= -1,
281 #ifndef HAVE_VOLUME_IN_LIST
283 #endif /* HAVE_VOLUME_IN_LIST */
288 static const struct menu_item items
[] =
290 #ifndef HAVE_VOLUME_IN_LIST
292 { "Set Volume", NULL
},
293 #endif /* HAVE_VOLUME_IN_LIST */
295 { "Set Samplerate", NULL
},
303 /* Disable all talking before initializing IRAM */
304 rb
->talk_disable(true);
306 PLUGIN_IRAM_INIT(rb
);
308 m
= menu_init(items
, ARRAYLEN(items
),
309 NULL
, NULL
, NULL
, NULL
);
313 int result
= menu_show(m
);
317 #ifndef HAVE_VOLUME_IN_LIST
321 #endif /* HAVE_VOLUME_IN_LIST */
334 rb
->talk_disable(false);