Remove some inconsistent guarding around cpucache_* functions to fix a test_codec...
[kugel-rb.git] / apps / plugins / test_codec.c
blobd581d74f8e26dc47b7bf10a45baa5284e6398014
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"
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 ci.cpucache_invalidate = rb->cpucache_invalidate;
605 ci.cpucache_flush = rb->cpucache_flush;
607 #if NUM_CORES > 1
608 ci.create_thread = rb->create_thread;
609 ci.thread_thaw = rb->thread_thaw;
610 ci.thread_wait = rb->thread_wait;
611 ci.semaphore_init = rb->semaphore_init;
612 ci.semaphore_wait = rb->semaphore_wait;
613 ci.semaphore_release = rb->semaphore_release;
614 #endif
616 #if defined(CPU_ARM) && (CONFIG_PLATFORM & PLATFORM_NATIVE)
617 ci.__div0 = rb->__div0;
618 #endif
621 static void codec_thread(void)
623 const char* codecname;
624 int res;
626 codecname = rb->get_codec_filename(track.id3.codectype);
628 /* Load the codec and start decoding. */
629 res = rb->codec_load_file(codecname,&ci);
631 /* Signal to the main thread that we are done */
632 endtick = *rb->current_tick - rebuffertick;
633 codec_playing = false;
636 static enum plugin_status test_track(const char* filename)
638 size_t n;
639 enum plugin_status res = PLUGIN_ERROR;
640 long starttick;
641 long ticks;
642 unsigned long speed;
643 unsigned long duration;
644 const char* ch;
645 char str[MAX_PATH];
646 offset=0;
648 /* Display filename (excluding any path)*/
649 ch = rb->strrchr(filename, '/');
650 if (ch==NULL)
651 ch = filename;
652 else
653 ch++;
655 rb->snprintf(str,sizeof(str),"%s",ch);
656 log_text(str,true);
658 log_text("Loading...",false);
660 fd = rb->open(filename,O_RDONLY);
661 if (fd < 0)
663 log_text("Cannot open file",true);
664 goto exit;
667 track.filesize = rb->filesize(fd);
669 /* Clear the id3 struct */
670 rb->memset(&track.id3, 0, sizeof(struct mp3entry));
672 if (!rb->get_metadata(&(track.id3), fd, filename))
674 log_text("Cannot read metadata",true);
675 goto exit;
678 if (track.filesize > audiosize)
680 audiobufsize=audiosize;
682 } else
684 audiobufsize=track.filesize;
687 n = rb->read(fd, audiobuf, audiobufsize);
689 if (n != audiobufsize)
691 log_text("Read failed.",true);
692 goto exit;
696 /* Initialise the function pointers in the codec API */
697 init_ci();
699 /* Prepare the codec struct for playing the whole file */
700 ci.filesize = track.filesize;
701 ci.id3 = &track.id3;
702 ci.taginfo_ready = &taginfo_ready;
703 ci.curpos = 0;
704 ci.stop_codec = false;
705 ci.new_track = 0;
706 ci.seek_time = 0;
708 if (use_dsp)
709 rb->dsp_configure(ci.dsp, DSP_RESET, 0);
711 if (checksum)
712 crc32 = 0xffffffff;
714 rebuffertick=0;
715 starttick = *rb->current_tick;
717 codec_playing = true;
719 rb->codec_thread_do_callback(codec_thread, NULL);
721 /* Wait for codec thread to die */
722 while (codec_playing)
724 rb->sleep(HZ);
725 rb->snprintf(str,sizeof(str),"%d of %d",elapsed,(int)track.id3.length);
726 log_text(str,false);
728 ticks = endtick - starttick;
730 /* Be sure it is done */
731 rb->codec_thread_do_callback(NULL, NULL);
732 rb->backlight_on();
733 log_text(str,true);
735 if (checksum)
737 rb->snprintf(str, sizeof(str), "CRC32 - %08x", (unsigned)crc32);
738 log_text(str,true);
740 else if (wavinfo.fd < 0)
742 /* Display benchmark information */
743 rb->snprintf(str,sizeof(str),"Decode time - %d.%02ds",(int)ticks/100,(int)ticks%100);
744 log_text(str,true);
746 duration = track.id3.length / 10;
747 rb->snprintf(str,sizeof(str),"File duration - %d.%02ds",(int)duration/100,(int)duration%100);
748 log_text(str,true);
750 if (ticks > 0)
751 speed = duration * 10000 / ticks;
752 else
753 speed = 0;
755 rb->snprintf(str,sizeof(str),"%d.%02d%% realtime",(int)speed/100,(int)speed%100);
756 log_text(str,true);
758 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
759 /* show effective clockrate in MHz needed for realtime decoding */
760 if (speed > 0)
762 speed = CPUFREQ_MAX / speed;
763 rb->snprintf(str,sizeof(str),"%d.%02dMHz needed for realtime",
764 (int)speed/100,(int)speed%100);
765 log_text(str,true);
767 #endif
770 res = PLUGIN_OK;
772 exit:
773 rb->backlight_on();
775 if (fd >= 0)
777 rb->close(fd);
780 return res;
783 /* plugin entry point */
784 enum plugin_status plugin_start(const void* parameter)
786 int result, selection = 0;
787 enum plugin_status res = PLUGIN_OK;
788 int scandir;
789 struct dirent *entry;
790 DIR* dir;
791 char* ch;
792 char dirpath[MAX_PATH];
793 char filename[MAX_PATH];
794 size_t buffer_size;
796 if (parameter == NULL)
798 rb->splash(HZ*2, "No File");
799 return PLUGIN_ERROR;
802 wavbuffer = rb->plugin_get_buffer(&buffer_size);
803 dspbuffer = wavbuffer + buffer_size / 2;
805 codec_mallocbuf = rb->plugin_get_audio_buffer(&audiosize);
806 audiobuf = SKIPBYTES(codec_mallocbuf, CODEC_SIZE);
807 audiosize -= CODEC_SIZE;
809 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
810 rb->cpu_boost(true);
811 #endif
812 rb->lcd_clear_display();
813 rb->lcd_update();
815 enum
817 SPEED_TEST = 0,
818 SPEED_TEST_DIR,
819 WRITE_WAV,
820 SPEED_TEST_WITH_DSP,
821 SPEED_TEST_DIR_WITH_DSP,
822 WRITE_WAV_WITH_DSP,
823 CHECKSUM,
824 CHECKSUM_DIR,
825 QUIT,
828 MENUITEM_STRINGLIST(
829 menu, "test_codec", NULL,
830 "Speed test",
831 "Speed test folder",
832 "Write WAV",
833 "Speed test with DSP",
834 "Speed test folder with DSP",
835 "Write WAV with DSP",
836 "Checksum",
837 "Checksum folder",
838 "Quit",
841 show_menu:
842 rb->lcd_clear_display();
844 result = rb->do_menu(&menu, &selection, NULL, false);
846 if (result == QUIT)
848 res = PLUGIN_OK;
849 goto exit;
852 scandir = 0;
854 if ((checksum = (result == CHECKSUM || result == CHECKSUM_DIR)))
855 result -= 6;
857 if ((use_dsp = ((result >= SPEED_TEST_WITH_DSP)
858 && (result <= WRITE_WAV_WITH_DSP)))) {
859 result -= 3;
861 if (result == SPEED_TEST) {
862 wavinfo.fd = -1;
863 log_init(false);
864 } else if (result == SPEED_TEST_DIR) {
865 wavinfo.fd = -1;
866 scandir = 1;
868 /* Only create a log file when we are testing a folder */
869 if (!log_init(true)) {
870 rb->splash(HZ*2, "Cannot create logfile");
871 res = PLUGIN_ERROR;
872 goto exit;
874 } else if (result == WRITE_WAV) {
875 log_init(false);
876 init_wav("/test.wav");
877 if (wavinfo.fd < 0) {
878 rb->splash(HZ*2, "Cannot create /test.wav");
879 res = PLUGIN_ERROR;
880 goto exit;
882 } else if (result == MENU_ATTACHED_USB) {
883 res = PLUGIN_USB_CONNECTED;
884 goto exit;
885 } else if (result < 0) {
886 res = PLUGIN_OK;
887 goto exit;
890 if (scandir) {
891 /* Test all files in the same directory as the file selected by the
892 user */
894 rb->strlcpy(dirpath,parameter,sizeof(dirpath));
895 ch = rb->strrchr(dirpath,'/');
896 ch[1]=0;
898 DEBUGF("Scanning directory \"%s\"\n",dirpath);
899 dir = rb->opendir(dirpath);
900 if (dir) {
901 entry = rb->readdir(dir);
902 while (entry) {
903 struct dirinfo info = rb->dir_get_info(dir, entry);
904 if (!(info.attribute & ATTR_DIRECTORY)) {
905 rb->snprintf(filename,sizeof(filename),"%s%s",dirpath,entry->d_name);
906 test_track(filename);
907 log_text("", true);
910 /* Read next entry */
911 entry = rb->readdir(dir);
914 rb->closedir(dir);
916 } else {
917 /* Just test the file */
918 res = test_track(parameter);
920 /* Close WAV file (if there was one) */
921 if (wavinfo.fd >= 0) {
922 close_wav();
923 log_text("Wrote /test.wav",true);
925 while (rb->button_get(true) != TESTCODEC_EXITBUTTON);
927 rb->button_clear_queue();
928 goto show_menu;
930 exit:
931 log_close();
933 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
934 rb->cpu_boost(false);
935 #endif
937 return res;