Move paths.[ch] to firmware
[kugel-rb.git] / apps / plugins / test_codec.c
blobb8aa93d99b9e95640ebb92d537f62c2d4cc967b0
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 CONFIG_KEYPAD == PBELL_VIBE500_PAD
36 #define TESTCODEC_EXITBUTTON BUTTON_REC
37 #elif defined(HAVE_TOUCHSCREEN)
38 #define TESTCODEC_EXITBUTTON BUTTON_TOPLEFT
39 #else
40 #define TESTCODEC_EXITBUTTON BUTTON_SELECT
41 #endif
43 /* Log functions copied from test_disk.c */
44 static int line = 0;
45 static int max_line = 0;
46 static int log_fd = -1;
48 static void log_close(void)
50 if (log_fd >= 0)
51 rb->close(log_fd);
54 static bool log_init(bool use_logfile)
56 int h;
57 char logfilename[MAX_PATH];
59 rb->lcd_getstringsize("A", NULL, &h);
60 max_line = LCD_HEIGHT / h;
61 line = 0;
62 rb->lcd_clear_display();
63 rb->lcd_update();
65 if (use_logfile) {
66 log_close();
67 rb->create_numbered_filename(logfilename, "/", "test_codec_log_", ".txt",
68 2 IF_CNFN_NUM_(, NULL));
69 log_fd = rb->open(logfilename, O_RDWR|O_CREAT|O_TRUNC, 0666);
70 return log_fd >= 0;
73 return true;
76 static void log_text(char *text, bool advance)
78 rb->lcd_puts(0, line, text);
79 rb->lcd_update();
80 if (advance)
82 if (++line >= max_line)
83 line = 0;
84 if (log_fd >= 0)
85 rb->fdprintf(log_fd, "%s\n", text);
89 struct wavinfo_t
91 int fd;
92 int samplerate;
93 int channels;
94 int sampledepth;
95 int stereomode;
96 int totalsamples;
99 static void* audiobuf;
100 static void* codec_mallocbuf;
101 static size_t audiosize;
102 static size_t audiobufsize;
103 static int offset;
104 static int fd;
106 /* Our local implementation of the codec API */
107 static struct codec_api ci;
109 struct test_track_info {
110 struct mp3entry id3; /* TAG metadata */
111 size_t filesize; /* File total length */
114 static struct test_track_info track;
115 static bool taginfo_ready = true;
117 static bool use_dsp;
119 static bool checksum;
120 static uint32_t crc32;
122 static volatile unsigned int elapsed;
123 static volatile bool codec_playing;
124 static volatile long endtick;
125 static volatile long rebuffertick;
126 struct wavinfo_t wavinfo;
128 static unsigned char wav_header[44] =
130 'R','I','F','F', // 0 - ChunkID
131 0,0,0,0, // 4 - ChunkSize (filesize-8)
132 'W','A','V','E', // 8 - Format
133 'f','m','t',' ', // 12 - SubChunkID
134 16,0,0,0, // 16 - SubChunk1ID // 16 for PCM
135 1,0, // 20 - AudioFormat (1=16-bit)
136 0,0, // 22 - NumChannels
137 0,0,0,0, // 24 - SampleRate in Hz
138 0,0,0,0, // 28 - Byte Rate (SampleRate*NumChannels*(BitsPerSample/8)
139 0,0, // 32 - BlockAlign (== NumChannels * BitsPerSample/8)
140 16,0, // 34 - BitsPerSample
141 'd','a','t','a', // 36 - Subchunk2ID
142 0,0,0,0 // 40 - Subchunk2Size
145 static inline void int2le32(unsigned char* buf, int32_t x)
147 buf[0] = (x & 0xff);
148 buf[1] = (x & 0xff00) >> 8;
149 buf[2] = (x & 0xff0000) >> 16;
150 buf[3] = (x & 0xff000000) >>24;
153 static inline void int2le24(unsigned char* buf, int32_t x)
155 buf[0] = (x & 0xff);
156 buf[1] = (x & 0xff00) >> 8;
157 buf[2] = (x & 0xff0000) >> 16;
160 static inline void int2le16(unsigned char* buf, int16_t x)
162 buf[0] = (x & 0xff);
163 buf[1] = (x & 0xff00) >> 8;
166 static unsigned char *wavbuffer;
167 static unsigned char *dspbuffer;
169 void init_wav(char* filename)
171 wavinfo.totalsamples = 0;
173 wavinfo.fd = rb->creat(filename, 0666);
175 if (wavinfo.fd >= 0)
177 /* Write WAV header - we go back and fill in the details at the end */
178 rb->write(wavinfo.fd, wav_header, sizeof(wav_header));
183 void close_wav(void)
185 int filesize = rb->filesize(wavinfo.fd);
186 int channels = (wavinfo.stereomode == STEREO_MONO) ? 1 : 2;
187 int bps = 16; /* TODO */
189 /* We assume 16-bit, Stereo */
191 rb->lseek(wavinfo.fd,0,SEEK_SET);
193 int2le32(wav_header+4, filesize-8); /* ChunkSize */
195 int2le16(wav_header+22, channels);
197 int2le32(wav_header+24, wavinfo.samplerate);
199 int2le32(wav_header+28, wavinfo.samplerate * channels * (bps / 8)); /* ByteRate */
201 int2le16(wav_header+32, channels * (bps / 8));
203 int2le32(wav_header+40, filesize - 44); /* Subchunk2Size */
205 rb->write(wavinfo.fd, wav_header, sizeof(wav_header));
207 rb->close(wavinfo.fd);
210 /* Returns buffer to malloc array. Only codeclib should need this. */
211 static void* codec_get_buffer(size_t *size)
213 DEBUGF("codec_get_buffer(%"PRIuPTR")\n",(uintptr_t)size);
214 *size = CODEC_SIZE;
215 return codec_mallocbuf;
218 static int process_dsp(const void *ch1, const void *ch2, int count)
220 const char *src[2] = { ch1, ch2 };
221 int written_count = 0;
222 char *dest = dspbuffer;
224 while (count > 0)
226 int out_count = rb->dsp_output_count(ci.dsp, count);
228 int inp_count = rb->dsp_input_count(ci.dsp, out_count);
230 if (inp_count <= 0)
231 break;
233 if (inp_count > count)
234 inp_count = count;
236 out_count = rb->dsp_process(ci.dsp, dest, src, inp_count);
238 if (out_count <= 0)
239 break;
241 written_count += out_count;
242 dest += out_count * 4;
244 count -= inp_count;
247 return written_count;
250 static inline int32_t clip_sample(int32_t sample)
252 if ((int16_t)sample != sample)
253 sample = 0x7fff ^ (sample >> 31);
255 return sample;
258 /* Null output */
259 static void pcmbuf_insert_null(const void *ch1, const void *ch2, int count)
261 if (use_dsp)
262 process_dsp(ch1, ch2, count);
264 /* Prevent idle poweroff */
265 rb->reset_poweroff_timer();
269 * Helper function used when the file is larger then the available memory.
270 * Rebuffers the file by setting the start of the audio buffer to be
271 * new_offset and filling from there.
273 static int fill_buffer(int new_offset){
274 size_t n, bytestoread;
275 long temp = *rb->current_tick;
276 rb->lseek(fd,new_offset,SEEK_SET);
278 if(new_offset + audiobufsize <= track.filesize)
279 bytestoread = audiobufsize;
280 else
281 bytestoread = track.filesize-new_offset;
283 n = rb->read(fd, audiobuf,bytestoread);
285 if (n != bytestoread)
287 log_text("Read failed.",true);
288 DEBUGF("read fail: got %d bytes, expected %d\n", (int)n, (int)audiobufsize);
289 rb->backlight_on();
291 if (fd >= 0)
293 rb->close(fd);
296 return -1;
298 offset = new_offset;
300 /*keep track of how much time we spent buffering*/
301 rebuffertick += *rb->current_tick-temp;
303 return 0;
306 /* WAV output or calculate crc32 of output*/
307 static void pcmbuf_insert_wav_checksum(const void *ch1, const void *ch2, int count)
309 const int16_t* data1_16;
310 const int16_t* data2_16;
311 const int32_t* data1_32;
312 const int32_t* data2_32;
313 unsigned char* p = wavbuffer;
314 const int scale = wavinfo.sampledepth - 15;
315 const int dc_bias = 1 << (scale - 1);
316 int channels = (wavinfo.stereomode == STEREO_MONO) ? 1 : 2;
318 /* Prevent idle poweroff */
319 rb->reset_poweroff_timer();
321 if (use_dsp) {
322 count = process_dsp(ch1, ch2, count);
323 wavinfo.totalsamples += count;
324 if (channels == 1)
326 unsigned char *s = dspbuffer, *d = dspbuffer;
327 int c = count;
328 while (c-- > 0)
330 *d++ = *s++;
331 *d++ = *s++;
332 s++;
333 s++;
336 if (checksum)
337 crc32 = rb->crc_32(dspbuffer, count * 2 * channels, crc32);
338 else
339 rb->write(wavinfo.fd, dspbuffer, count * 2 * channels);
341 else
343 if (wavinfo.sampledepth <= 16) {
344 data1_16 = ch1;
345 data2_16 = ch2;
347 switch(wavinfo.stereomode)
349 case STEREO_INTERLEAVED:
350 while (count--) {
351 int2le16(p,*data1_16++);
352 p += 2;
353 int2le16(p,*data1_16++);
354 p += 2;
356 break;
358 case STEREO_NONINTERLEAVED:
359 while (count--) {
360 int2le16(p,*data1_16++);
361 p += 2;
362 int2le16(p,*data2_16++);
363 p += 2;
366 break;
368 case STEREO_MONO:
369 while (count--) {
370 int2le16(p,*data1_16++);
371 p += 2;
373 break;
375 } else {
376 data1_32 = ch1;
377 data2_32 = ch2;
379 switch(wavinfo.stereomode)
381 case STEREO_INTERLEAVED:
382 while (count--) {
383 int2le16(p, clip_sample((*data1_32++ + dc_bias) >> scale));
384 p += 2;
385 int2le16(p, clip_sample((*data1_32++ + dc_bias) >> scale));
386 p += 2;
388 break;
390 case STEREO_NONINTERLEAVED:
391 while (count--) {
392 int2le16(p, clip_sample((*data1_32++ + dc_bias) >> scale));
393 p += 2;
394 int2le16(p, clip_sample((*data2_32++ + dc_bias) >> scale));
395 p += 2;
398 break;
400 case STEREO_MONO:
401 while (count--) {
402 int2le16(p, clip_sample((*data1_32++ + dc_bias) >> scale));
403 p += 2;
405 break;
409 wavinfo.totalsamples += count;
410 if (checksum)
411 crc32 = rb->crc_32(wavbuffer, p - wavbuffer, crc32);
412 else
413 rb->write(wavinfo.fd, wavbuffer, p - wavbuffer);
414 } /* else */
417 /* Set song position in WPS (value in ms). */
418 static void set_elapsed(unsigned long value)
420 elapsed = value;
424 /* Read next <size> amount bytes from file buffer to <ptr>.
425 Will return number of bytes read or 0 if end of file. */
426 static size_t read_filebuf(void *ptr, size_t size)
428 if (ci.curpos > (off_t)track.filesize)
430 return 0;
431 } else {
432 size_t realsize = MIN(track.filesize-ci.curpos,size);
434 /* check if we have enough bytes ready*/
435 if(realsize >(audiobufsize - (ci.curpos-offset)))
437 /*rebuffer so that we start at ci.curpos*/
438 fill_buffer(ci.curpos);
441 rb->memcpy(ptr, audiobuf + (ci.curpos-offset), realsize);
442 ci.curpos += realsize;
443 return realsize;
448 /* Request pointer to file buffer which can be used to read
449 <realsize> amount of data. <reqsize> tells the buffer system
450 how much data it should try to allocate. If <realsize> is 0,
451 end of file is reached. */
452 static void* request_buffer(size_t *realsize, size_t reqsize)
454 *realsize = MIN(track.filesize-ci.curpos,reqsize);
456 /*check if we have enough bytes ready - requested > bufsize-currentbufpos*/
457 if(*realsize>(audiobufsize - (ci.curpos-offset)))
459 /*rebuffer so that we start at ci.curpos*/
460 fill_buffer(ci.curpos);
463 return (audiobuf + (ci.curpos-offset));
466 /* Advance file buffer position by <amount> amount of bytes. */
467 static void advance_buffer(size_t amount)
469 ci.curpos += amount;
473 /* Advance file buffer to a pointer location inside file buffer. */
474 static void advance_buffer_loc(void *ptr)
476 ci.curpos = ptr - (audiobuf - offset);
480 /* Seek file buffer to position <newpos> beginning of file. */
481 static bool seek_buffer(size_t newpos)
483 ci.curpos = newpos;
484 return true;
488 /* Codec should call this function when it has done the seeking. */
489 static void seek_complete(void)
491 /* Do nothing */
494 /* Request file change from file buffer. Returns true is next
495 track is available and changed. If return value is false,
496 codec should exit immediately with PLUGIN_OK status. */
497 static bool request_next_track(void)
499 /* We are only decoding a single track */
500 return false;
504 /* Free the buffer area of the current codec after its loaded */
505 static void discard_codec(void)
507 /* ??? */
511 static void set_offset(size_t value)
513 /* ??? */
514 (void)value;
518 /* Configure different codec buffer parameters. */
519 static void configure(int setting, intptr_t value)
521 if (use_dsp)
522 rb->dsp_configure(ci.dsp, setting, value);
523 switch(setting)
525 case DSP_SWITCH_FREQUENCY:
526 case DSP_SET_FREQUENCY:
527 DEBUGF("samplerate=%d\n",(int)value);
528 wavinfo.samplerate = (int)value;
529 break;
531 case DSP_SET_SAMPLE_DEPTH:
532 DEBUGF("sampledepth = %d\n",(int)value);
533 wavinfo.sampledepth=(int)value;
534 break;
536 case DSP_SET_STEREO_MODE:
537 DEBUGF("Stereo mode = %d\n",(int)value);
538 wavinfo.stereomode=(int)value;
539 break;
544 static void init_ci(void)
546 /* --- Our "fake" implementations of the codec API functions. --- */
548 ci.codec_get_buffer = codec_get_buffer;
550 if (wavinfo.fd >= 0 || checksum) {
551 ci.pcmbuf_insert = pcmbuf_insert_wav_checksum;
552 } else {
553 ci.pcmbuf_insert = pcmbuf_insert_null;
556 ci.set_elapsed = set_elapsed;
557 ci.read_filebuf = read_filebuf;
558 ci.request_buffer = request_buffer;
559 ci.advance_buffer = advance_buffer;
560 ci.advance_buffer_loc = advance_buffer_loc;
561 ci.seek_buffer = seek_buffer;
562 ci.seek_complete = seek_complete;
563 ci.request_next_track = request_next_track;
564 ci.discard_codec = discard_codec;
565 ci.set_offset = set_offset;
566 ci.configure = configure;
567 ci.dsp = (struct dsp_config *)rb->dsp_configure(NULL, DSP_MYDSP,
568 CODEC_IDX_AUDIO);
570 /* --- "Core" functions --- */
572 /* kernel/ system */
573 ci.sleep = rb->sleep;
574 ci.yield = rb->yield;
576 /* strings and memory */
577 ci.strcpy = rb->strcpy;
578 ci.strlen = rb->strlen;
579 ci.strcmp = rb->strcmp;
580 ci.strcat = rb->strcat;
581 ci.memset = rb->memset;
582 ci.memcpy = rb->memcpy;
583 ci.memmove = rb->memmove;
584 ci.memcmp = rb->memcmp;
585 ci.memchr = rb->memchr;
586 ci.strcasestr = rb->strcasestr;
587 #if defined(DEBUG) || defined(SIMULATOR)
588 ci.debugf = rb->debugf;
589 #endif
590 #ifdef ROCKBOX_HAS_LOGF
591 ci.logf = rb->logf;
592 #endif
594 ci.qsort = rb->qsort;
595 ci.global_settings = rb->global_settings;
597 #ifdef RB_PROFILE
598 ci.profile_thread = rb->profile_thread;
599 ci.profstop = rb->profstop;
600 ci.profile_func_enter = rb->profile_func_enter;
601 ci.profile_func_exit = rb->profile_func_exit;
602 #endif
604 #if NUM_CORES > 1
605 ci.cpucache_invalidate = rb->cpucache_invalidate;
606 ci.cpucache_flush = rb->cpucache_flush;
607 #endif
609 #if NUM_CORES > 1
610 ci.create_thread = rb->create_thread;
611 ci.thread_thaw = rb->thread_thaw;
612 ci.thread_wait = rb->thread_wait;
613 ci.semaphore_init = rb->semaphore_init;
614 ci.semaphore_wait = rb->semaphore_wait;
615 ci.semaphore_release = rb->semaphore_release;
616 #endif
618 #ifdef CPU_ARM
619 ci.__div0 = rb->__div0;
620 #endif
623 static void codec_thread(void)
625 const char* codecname;
626 int res;
628 codecname = rb->get_codec_filename(track.id3.codectype);
630 /* Load the codec and start decoding. */
631 res = rb->codec_load_file(codecname,&ci);
633 /* Signal to the main thread that we are done */
634 endtick = *rb->current_tick - rebuffertick;
635 codec_playing = false;
638 static enum plugin_status test_track(const char* filename)
640 size_t n;
641 enum plugin_status res = PLUGIN_ERROR;
642 long starttick;
643 long ticks;
644 unsigned long speed;
645 unsigned long duration;
646 const char* ch;
647 char str[MAX_PATH];
648 offset=0;
650 /* Display filename (excluding any path)*/
651 ch = rb->strrchr(filename, '/');
652 if (ch==NULL)
653 ch = filename;
654 else
655 ch++;
657 rb->snprintf(str,sizeof(str),"%s",ch);
658 log_text(str,true);
660 log_text("Loading...",false);
662 fd = rb->open(filename,O_RDONLY);
663 if (fd < 0)
665 log_text("Cannot open file",true);
666 goto exit;
669 track.filesize = rb->filesize(fd);
671 /* Clear the id3 struct */
672 rb->memset(&track.id3, 0, sizeof(struct mp3entry));
674 if (!rb->get_metadata(&(track.id3), fd, filename))
676 log_text("Cannot read metadata",true);
677 goto exit;
680 if (track.filesize > audiosize)
682 audiobufsize=audiosize;
684 } else
686 audiobufsize=track.filesize;
689 n = rb->read(fd, audiobuf, audiobufsize);
691 if (n != audiobufsize)
693 log_text("Read failed.",true);
694 goto exit;
698 /* Initialise the function pointers in the codec API */
699 init_ci();
701 /* Prepare the codec struct for playing the whole file */
702 ci.filesize = track.filesize;
703 ci.id3 = &track.id3;
704 ci.taginfo_ready = &taginfo_ready;
705 ci.curpos = 0;
706 ci.stop_codec = false;
707 ci.new_track = 0;
708 ci.seek_time = 0;
710 if (use_dsp)
711 rb->dsp_configure(ci.dsp, DSP_RESET, 0);
713 if (checksum)
714 crc32 = 0xffffffff;
716 rebuffertick=0;
717 starttick = *rb->current_tick;
719 codec_playing = true;
721 rb->codec_thread_do_callback(codec_thread, NULL);
723 /* Wait for codec thread to die */
724 while (codec_playing)
726 rb->sleep(HZ);
727 rb->snprintf(str,sizeof(str),"%d of %d",elapsed,(int)track.id3.length);
728 log_text(str,false);
730 ticks = endtick - starttick;
732 /* Be sure it is done */
733 rb->codec_thread_do_callback(NULL, NULL);
734 rb->backlight_on();
735 log_text(str,true);
737 if (checksum)
739 rb->snprintf(str, sizeof(str), "CRC32 - %08x", (unsigned)crc32);
740 log_text(str,true);
742 else if (wavinfo.fd < 0)
744 /* Display benchmark information */
745 rb->snprintf(str,sizeof(str),"Decode time - %d.%02ds",(int)ticks/100,(int)ticks%100);
746 log_text(str,true);
748 duration = track.id3.length / 10;
749 rb->snprintf(str,sizeof(str),"File duration - %d.%02ds",(int)duration/100,(int)duration%100);
750 log_text(str,true);
752 if (ticks > 0)
753 speed = duration * 10000 / ticks;
754 else
755 speed = 0;
757 rb->snprintf(str,sizeof(str),"%d.%02d%% realtime",(int)speed/100,(int)speed%100);
758 log_text(str,true);
760 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
761 /* show effective clockrate in MHz needed for realtime decoding */
762 if (speed > 0)
764 speed = CPUFREQ_MAX / speed;
765 rb->snprintf(str,sizeof(str),"%d.%02dMHz needed for realtime",
766 (int)speed/100,(int)speed%100);
767 log_text(str,true);
769 #endif
772 res = PLUGIN_OK;
774 exit:
775 rb->backlight_on();
777 if (fd >= 0)
779 rb->close(fd);
782 return res;
785 /* plugin entry point */
786 enum plugin_status plugin_start(const void* parameter)
788 int result, selection = 0;
789 enum plugin_status res = PLUGIN_OK;
790 int scandir;
791 struct dirent *entry;
792 DIR* dir;
793 char* ch;
794 char dirpath[MAX_PATH];
795 char filename[MAX_PATH];
796 size_t buffer_size;
798 if (parameter == NULL)
800 rb->splash(HZ*2, "No File");
801 return PLUGIN_ERROR;
804 wavbuffer = rb->plugin_get_buffer(&buffer_size);
805 dspbuffer = wavbuffer + buffer_size / 2;
807 codec_mallocbuf = rb->plugin_get_audio_buffer(&audiosize);
808 audiobuf = SKIPBYTES(codec_mallocbuf, CODEC_SIZE);
809 audiosize -= CODEC_SIZE;
811 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
812 rb->cpu_boost(true);
813 #endif
814 rb->lcd_clear_display();
815 rb->lcd_update();
817 enum
819 SPEED_TEST = 0,
820 SPEED_TEST_DIR,
821 WRITE_WAV,
822 SPEED_TEST_WITH_DSP,
823 SPEED_TEST_DIR_WITH_DSP,
824 WRITE_WAV_WITH_DSP,
825 CHECKSUM,
826 CHECKSUM_DIR,
827 QUIT,
830 MENUITEM_STRINGLIST(
831 menu, "test_codec", NULL,
832 "Speed test",
833 "Speed test folder",
834 "Write WAV",
835 "Speed test with DSP",
836 "Speed test folder with DSP",
837 "Write WAV with DSP",
838 "Checksum",
839 "Checksum folder",
840 "Quit",
843 show_menu:
844 rb->lcd_clear_display();
846 result = rb->do_menu(&menu, &selection, NULL, false);
848 if (result == QUIT)
850 res = PLUGIN_OK;
851 goto exit;
854 scandir = 0;
856 if ((checksum = (result == CHECKSUM || result == CHECKSUM_DIR)))
857 result -= 6;
859 if ((use_dsp = ((result >= SPEED_TEST_WITH_DSP)
860 && (result <= WRITE_WAV_WITH_DSP)))) {
861 result -= 3;
863 if (result == SPEED_TEST) {
864 wavinfo.fd = -1;
865 log_init(false);
866 } else if (result == SPEED_TEST_DIR) {
867 wavinfo.fd = -1;
868 scandir = 1;
870 /* Only create a log file when we are testing a folder */
871 if (!log_init(true)) {
872 rb->splash(HZ*2, "Cannot create logfile");
873 res = PLUGIN_ERROR;
874 goto exit;
876 } else if (result == WRITE_WAV) {
877 log_init(false);
878 init_wav("/test.wav");
879 if (wavinfo.fd < 0) {
880 rb->splash(HZ*2, "Cannot create /test.wav");
881 res = PLUGIN_ERROR;
882 goto exit;
884 } else if (result == MENU_ATTACHED_USB) {
885 res = PLUGIN_USB_CONNECTED;
886 goto exit;
887 } else if (result < 0) {
888 res = PLUGIN_OK;
889 goto exit;
892 if (scandir) {
893 /* Test all files in the same directory as the file selected by the
894 user */
896 rb->strlcpy(dirpath,parameter,sizeof(dirpath));
897 ch = rb->strrchr(dirpath,'/');
898 ch[1]=0;
900 DEBUGF("Scanning directory \"%s\"\n",dirpath);
901 dir = rb->opendir(dirpath);
902 if (dir) {
903 entry = rb->readdir(dir);
904 while (entry) {
905 if (!(entry->attribute & ATTR_DIRECTORY)) {
906 rb->snprintf(filename,sizeof(filename),"%s%s",dirpath,entry->d_name);
907 test_track(filename);
908 log_text("", true);
911 /* Read next entry */
912 entry = rb->readdir(dir);
915 rb->closedir(dir);
917 } else {
918 /* Just test the file */
919 res = test_track(parameter);
921 /* Close WAV file (if there was one) */
922 if (wavinfo.fd >= 0) {
923 close_wav();
924 log_text("Wrote /test.wav",true);
926 while (rb->button_get(true) != TESTCODEC_EXITBUTTON);
928 rb->button_clear_queue();
929 goto show_menu;
931 exit:
932 log_close();
934 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
935 rb->cpu_boost(false);
936 #endif
938 return res;