Bump plugin API version. This should have been done in r24587. Also, because the...
[kugel-rb.git] / apps / plugins / test_codec.c
blobe57af8cc0aa2bc45ffe07b04ab646c2c510587a7
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007 Dave Chapman
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 ****************************************************************************/
21 #include "plugin.h"
23 PLUGIN_HEADER
25 /* All swcodec targets have BUTTON_SELECT apart from the H10 and M3 */
27 #if CONFIG_KEYPAD == IRIVER_H10_PAD
28 #define TESTCODEC_EXITBUTTON BUTTON_RIGHT
29 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
30 #define TESTCODEC_EXITBUTTON BUTTON_RC_PLAY
31 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
32 #define TESTCODEC_EXITBUTTON BUTTON_PLAY
33 #elif CONFIG_KEYPAD == COWON_D2_PAD || CONFIG_KEYPAD == ONDAVX747_PAD
34 #define TESTCODEC_EXITBUTTON BUTTON_POWER
35 #elif defined(HAVE_TOUCHSCREEN)
36 #define TESTCODEC_EXITBUTTON BUTTON_TOPLEFT
37 #else
38 #define TESTCODEC_EXITBUTTON BUTTON_SELECT
39 #endif
41 /* Log functions copied from test_disk.c */
42 static int line = 0;
43 static int max_line = 0;
44 static int log_fd = -1;
45 static char logfilename[MAX_PATH];
47 static bool log_init(bool use_logfile)
49 int h;
51 rb->lcd_getstringsize("A", NULL, &h);
52 max_line = LCD_HEIGHT / h;
53 line = 0;
54 rb->lcd_clear_display();
55 rb->lcd_update();
57 if (use_logfile) {
58 rb->create_numbered_filename(logfilename, "/", "test_codec_log_", ".txt",
59 2 IF_CNFN_NUM_(, NULL));
60 log_fd = rb->open(logfilename, O_RDWR|O_CREAT|O_TRUNC);
61 return log_fd >= 0;
64 return true;
67 static void log_text(char *text, bool advance)
69 rb->lcd_puts(0, line, text);
70 rb->lcd_update();
71 if (advance)
73 if (++line >= max_line)
74 line = 0;
75 if (log_fd >= 0)
76 rb->fdprintf(log_fd, "%s\n", text);
80 static void log_close(void)
82 if (log_fd >= 0)
83 rb->close(log_fd);
86 struct wavinfo_t
88 int fd;
89 int samplerate;
90 int channels;
91 int sampledepth;
92 int stereomode;
93 int totalsamples;
96 static void* audiobuf;
97 static void* codec_mallocbuf;
98 static size_t audiosize;
99 static char str[MAX_PATH];
101 /* Our local implementation of the codec API */
102 static struct codec_api ci;
104 struct test_track_info {
105 struct mp3entry id3; /* TAG metadata */
106 size_t filesize; /* File total length */
109 static struct test_track_info track;
110 static bool taginfo_ready = true;
112 static bool use_dsp;
114 static bool checksum;
115 static uint32_t crc32;
117 static volatile unsigned int elapsed;
118 static volatile bool codec_playing;
119 static volatile long endtick;
120 struct wavinfo_t wavinfo;
122 static unsigned char wav_header[44] =
124 'R','I','F','F', // 0 - ChunkID
125 0,0,0,0, // 4 - ChunkSize (filesize-8)
126 'W','A','V','E', // 8 - Format
127 'f','m','t',' ', // 12 - SubChunkID
128 16,0,0,0, // 16 - SubChunk1ID // 16 for PCM
129 1,0, // 20 - AudioFormat (1=16-bit)
130 0,0, // 22 - NumChannels
131 0,0,0,0, // 24 - SampleRate in Hz
132 0,0,0,0, // 28 - Byte Rate (SampleRate*NumChannels*(BitsPerSample/8)
133 0,0, // 32 - BlockAlign (== NumChannels * BitsPerSample/8)
134 16,0, // 34 - BitsPerSample
135 'd','a','t','a', // 36 - Subchunk2ID
136 0,0,0,0 // 40 - Subchunk2Size
139 static inline void int2le32(unsigned char* buf, int32_t x)
141 buf[0] = (x & 0xff);
142 buf[1] = (x & 0xff00) >> 8;
143 buf[2] = (x & 0xff0000) >> 16;
144 buf[3] = (x & 0xff000000) >>24;
147 static inline void int2le24(unsigned char* buf, int32_t x)
149 buf[0] = (x & 0xff);
150 buf[1] = (x & 0xff00) >> 8;
151 buf[2] = (x & 0xff0000) >> 16;
154 static inline void int2le16(unsigned char* buf, int16_t x)
156 buf[0] = (x & 0xff);
157 buf[1] = (x & 0xff00) >> 8;
160 /* 32KB should be enough */
161 static unsigned char wavbuffer[32*1024];
162 static unsigned char dspbuffer[32*1024];
164 void init_wav(char* filename)
166 wavinfo.totalsamples = 0;
168 wavinfo.fd = rb->creat(filename);
170 if (wavinfo.fd >= 0)
172 /* Write WAV header - we go back and fill in the details at the end */
173 rb->write(wavinfo.fd, wav_header, sizeof(wav_header));
178 void close_wav(void)
180 int filesize = rb->filesize(wavinfo.fd);
181 int channels = (wavinfo.stereomode == STEREO_MONO) ? 1 : 2;
182 int bps = 16; /* TODO */
184 /* We assume 16-bit, Stereo */
186 rb->lseek(wavinfo.fd,0,SEEK_SET);
188 int2le32(wav_header+4, filesize-8); /* ChunkSize */
190 int2le16(wav_header+22, channels);
192 int2le32(wav_header+24, wavinfo.samplerate);
194 int2le32(wav_header+28, wavinfo.samplerate * channels * (bps / 8)); /* ByteRate */
196 int2le16(wav_header+32, channels * (bps / 8));
198 int2le32(wav_header+40, filesize - 44); /* Subchunk2Size */
200 rb->write(wavinfo.fd, wav_header, sizeof(wav_header));
202 rb->close(wavinfo.fd);
205 /* Returns buffer to malloc array. Only codeclib should need this. */
206 static void* codec_get_buffer(size_t *size)
208 DEBUGF("codec_get_buffer(%d)\n",(int)size);
209 *size = CODEC_SIZE;
210 return codec_mallocbuf;
213 static int process_dsp(const void *ch1, const void *ch2, int count)
215 const char *src[2] = { ch1, ch2 };
216 int written_count = 0;
217 char *dest = dspbuffer;
219 while (count > 0)
221 int out_count = rb->dsp_output_count(ci.dsp, count);
223 int inp_count = rb->dsp_input_count(ci.dsp, out_count);
225 if (inp_count <= 0)
226 break;
228 if (inp_count > count)
229 inp_count = count;
231 out_count = rb->dsp_process(ci.dsp, dest, src, inp_count);
233 if (out_count <= 0)
234 break;
236 written_count += out_count;
237 dest += out_count * 4;
239 count -= inp_count;
242 return written_count;
245 static inline int32_t clip_sample(int32_t sample)
247 if ((int16_t)sample != sample)
248 sample = 0x7fff ^ (sample >> 31);
250 return sample;
253 /* Null output */
254 static void pcmbuf_insert_null(const void *ch1, const void *ch2, int count)
256 if (use_dsp)
257 process_dsp(ch1, ch2, count);
259 /* Prevent idle poweroff */
260 rb->reset_poweroff_timer();
263 static void pcmbuf_insert_checksum(const void *ch1, const void *ch2, int count)
265 const int16_t* data1_16;
266 const int16_t* data2_16;
267 const int32_t* data1_32;
268 const int32_t* data2_32;
269 const int scale = wavinfo.sampledepth - 15;
270 const int dc_bias = 1 << (scale - 1);
271 int channels = (wavinfo.stereomode == STEREO_MONO) ? 1 : 2;
273 /* Prevent idle poweroff */
274 rb->reset_poweroff_timer();
276 if (use_dsp) {
277 count = process_dsp(ch1, ch2, count);
278 wavinfo.totalsamples += count;
279 if (channels == 1)
281 unsigned char *s = dspbuffer, *d = dspbuffer;
282 int c = count;
283 while (c-- > 0)
285 *d++ = *s++;
286 *d++ = *s++;
287 s++;
288 s++;
291 crc32 = rb->crc_32(dspbuffer, count * 2 * channels, crc32);
293 else
295 if (wavinfo.sampledepth <= 16) {
296 data1_16 = ch1;
297 data2_16 = ch2;
299 switch(wavinfo.stereomode)
301 case STEREO_INTERLEAVED:
302 while (count--) {
303 crc32 = rb->crc_32(data1_16, 4, crc32);
304 data1_16 += 2;
306 break;
308 case STEREO_NONINTERLEAVED:
309 while (count--) {
310 crc32 = rb->crc_32(data1_16++, 2, crc32);
311 crc32 = rb->crc_32(data2_16++, 2, crc32);
313 break;
315 case STEREO_MONO:
316 while (count--) {
317 crc32 = rb->crc_32(data1_16++, 2, crc32);
319 break;
322 else
324 data1_32 = ch1;
325 data2_32 = ch2;
327 switch(wavinfo.stereomode)
329 case STEREO_INTERLEAVED:
330 while (count--) {
331 int16_t s = clip_sample((*data1_32++ + dc_bias) >> scale);
332 crc32 = rb->crc_32(&s, 2, crc32);
333 s = clip_sample((*data1_32++ + dc_bias) >> scale);
334 crc32 = rb->crc_32(&s, 2, crc32);
336 break;
338 case STEREO_NONINTERLEAVED:
339 while (count--) {
340 int16_t s = clip_sample((*data1_32++ + dc_bias) >> scale);
341 crc32 = rb->crc_32(&s, 2, crc32);
342 s = clip_sample((*data2_32++ + dc_bias) >> scale);
343 crc32 = rb->crc_32(&s, 2, crc32);
346 break;
348 case STEREO_MONO:
349 while (count--) {
350 int16_t s = clip_sample((*data1_32++ + dc_bias) >> scale);
351 crc32 = rb->crc_32(&s, 2, crc32);
353 break;
359 /* WAV output */
360 static void pcmbuf_insert_wav(const void *ch1, const void *ch2, int count)
362 const int16_t* data1_16;
363 const int16_t* data2_16;
364 const int32_t* data1_32;
365 const int32_t* data2_32;
366 unsigned char* p = wavbuffer;
367 const int scale = wavinfo.sampledepth - 15;
368 const int dc_bias = 1 << (scale - 1);
369 int channels = (wavinfo.stereomode == STEREO_MONO) ? 1 : 2;
371 /* Prevent idle poweroff */
372 rb->reset_poweroff_timer();
374 if (use_dsp) {
375 count = process_dsp(ch1, ch2, count);
376 wavinfo.totalsamples += count;
377 if (channels == 1)
379 unsigned char *s = dspbuffer, *d = dspbuffer;
380 int c = count;
381 while (c-- > 0)
383 *d++ = *s++;
384 *d++ = *s++;
385 s++;
386 s++;
389 rb->write(wavinfo.fd, dspbuffer, count * 2 * channels);
391 else
393 if (wavinfo.sampledepth <= 16) {
394 data1_16 = ch1;
395 data2_16 = ch2;
397 switch(wavinfo.stereomode)
399 case STEREO_INTERLEAVED:
400 while (count--) {
401 int2le16(p,*data1_16++);
402 p += 2;
403 int2le16(p,*data1_16++);
404 p += 2;
406 break;
408 case STEREO_NONINTERLEAVED:
409 while (count--) {
410 int2le16(p,*data1_16++);
411 p += 2;
412 int2le16(p,*data2_16++);
413 p += 2;
416 break;
418 case STEREO_MONO:
419 while (count--) {
420 int2le16(p,*data1_16++);
421 p += 2;
423 break;
425 } else {
426 data1_32 = ch1;
427 data2_32 = ch2;
429 switch(wavinfo.stereomode)
431 case STEREO_INTERLEAVED:
432 while (count--) {
433 int2le16(p, clip_sample((*data1_32++ + dc_bias) >> scale));
434 p += 2;
435 int2le16(p, clip_sample((*data1_32++ + dc_bias) >> scale));
436 p += 2;
438 break;
440 case STEREO_NONINTERLEAVED:
441 while (count--) {
442 int2le16(p, clip_sample((*data1_32++ + dc_bias) >> scale));
443 p += 2;
444 int2le16(p, clip_sample((*data2_32++ + dc_bias) >> scale));
445 p += 2;
448 break;
450 case STEREO_MONO:
451 while (count--) {
452 int2le16(p, clip_sample((*data1_32++ + dc_bias) >> scale));
453 p += 2;
455 break;
459 wavinfo.totalsamples += count;
460 rb->write(wavinfo.fd, wavbuffer, p - wavbuffer);
461 } /* else */
464 /* Set song position in WPS (value in ms). */
465 static void set_elapsed(unsigned long value)
467 elapsed = value;
471 /* Read next <size> amount bytes from file buffer to <ptr>.
472 Will return number of bytes read or 0 if end of file. */
473 static size_t read_filebuf(void *ptr, size_t size)
475 if (ci.curpos > (off_t)track.filesize)
477 return 0;
478 } else {
479 /* TODO: Don't read beyond end of buffer */
480 rb->memcpy(ptr, audiobuf + ci.curpos, size);
481 ci.curpos += size;
482 return size;
487 /* Request pointer to file buffer which can be used to read
488 <realsize> amount of data. <reqsize> tells the buffer system
489 how much data it should try to allocate. If <realsize> is 0,
490 end of file is reached. */
491 static void* request_buffer(size_t *realsize, size_t reqsize)
493 *realsize = MIN(track.filesize-ci.curpos,reqsize);
495 return (audiobuf + ci.curpos);
499 /* Advance file buffer position by <amount> amount of bytes. */
500 static void advance_buffer(size_t amount)
502 ci.curpos += amount;
506 /* Advance file buffer to a pointer location inside file buffer. */
507 static void advance_buffer_loc(void *ptr)
509 ci.curpos = ptr - audiobuf;
513 /* Seek file buffer to position <newpos> beginning of file. */
514 static bool seek_buffer(size_t newpos)
516 ci.curpos = newpos;
517 return true;
521 /* Codec should call this function when it has done the seeking. */
522 static void seek_complete(void)
524 /* Do nothing */
527 /* Request file change from file buffer. Returns true is next
528 track is available and changed. If return value is false,
529 codec should exit immediately with PLUGIN_OK status. */
530 static bool request_next_track(void)
532 /* We are only decoding a single track */
533 return false;
537 /* Free the buffer area of the current codec after its loaded */
538 static void discard_codec(void)
540 /* ??? */
544 static void set_offset(size_t value)
546 /* ??? */
547 (void)value;
551 /* Configure different codec buffer parameters. */
552 static void configure(int setting, intptr_t value)
554 if (use_dsp)
555 rb->dsp_configure(ci.dsp, setting, value);
556 switch(setting)
558 case DSP_SWITCH_FREQUENCY:
559 case DSP_SET_FREQUENCY:
560 DEBUGF("samplerate=%d\n",(int)value);
561 wavinfo.samplerate = (int)value;
562 break;
564 case DSP_SET_SAMPLE_DEPTH:
565 DEBUGF("sampledepth = %d\n",(int)value);
566 wavinfo.sampledepth=(int)value;
567 break;
569 case DSP_SET_STEREO_MODE:
570 DEBUGF("Stereo mode = %d\n",(int)value);
571 wavinfo.stereomode=(int)value;
572 break;
577 static void init_ci(void)
579 /* --- Our "fake" implementations of the codec API functions. --- */
581 ci.codec_get_buffer = codec_get_buffer;
583 if (wavinfo.fd >= 0) {
584 ci.pcmbuf_insert = pcmbuf_insert_wav;
585 } else if (checksum){
586 ci.pcmbuf_insert = pcmbuf_insert_checksum;
587 } else {
588 ci.pcmbuf_insert = pcmbuf_insert_null;
591 ci.set_elapsed = set_elapsed;
592 ci.read_filebuf = read_filebuf;
593 ci.request_buffer = request_buffer;
594 ci.advance_buffer = advance_buffer;
595 ci.advance_buffer_loc = advance_buffer_loc;
596 ci.seek_buffer = seek_buffer;
597 ci.seek_complete = seek_complete;
598 ci.request_next_track = request_next_track;
599 ci.discard_codec = discard_codec;
600 ci.set_offset = set_offset;
601 ci.configure = configure;
602 ci.dsp = (struct dsp_config *)rb->dsp_configure(NULL, DSP_MYDSP,
603 CODEC_IDX_AUDIO);
605 /* --- "Core" functions --- */
607 /* kernel/ system */
608 ci.sleep = rb->sleep;
609 ci.yield = rb->yield;
611 /* strings and memory */
612 ci.strcpy = rb->strcpy;
613 ci.strlen = rb->strlen;
614 ci.strcmp = rb->strcmp;
615 ci.strcat = rb->strcat;
616 ci.memset = rb->memset;
617 ci.memcpy = rb->memcpy;
618 ci.memmove = rb->memmove;
619 ci.memcmp = rb->memcmp;
620 ci.memchr = rb->memchr;
621 ci.strcasestr = rb->strcasestr;
622 #if defined(DEBUG) || defined(SIMULATOR)
623 ci.debugf = rb->debugf;
624 #endif
625 #ifdef ROCKBOX_HAS_LOGF
626 ci.logf = rb->logf;
627 #endif
629 ci.qsort = rb->qsort;
630 ci.global_settings = rb->global_settings;
632 #ifdef RB_PROFILE
633 ci.profile_thread = rb->profile_thread;
634 ci.profstop = rb->profstop;
635 ci.profile_func_enter = rb->profile_func_enter;
636 ci.profile_func_exit = rb->profile_func_exit;
637 #endif
639 #if NUM_CORES > 1
640 ci.cpucache_invalidate = rb->cpucache_invalidate;
641 ci.cpucache_flush = rb->cpucache_flush;
642 #endif
644 #if NUM_CORES > 1
645 ci.create_thread = rb->create_thread;
646 ci.thread_thaw = rb->thread_thaw;
647 ci.thread_wait = rb->thread_wait;
648 ci.semaphore_init = rb->semaphore_init;
649 ci.semaphore_wait = rb->semaphore_wait;
650 ci.semaphore_release = rb->semaphore_release;
651 #endif
653 #ifdef CPU_ARM
654 ci.__div0 = rb->__div0;
655 #endif
658 static void codec_thread(void)
660 const char* codecname;
661 int res;
663 codecname = rb->get_codec_filename(track.id3.codectype);
665 /* Load the codec and start decoding. */
666 res = rb->codec_load_file(codecname,&ci);
668 /* Signal to the main thread that we are done */
669 endtick = *rb->current_tick;
670 codec_playing = false;
673 static enum plugin_status test_track(const char* filename)
675 size_t n;
676 int fd;
677 enum plugin_status res = PLUGIN_ERROR;
678 long starttick;
679 long ticks;
680 unsigned long speed;
681 unsigned long duration;
682 const char* ch;
684 /* Display filename (excluding any path)*/
685 ch = rb->strrchr(filename, '/');
686 if (ch==NULL)
687 ch = filename;
688 else
689 ch++;
691 rb->snprintf(str,sizeof(str),"%s",ch);
692 log_text(str,true);
694 log_text("Loading...",false);
696 fd = rb->open(filename,O_RDONLY);
697 if (fd < 0)
699 log_text("Cannot open file",true);
700 goto exit;
703 track.filesize = rb->filesize(fd);
705 /* Clear the id3 struct */
706 rb->memset(&track.id3, 0, sizeof(struct mp3entry));
708 if (!rb->get_metadata(&(track.id3), fd, filename))
710 log_text("Cannot read metadata",true);
711 goto exit;
714 if (track.filesize > audiosize)
716 log_text("File too large",true);
717 goto exit;
720 n = rb->read(fd, audiobuf, track.filesize);
722 if (n != track.filesize)
724 log_text("Read failed.",true);
725 goto exit;
728 /* Initialise the function pointers in the codec API */
729 init_ci();
731 /* Prepare the codec struct for playing the whole file */
732 ci.filesize = track.filesize;
733 ci.id3 = &track.id3;
734 ci.taginfo_ready = &taginfo_ready;
735 ci.curpos = 0;
736 ci.stop_codec = false;
737 ci.new_track = 0;
738 ci.seek_time = 0;
740 if (use_dsp)
741 rb->dsp_configure(ci.dsp, DSP_RESET, 0);
743 if (checksum)
744 crc32 = 0xffffffff;
746 starttick = *rb->current_tick;
748 codec_playing = true;
750 rb->codec_thread_do_callback(codec_thread, NULL);
752 /* Wait for codec thread to die */
753 while (codec_playing)
755 rb->sleep(HZ);
756 rb->snprintf(str,sizeof(str),"%d of %d",elapsed,(int)track.id3.length);
757 log_text(str,false);
759 ticks = endtick - starttick;
761 /* Be sure it is done */
762 rb->codec_thread_do_callback(NULL, NULL);
764 log_text(str,true);
766 if (checksum)
768 rb->snprintf(str, sizeof(str), "CRC32 - %x", (unsigned)crc32);
769 log_text(str,true);
771 else if (wavinfo.fd < 0)
773 /* Display benchmark information */
774 rb->snprintf(str,sizeof(str),"Decode time - %d.%02ds",(int)ticks/100,(int)ticks%100);
775 log_text(str,true);
777 duration = track.id3.length / 10;
778 rb->snprintf(str,sizeof(str),"File duration - %d.%02ds",(int)duration/100,(int)duration%100);
779 log_text(str,true);
781 if (ticks > 0)
782 speed = duration * 10000 / ticks;
783 else
784 speed = 0;
786 rb->snprintf(str,sizeof(str),"%d.%02d%% realtime",(int)speed/100,(int)speed%100);
787 log_text(str,true);
789 #ifndef SIMULATOR
790 /* show effective clockrate in MHz needed for realtime decoding */
791 if (speed > 0)
793 speed = CPUFREQ_MAX / speed;
794 rb->snprintf(str,sizeof(str),"%d.%02dMHz needed for realtime",
795 (int)speed/100,(int)speed%100);
796 log_text(str,true);
798 #endif
801 res = PLUGIN_OK;
803 exit:
804 rb->backlight_on();
806 if (fd >= 0)
808 rb->close(fd);
811 return res;
814 /* plugin entry point */
815 enum plugin_status plugin_start(const void* parameter)
817 int result, selection = 0;
818 enum plugin_status res = PLUGIN_OK;
819 int scandir;
820 struct dirent *entry;
821 DIR* dir;
822 char* ch;
823 char dirpath[MAX_PATH];
824 char filename[MAX_PATH];
826 if (parameter == NULL)
828 rb->splash(HZ*2, "No File");
829 return PLUGIN_ERROR;
832 codec_mallocbuf = rb->plugin_get_audio_buffer(&audiosize);
833 audiobuf = SKIPBYTES(codec_mallocbuf, CODEC_SIZE);
834 audiosize -= CODEC_SIZE;
836 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
837 rb->cpu_boost(true);
838 #endif
839 rb->lcd_clear_display();
840 rb->lcd_update();
842 enum
844 SPEED_TEST = 0,
845 SPEED_TEST_DIR,
846 WRITE_WAV,
847 SPEED_TEST_WITH_DSP,
848 SPEED_TEST_DIR_WITH_DSP,
849 WRITE_WAV_WITH_DSP,
850 CHECKSUM,
851 CHECKSUM_DIR,
852 QUIT,
855 MENUITEM_STRINGLIST(
856 menu, "test_codec", NULL,
857 "Speed test",
858 "Speed test folder",
859 "Write WAV",
860 "Speed test with DSP",
861 "Speed test folder with DSP",
862 "Write WAV with DSP",
863 "Checksum",
864 "Checksum folder",
865 "Quit",
868 show_menu:
869 rb->lcd_clear_display();
871 result = rb->do_menu(&menu, &selection, NULL, false);
873 if (result == QUIT)
875 res = PLUGIN_OK;
876 goto exit;
879 scandir = 0;
881 if ((checksum = (result == CHECKSUM || result == CHECKSUM_DIR)))
882 result -= 6;
884 if ((use_dsp = ((result >= SPEED_TEST_WITH_DSP)
885 && (result <= WRITE_WAV_WITH_DSP)))) {
886 result -= 3;
888 if (result == SPEED_TEST) {
889 wavinfo.fd = -1;
890 log_init(false);
891 } else if (result == SPEED_TEST_DIR) {
892 wavinfo.fd = -1;
893 scandir = 1;
895 /* Only create a log file when we are testing a folder */
896 if (!log_init(true)) {
897 rb->splash(HZ*2, "Cannot create logfile");
898 res = PLUGIN_ERROR;
899 goto exit;
901 } else if (result == WRITE_WAV) {
902 log_init(false);
903 init_wav("/test.wav");
904 if (wavinfo.fd < 0) {
905 rb->splash(HZ*2, "Cannot create /test.wav");
906 res = PLUGIN_ERROR;
907 goto exit;
909 } else if (result == MENU_ATTACHED_USB) {
910 res = PLUGIN_USB_CONNECTED;
911 goto exit;
912 } else if (result < 0) {
913 res = PLUGIN_OK;
914 goto exit;
917 if (scandir) {
918 /* Test all files in the same directory as the file selected by the
919 user */
921 rb->strlcpy(dirpath,parameter,sizeof(dirpath));
922 ch = rb->strrchr(dirpath,'/');
923 ch[1]=0;
925 DEBUGF("Scanning directory \"%s\"\n",dirpath);
926 dir = rb->opendir(dirpath);
927 if (dir) {
928 entry = rb->readdir(dir);
929 while (entry) {
930 if (!(entry->attribute & ATTR_DIRECTORY)) {
931 rb->snprintf(filename,sizeof(filename),"%s%s",dirpath,entry->d_name);
932 test_track(filename);
933 log_text("", true);
936 /* Read next entry */
937 entry = rb->readdir(dir);
940 rb->closedir(dir);
942 } else {
943 /* Just test the file */
944 res = test_track(parameter);
946 /* Close WAV file (if there was one) */
947 if (wavinfo.fd >= 0) {
948 close_wav();
949 log_text("Wrote /test.wav",true);
951 while (rb->button_get(true) != TESTCODEC_EXITBUTTON);
953 goto show_menu;
955 exit:
956 log_close();
958 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
959 rb->cpu_boost(false);
960 #endif
962 return res;