diff options
-rw-r--r-- | apps/plugins/test_sampr.c | 296 |
1 files changed, 296 insertions, 0 deletions
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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 Michael Sevakis | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include "plugin.h" | ||
20 | |||
21 | PLUGIN_HEADER | ||
22 | |||
23 | struct plugin_api *rb; | ||
24 | |||
25 | enum | ||
26 | { | ||
27 | TONE_SINE = 0, | ||
28 | TONE_TRIANGLE, | ||
29 | TONE_SAWTOOTH, | ||
30 | TONE_SQUARE, | ||
31 | NUM_WAVEFORMS | ||
32 | }; | ||
33 | |||
34 | static int freq = HW_FREQ_DEFAULT; | ||
35 | static int waveform = TONE_SINE; | ||
36 | |||
37 | /* A441 at 44100Hz. Pitch will change with changing samplerate. | ||
38 | Test different waveforms to detect any aliasing in signal which | ||
39 | indicates duplicated/dropped samples */ | ||
40 | static const int16_t A441[NUM_WAVEFORMS][100] = | ||
41 | { | ||
42 | [TONE_SINE] = | ||
43 | { | ||
44 | 0, 2057, 4106, 6139, 8148, | ||
45 | 10125, 12062, 13951, 15785, 17557, | ||
46 | 19259, 20886, 22430, 23886, 25247, | ||
47 | 26509, 27666, 28713, 29648, 30465, | ||
48 | 31163, 31737, 32186, 32508, 32702, | ||
49 | 32767, 32702, 32508, 32186, 31737, | ||
50 | 31163, 30465, 29648, 28713, 27666, | ||
51 | 26509, 25247, 23886, 22430, 20886, | ||
52 | 19259, 17557, 15785, 13951, 12062, | ||
53 | 10125, 8148, 6139, 4106, 2057, | ||
54 | 0, -2057, -4106, -6139, -8148, | ||
55 | -10125, -12062, -13951, -15785, -17557, | ||
56 | -19259, -20886, -22430, -23886, -25247, | ||
57 | -26509, -27666, -28713, -29648, -30465, | ||
58 | -31163, -31737, -32186, -32508, -32702, | ||
59 | -32767, -32702, -32508, -32186, -31737, | ||
60 | -31163, -30465, -29648, -28713, -27666, | ||
61 | -26509, -25247, -23886, -22430, -20886, | ||
62 | -19259, -17557, -15785, -13951, -12062, | ||
63 | -10125, -8148, -6139, -4106, -2057, | ||
64 | }, | ||
65 | [TONE_TRIANGLE] = | ||
66 | { | ||
67 | 0, 1310, 2621, 3932, 5242, | ||
68 | 6553, 7864, 9174, 10485, 11796, | ||
69 | 13106, 14417, 15728, 17038, 18349, | ||
70 | 19660, 20970, 22281, 23592, 24902, | ||
71 | 26213, 27524, 28834, 30145, 31456, | ||
72 | 32767, 31456, 30145, 28834, 27524, | ||
73 | 26213, 24902, 23592, 22281, 20970, | ||
74 | 19660, 18349, 17038, 15728, 14417, | ||
75 | 13106, 11796, 10485, 9174, 7864, | ||
76 | 6553, 5242, 3932, 2621, 1310, | ||
77 | 0, -1310, -2621, -3932, -5242, | ||
78 | -6553, -7864, -9174, -10485, -11796, | ||
79 | -13106, -14417, -15728, -17038, -18349, | ||
80 | -19660, -20970, -22281, -23592, -24902, | ||
81 | -26213, -27524, -28834, -30145, -31456, | ||
82 | -32767, -31456, -30145, -28834, -27524, | ||
83 | -26213, -24902, -23592, -22281, -20970, | ||
84 | -19660, -18349, -17038, -15728, -14417, | ||
85 | -13106, -11796, -10485, -9174, -7864, | ||
86 | -6553, -5242, -3932, -2621, -1310, | ||
87 | }, | ||
88 | [TONE_SAWTOOTH] = | ||
89 | { | ||
90 | -32767, -32111, -31456, -30800, -30145, | ||
91 | -29490, -28834, -28179, -27524, -26868, | ||
92 | -26213, -25558, -24902, -24247, -23592, | ||
93 | -22936, -22281, -21626, -20970, -20315, | ||
94 | -19660, -19004, -18349, -17694, -17038, | ||
95 | -16383, -15728, -15072, -14417, -13762, | ||
96 | -13106, -12451, -11796, -11140, -10485, | ||
97 | -9830, -9174, -8519, -7864, -7208, | ||
98 | -6553, -5898, -5242, -4587, -3932, | ||
99 | -3276, -2621, -1966, -1310, -655, | ||
100 | 0, 655, 1310, 1966, 2621, | ||
101 | 3276, 3932, 4587, 5242, 5898, | ||
102 | 6553, 7208, 7864, 8519, 9174, | ||
103 | 9830, 10485, 11140, 11796, 12451, | ||
104 | 13106, 13762, 14417, 15072, 15728, | ||
105 | 16383, 17038, 17694, 18349, 19004, | ||
106 | 19660, 20315, 20970, 21626, 22281, | ||
107 | 22936, 23592, 24247, 24902, 25558, | ||
108 | 26213, 26868, 27524, 28179, 28834, | ||
109 | 29490, 30145, 30800, 31456, 32111, | ||
110 | }, | ||
111 | [TONE_SQUARE] = | ||
112 | { | ||
113 | 32767, 32767, 32767, 32767, 32767, | ||
114 | 32767, 32767, 32767, 32767, 32767, | ||
115 | 32767, 32767, 32767, 32767, 32767, | ||
116 | 32767, 32767, 32767, 32767, 32767, | ||
117 | 32767, 32767, 32767, 32767, 32767, | ||
118 | 32767, 32767, 32767, 32767, 32767, | ||
119 | 32767, 32767, 32767, 32767, 32767, | ||
120 | 32767, 32767, 32767, 32767, 32767, | ||
121 | 32767, 32767, 32767, 32767, 32767, | ||
122 | 32767, 32767, 32767, 32767, 32767, | ||
123 | -32767, -32767, -32767, -32767, -32767, | ||
124 | -32767, -32767, -32767, -32767, -32767, | ||
125 | -32767, -32767, -32767, -32767, -32767, | ||
126 | -32767, -32767, -32767, -32767, -32767, | ||
127 | -32767, -32767, -32767, -32767, -32767, | ||
128 | -32767, -32767, -32767, -32767, -32767, | ||
129 | -32767, -32767, -32767, -32767, -32767, | ||
130 | -32767, -32767, -32767, -32767, -32767, | ||
131 | -32767, -32767, -32767, -32767, -32767, | ||
132 | -32767, -32767, -32767, -32767, -32767, | ||
133 | } | ||
134 | }; | ||
135 | |||
136 | void play_waveform(void) | ||
137 | { | ||
138 | static struct opt_items names[HW_NUM_FREQ] = | ||
139 | { | ||
140 | HW_HAVE_96_([HW_FREQ_96] = { "96kHz", NULL },) | ||
141 | HW_HAVE_88_([HW_FREQ_88] = { "88.2kHz", NULL },) | ||
142 | HW_HAVE_64_([HW_FREQ_64] = { "64kHz", NULL },) | ||
143 | HW_HAVE_48_([HW_FREQ_48] = { "48kHz", NULL },) | ||
144 | HW_HAVE_44_([HW_FREQ_44] = { "44.1kHz", NULL },) | ||
145 | HW_HAVE_32_([HW_FREQ_32] = { "32kHz", NULL },) | ||
146 | HW_HAVE_24_([HW_FREQ_24] = { "24kHz", NULL },) | ||
147 | HW_HAVE_22_([HW_FREQ_22] = { "22.05kHz", NULL },) | ||
148 | HW_HAVE_16_([HW_FREQ_16] = { "16kHz", NULL },) | ||
149 | HW_HAVE_12_([HW_FREQ_12] = { "12kHz", NULL },) | ||
150 | HW_HAVE_11_([HW_FREQ_11] = { "11.025kHz", NULL },) | ||
151 | HW_HAVE_8_( [HW_FREQ_8 ] = { "8kHz", NULL },) | ||
152 | }; | ||
153 | |||
154 | /* 50 cycles of wavform */ | ||
155 | static int32_t audio[5000]; | ||
156 | |||
157 | void init_audio(int type) | ||
158 | { | ||
159 | int i; | ||
160 | /* Signal amplitudes to adjust for somewhat equal percieved | ||
161 | volume */ | ||
162 | int amps[NUM_WAVEFORMS] = | ||
163 | { | ||
164 | [TONE_SINE] = 8191, | ||
165 | [TONE_TRIANGLE] = 5119, | ||
166 | [TONE_SAWTOOTH] = 2047, | ||
167 | [TONE_SQUARE] = 1535 | ||
168 | }; | ||
169 | |||
170 | /* Initialize one cycle of the waveform */ | ||
171 | for (i = 0; i < 100; i++) | ||
172 | { | ||
173 | uint16_t val = amps[type]*A441[type][i]/32767; | ||
174 | audio[i] = (val << 16) | val; | ||
175 | } | ||
176 | |||
177 | /* Duplicate it 49 more times */ | ||
178 | for (i = 1; i < 50; i++) | ||
179 | { | ||
180 | rb->memcpy(audio + i*100, audio, 100*sizeof(int32_t)); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | /* ISR handler to get next block of data */ | ||
185 | void get_more(unsigned char **start, size_t *size) | ||
186 | { | ||
187 | *start = (unsigned char *)audio; | ||
188 | *size = sizeof (audio); | ||
189 | } | ||
190 | |||
191 | /* Called to switch samplerate on the fly */ | ||
192 | void set_frequency(int index) | ||
193 | { | ||
194 | rb->pcm_set_frequency(rb->hw_freq_sampr[index]); | ||
195 | rb->pcm_apply_settings(false); | ||
196 | } | ||
197 | |||
198 | rb->audio_stop(); | ||
199 | rb->sound_set(SOUND_VOLUME, rb->sound_default(SOUND_VOLUME)); | ||
200 | |||
201 | /* Select playback */ | ||
202 | rb->rec_set_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); | ||
203 | |||
204 | rb->cpu_boost(true); | ||
205 | |||
206 | rb->pcm_set_frequency(rb->hw_freq_sampr[freq]); | ||
207 | |||
208 | #ifdef HAVE_RECORDING | ||
209 | /* Recordable targets can play back from other sources */ | ||
210 | rb->audio_set_output_source(AUDIO_SRC_PLAYBACK); | ||
211 | #endif | ||
212 | /* This reset parameter will likely be deleted soon and resetting be | ||
213 | automatic - ignore if the implementation doesn't need it */ | ||
214 | rb->pcm_apply_settings(true); | ||
215 | |||
216 | init_audio(waveform); | ||
217 | rb->pcm_play_data(get_more, NULL, 0); | ||
218 | |||
219 | rb->set_option("Sample Rate", &freq, INT, names, | ||
220 | HW_NUM_FREQ, set_frequency); | ||
221 | |||
222 | rb->pcm_play_stop(); | ||
223 | |||
224 | while (rb->pcm_is_playing()) | ||
225 | rb->yield(); | ||
226 | |||
227 | rb->cpu_boost(false); | ||
228 | |||
229 | /* restore default - user of apis is responsible for restoring | ||
230 | default state - normally playback at 44100Hz */ | ||
231 | rb->pcm_set_frequency(HW_FREQ_DEFAULT); | ||
232 | } | ||
233 | |||
234 | void set_waveform(void) | ||
235 | { | ||
236 | static struct opt_items names[NUM_WAVEFORMS] = | ||
237 | { | ||
238 | [TONE_SINE] = { "Sine", NULL }, | ||
239 | [TONE_TRIANGLE] = { "Triangle", NULL }, | ||
240 | [TONE_SAWTOOTH] = { "Sawtooth", NULL }, | ||
241 | [TONE_SQUARE] = { "Square", NULL }, | ||
242 | }; | ||
243 | |||
244 | rb->set_option("Waveform", &waveform, INT, names, | ||
245 | NUM_WAVEFORMS, NULL); | ||
246 | } | ||
247 | |||
248 | /* Tests hardware sample rate switching */ | ||
249 | /* TODO: needs a volume control */ | ||
250 | enum plugin_status plugin_start(struct plugin_api *api, void *parameter) | ||
251 | { | ||
252 | static const struct menu_item items[] = | ||
253 | { | ||
254 | { "Set Waveform", NULL }, | ||
255 | { "Play Waveform", NULL }, | ||
256 | { "Quit", NULL }, | ||
257 | }; | ||
258 | |||
259 | bool exit = false; | ||
260 | int m; | ||
261 | bool talk_menu; | ||
262 | |||
263 | rb = api; | ||
264 | |||
265 | /* Have to shut up voice menus or it will mess up our waveform playback */ | ||
266 | talk_menu = rb->global_settings->talk_menu; | ||
267 | rb->global_settings->talk_menu = false; | ||
268 | |||
269 | m = rb->menu_init(items, ARRAYLEN(items), | ||
270 | NULL, NULL, NULL, NULL); | ||
271 | |||
272 | while (!exit) | ||
273 | { | ||
274 | int result = rb->menu_show(m); | ||
275 | |||
276 | switch (result) | ||
277 | { | ||
278 | case 0: | ||
279 | set_waveform(); | ||
280 | break; | ||
281 | case 1: | ||
282 | play_waveform(); | ||
283 | break; | ||
284 | case 2: | ||
285 | exit = true; | ||
286 | break; | ||
287 | } | ||
288 | } | ||
289 | |||
290 | rb->menu_exit(m); | ||
291 | |||
292 | rb->global_settings->talk_menu = talk_menu; | ||
293 | |||
294 | return PLUGIN_OK; | ||
295 | (void)parameter; | ||
296 | } | ||