Merge branch 'master' into android-test-plugins
[kugel-rb.git] / apps / plugins / test_codec.c
blobb925ad7e514c0bd448bfbccb8b0bc6664f5bc825
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 || CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
35 #define TESTCODEC_EXITBUTTON BUTTON_POWER
36 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
37 #define TESTCODEC_EXITBUTTON BUTTON_REC
38 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
39 #define TESTCODEC_EXITBUTTON (BUTTON_REC | BUTTON_PLAY)
40 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
41 #define TESTCODEC_EXITBUTTON (BUTTON_REC | BUTTON_REPEAT)
42 #elif defined(HAVE_TOUCHSCREEN)
43 #define TESTCODEC_EXITBUTTON BUTTON_BOTTOMMIDDLE
44 #else
45 #define TESTCODEC_EXITBUTTON BUTTON_SELECT
46 #endif
48 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
49 static unsigned int boost =1;
51 static const struct opt_items boost_settings[2] = {
52 { "No", -1 },
53 { "Yes", -1 },
56 #endif
58 /* Log functions copied from test_disk.c */
59 static int line = 0;
60 static int max_line = 0;
61 static int log_fd = -1;
63 static void log_close(void)
65 if (log_fd >= 0)
66 rb->close(log_fd);
69 static bool log_init(bool use_logfile)
71 int h;
72 char logfilename[MAX_PATH];
74 rb->lcd_getstringsize("A", NULL, &h);
75 max_line = LCD_HEIGHT / h;
76 line = 0;
77 rb->lcd_clear_display();
78 rb->lcd_update();
80 if (use_logfile) {
81 log_close();
82 #if (CONFIG_PLATFORM & PLATFORM_HOSTED) && !defined(SIMULATOR)
83 rb->create_numbered_filename(logfilename, ROCKBOX_DIR, "test_codec_log_", ".txt",
84 2 IF_CNFN_NUM_(, NULL));
85 #else
86 rb->create_numbered_filename(logfilename, "/", "test_codec_log_", ".txt",
87 2 IF_CNFN_NUM_(, NULL));
88 #endif
89 log_fd = rb->open(logfilename, O_RDWR|O_CREAT|O_TRUNC, 0666);
90 return log_fd >= 0;
93 return true;
96 static void log_text(char *text, bool advance)
98 rb->lcd_puts(0, line, text);
99 rb->lcd_update();
100 if (advance)
102 if (++line >= max_line)
103 line = 0;
104 if (log_fd >= 0)
105 rb->fdprintf(log_fd, "%s\n", text);
109 struct wavinfo_t
111 int fd;
112 int samplerate;
113 int channels;
114 int sampledepth;
115 int stereomode;
116 int totalsamples;
119 static void* audiobuf;
120 static void* codec_mallocbuf;
121 static size_t audiosize;
122 static size_t audiobufsize;
123 static int offset;
124 static int fd;
126 /* Our local implementation of the codec API */
127 static struct codec_api ci;
129 struct test_track_info {
130 struct mp3entry id3; /* TAG metadata */
131 size_t filesize; /* File total length */
134 static struct test_track_info track;
136 static bool use_dsp;
138 static bool checksum;
139 static uint32_t crc32;
141 static volatile unsigned int elapsed;
142 static volatile bool codec_playing;
143 static volatile long endtick;
144 static volatile long rebuffertick;
145 struct wavinfo_t wavinfo;
147 static unsigned char wav_header[44] =
149 'R','I','F','F', // 0 - ChunkID
150 0,0,0,0, // 4 - ChunkSize (filesize-8)
151 'W','A','V','E', // 8 - Format
152 'f','m','t',' ', // 12 - SubChunkID
153 16,0,0,0, // 16 - SubChunk1ID // 16 for PCM
154 1,0, // 20 - AudioFormat (1=16-bit)
155 0,0, // 22 - NumChannels
156 0,0,0,0, // 24 - SampleRate in Hz
157 0,0,0,0, // 28 - Byte Rate (SampleRate*NumChannels*(BitsPerSample/8)
158 0,0, // 32 - BlockAlign (== NumChannels * BitsPerSample/8)
159 16,0, // 34 - BitsPerSample
160 'd','a','t','a', // 36 - Subchunk2ID
161 0,0,0,0 // 40 - Subchunk2Size
164 static inline void int2le32(unsigned char* buf, int32_t x)
166 buf[0] = (x & 0xff);
167 buf[1] = (x & 0xff00) >> 8;
168 buf[2] = (x & 0xff0000) >> 16;
169 buf[3] = (x & 0xff000000) >>24;
172 static inline void int2le24(unsigned char* buf, int32_t x)
174 buf[0] = (x & 0xff);
175 buf[1] = (x & 0xff00) >> 8;
176 buf[2] = (x & 0xff0000) >> 16;
179 static inline void int2le16(unsigned char* buf, int16_t x)
181 buf[0] = (x & 0xff);
182 buf[1] = (x & 0xff00) >> 8;
185 static unsigned char *wavbuffer;
186 static unsigned char *dspbuffer;
188 void init_wav(char* filename)
190 wavinfo.totalsamples = 0;
192 wavinfo.fd = rb->creat(filename, 0666);
194 if (wavinfo.fd >= 0)
196 /* Write WAV header - we go back and fill in the details at the end */
197 rb->write(wavinfo.fd, wav_header, sizeof(wav_header));
202 void close_wav(void)
204 int filesize = rb->filesize(wavinfo.fd);
205 int channels = (wavinfo.stereomode == STEREO_MONO) ? 1 : 2;
206 int bps = 16; /* TODO */
208 /* We assume 16-bit, Stereo */
210 rb->lseek(wavinfo.fd,0,SEEK_SET);
212 int2le32(wav_header+4, filesize-8); /* ChunkSize */
214 int2le16(wav_header+22, channels);
216 int2le32(wav_header+24, wavinfo.samplerate);
218 int2le32(wav_header+28, wavinfo.samplerate * channels * (bps / 8)); /* ByteRate */
220 int2le16(wav_header+32, channels * (bps / 8));
222 int2le32(wav_header+40, filesize - 44); /* Subchunk2Size */
224 rb->write(wavinfo.fd, wav_header, sizeof(wav_header));
226 rb->close(wavinfo.fd);
229 /* Returns buffer to malloc array. Only codeclib should need this. */
230 static void* codec_get_buffer(size_t *size)
232 DEBUGF("codec_get_buffer(%"PRIuPTR")\n",(uintptr_t)size);
233 *size = CODEC_SIZE;
234 return codec_mallocbuf;
237 static int process_dsp(const void *ch1, const void *ch2, int count)
239 const char *src[2] = { ch1, ch2 };
240 int written_count = 0;
241 char *dest = dspbuffer;
243 while (count > 0)
245 int out_count = rb->dsp_output_count(ci.dsp, count);
247 int inp_count = rb->dsp_input_count(ci.dsp, out_count);
249 if (inp_count <= 0)
250 break;
252 if (inp_count > count)
253 inp_count = count;
255 out_count = rb->dsp_process(ci.dsp, dest, src, inp_count);
257 if (out_count <= 0)
258 break;
260 written_count += out_count;
261 dest += out_count * 4;
263 count -= inp_count;
266 return written_count;
269 static inline int32_t clip_sample(int32_t sample)
271 if ((int16_t)sample != sample)
272 sample = 0x7fff ^ (sample >> 31);
274 return sample;
277 /* Null output */
278 static void pcmbuf_insert_null(const void *ch1, const void *ch2, int count)
280 if (use_dsp)
281 process_dsp(ch1, ch2, count);
283 /* Prevent idle poweroff */
284 rb->reset_poweroff_timer();
288 * Helper function used when the file is larger then the available memory.
289 * Rebuffers the file by setting the start of the audio buffer to be
290 * new_offset and filling from there.
292 static int fill_buffer(int new_offset){
293 size_t n, bytestoread;
294 long temp = *rb->current_tick;
295 rb->lseek(fd,new_offset,SEEK_SET);
297 if(new_offset + audiobufsize <= track.filesize)
298 bytestoread = audiobufsize;
299 else
300 bytestoread = track.filesize-new_offset;
302 n = rb->read(fd, audiobuf,bytestoread);
304 if (n != bytestoread)
306 log_text("Read failed.",true);
307 DEBUGF("read fail: got %d bytes, expected %d\n", (int)n, (int)audiobufsize);
308 rb->backlight_on();
310 if (fd >= 0)
312 rb->close(fd);
315 return -1;
317 offset = new_offset;
319 /*keep track of how much time we spent buffering*/
320 rebuffertick += *rb->current_tick-temp;
322 return 0;
325 /* WAV output or calculate crc32 of output*/
326 static void pcmbuf_insert_wav_checksum(const void *ch1, const void *ch2, int count)
328 const int16_t* data1_16;
329 const int16_t* data2_16;
330 const int32_t* data1_32;
331 const int32_t* data2_32;
332 unsigned char* p = wavbuffer;
333 const int scale = wavinfo.sampledepth - 15;
334 const int dc_bias = 1 << (scale - 1);
335 int channels = (wavinfo.stereomode == STEREO_MONO) ? 1 : 2;
337 /* Prevent idle poweroff */
338 rb->reset_poweroff_timer();
340 if (use_dsp) {
341 count = process_dsp(ch1, ch2, count);
342 wavinfo.totalsamples += count;
343 if (channels == 1)
345 unsigned char *s = dspbuffer, *d = dspbuffer;
346 int c = count;
347 while (c-- > 0)
349 *d++ = *s++;
350 *d++ = *s++;
351 s++;
352 s++;
355 if (checksum)
356 crc32 = rb->crc_32(dspbuffer, count * 2 * channels, crc32);
357 else
358 rb->write(wavinfo.fd, dspbuffer, count * 2 * channels);
360 else
362 if (wavinfo.sampledepth <= 16) {
363 data1_16 = ch1;
364 data2_16 = ch2;
366 switch(wavinfo.stereomode)
368 case STEREO_INTERLEAVED:
369 while (count--) {
370 int2le16(p,*data1_16++);
371 p += 2;
372 int2le16(p,*data1_16++);
373 p += 2;
375 break;
377 case STEREO_NONINTERLEAVED:
378 while (count--) {
379 int2le16(p,*data1_16++);
380 p += 2;
381 int2le16(p,*data2_16++);
382 p += 2;
385 break;
387 case STEREO_MONO:
388 while (count--) {
389 int2le16(p,*data1_16++);
390 p += 2;
392 break;
394 } else {
395 data1_32 = ch1;
396 data2_32 = ch2;
398 switch(wavinfo.stereomode)
400 case STEREO_INTERLEAVED:
401 while (count--) {
402 int2le16(p, clip_sample((*data1_32++ + dc_bias) >> scale));
403 p += 2;
404 int2le16(p, clip_sample((*data1_32++ + dc_bias) >> scale));
405 p += 2;
407 break;
409 case STEREO_NONINTERLEAVED:
410 while (count--) {
411 int2le16(p, clip_sample((*data1_32++ + dc_bias) >> scale));
412 p += 2;
413 int2le16(p, clip_sample((*data2_32++ + dc_bias) >> scale));
414 p += 2;
417 break;
419 case STEREO_MONO:
420 while (count--) {
421 int2le16(p, clip_sample((*data1_32++ + dc_bias) >> scale));
422 p += 2;
424 break;
428 wavinfo.totalsamples += count;
429 if (checksum)
430 crc32 = rb->crc_32(wavbuffer, p - wavbuffer, crc32);
431 else
432 rb->write(wavinfo.fd, wavbuffer, p - wavbuffer);
433 } /* else */
436 /* Set song position in WPS (value in ms). */
437 static void set_elapsed(unsigned long value)
439 elapsed = value;
440 ci.id3->elapsed = value;
444 /* Read next <size> amount bytes from file buffer to <ptr>.
445 Will return number of bytes read or 0 if end of file. */
446 static size_t read_filebuf(void *ptr, size_t size)
448 if (ci.curpos > (off_t)track.filesize)
450 return 0;
451 } else {
452 size_t realsize = MIN(track.filesize-ci.curpos,size);
454 /* check if we have enough bytes ready*/
455 if(realsize >(audiobufsize - (ci.curpos-offset)))
457 /*rebuffer so that we start at ci.curpos*/
458 fill_buffer(ci.curpos);
461 rb->memcpy(ptr, audiobuf + (ci.curpos-offset), realsize);
462 ci.curpos += realsize;
463 return realsize;
468 /* Request pointer to file buffer which can be used to read
469 <realsize> amount of data. <reqsize> tells the buffer system
470 how much data it should try to allocate. If <realsize> is 0,
471 end of file is reached. */
472 static void* request_buffer(size_t *realsize, size_t reqsize)
474 *realsize = MIN(track.filesize-ci.curpos,reqsize);
476 /*check if we have enough bytes ready - requested > bufsize-currentbufpos*/
477 if(*realsize>(audiobufsize - (ci.curpos-offset)))
479 /*rebuffer so that we start at ci.curpos*/
480 fill_buffer(ci.curpos);
483 return (audiobuf + (ci.curpos-offset));
486 /* Advance file buffer position by <amount> amount of bytes. */
487 static void advance_buffer(size_t amount)
489 ci.curpos += amount;
490 ci.id3->offset = ci.curpos;
494 /* Seek file buffer to position <newpos> beginning of file. */
495 static bool seek_buffer(size_t newpos)
497 ci.curpos = newpos;
498 return true;
502 /* Codec should call this function when it has done the seeking. */
503 static void seek_complete(void)
505 /* Do nothing */
508 /* Codec calls this to know what it should do next. */
509 static enum codec_command_action get_command(intptr_t *param)
511 rb->yield();
512 return CODEC_ACTION_NULL; /* just continue processing */
513 (void)param;
516 static void set_offset(size_t value)
518 ci.id3->offset = value;
522 /* Configure different codec buffer parameters. */
523 static void configure(int setting, intptr_t value)
525 if (use_dsp)
526 rb->dsp_configure(ci.dsp, setting, value);
527 switch(setting)
529 case DSP_SWITCH_FREQUENCY:
530 case DSP_SET_FREQUENCY:
531 DEBUGF("samplerate=%d\n",(int)value);
532 wavinfo.samplerate = (int)value;
533 break;
535 case DSP_SET_SAMPLE_DEPTH:
536 DEBUGF("sampledepth = %d\n",(int)value);
537 wavinfo.sampledepth=(int)value;
538 break;
540 case DSP_SET_STEREO_MODE:
541 DEBUGF("Stereo mode = %d\n",(int)value);
542 wavinfo.stereomode=(int)value;
543 break;
548 static void init_ci(void)
550 /* --- Our "fake" implementations of the codec API functions. --- */
552 ci.dsp = (struct dsp_config *)rb->dsp_configure(NULL, DSP_MYDSP,
553 CODEC_IDX_AUDIO);
555 ci.codec_get_buffer = codec_get_buffer;
557 if (wavinfo.fd >= 0 || checksum) {
558 ci.pcmbuf_insert = pcmbuf_insert_wav_checksum;
559 } else {
560 ci.pcmbuf_insert = pcmbuf_insert_null;
563 ci.set_elapsed = set_elapsed;
564 ci.read_filebuf = read_filebuf;
565 ci.request_buffer = request_buffer;
566 ci.advance_buffer = advance_buffer;
567 ci.seek_buffer = seek_buffer;
568 ci.seek_complete = seek_complete;
569 ci.set_offset = set_offset;
570 ci.configure = configure;
571 ci.get_command = get_command;
573 /* --- "Core" functions --- */
575 /* kernel/ system */
576 ci.sleep = rb->sleep;
577 ci.yield = rb->yield;
579 /* strings and memory */
580 ci.strcpy = rb->strcpy;
581 ci.strlen = rb->strlen;
582 ci.strcmp = rb->strcmp;
583 ci.strcat = rb->strcat;
584 ci.memset = rb->memset;
585 ci.memcpy = rb->memcpy;
586 ci.memmove = rb->memmove;
587 ci.memcmp = rb->memcmp;
588 ci.memchr = rb->memchr;
589 ci.strcasestr = rb->strcasestr;
590 #if defined(DEBUG) || defined(SIMULATOR)
591 ci.debugf = rb->debugf;
592 #endif
593 #ifdef ROCKBOX_HAS_LOGF
594 ci.logf = rb->logf;
595 #endif
597 ci.qsort = rb->qsort;
598 ci.global_settings = rb->global_settings;
600 #ifdef RB_PROFILE
601 ci.profile_thread = rb->profile_thread;
602 ci.profstop = rb->profstop;
603 ci.profile_func_enter = rb->profile_func_enter;
604 ci.profile_func_exit = rb->profile_func_exit;
605 #endif
607 ci.cpucache_invalidate = rb->cpucache_invalidate;
608 ci.cpucache_flush = rb->cpucache_flush;
610 #if NUM_CORES > 1
611 ci.create_thread = rb->create_thread;
612 ci.thread_thaw = rb->thread_thaw;
613 ci.thread_wait = rb->thread_wait;
614 ci.semaphore_init = rb->semaphore_init;
615 ci.semaphore_wait = rb->semaphore_wait;
616 ci.semaphore_release = rb->semaphore_release;
617 #endif
619 #if defined(CPU_ARM) && (CONFIG_PLATFORM & PLATFORM_NATIVE)
620 ci.__div0 = rb->__div0;
621 #endif
624 static void codec_thread(void)
626 const char* codecname;
627 int res;
629 codecname = rb->get_codec_filename(track.id3.codectype);
631 /* Load the codec */
632 res = rb->codec_load_file(codecname, &ci);
634 if (res >= 0)
636 /* Decode the file */
637 res = rb->codec_run_proc();
640 /* Clean up */
641 rb->codec_close();
643 /* Signal to the main thread that we are done */
644 endtick = *rb->current_tick - rebuffertick;
645 codec_playing = false;
648 static enum plugin_status test_track(const char* filename)
650 size_t n;
651 enum plugin_status res = PLUGIN_ERROR;
652 long starttick;
653 long ticks;
654 unsigned long speed;
655 unsigned long duration;
656 const char* ch;
657 char str[MAX_PATH];
658 offset=0;
660 /* Display filename (excluding any path)*/
661 ch = rb->strrchr(filename, '/');
662 if (ch==NULL)
663 ch = filename;
664 else
665 ch++;
667 rb->snprintf(str,sizeof(str),"%s",ch);
668 log_text(str,true);
670 log_text("Loading...",false);
672 fd = rb->open(filename,O_RDONLY);
673 if (fd < 0)
675 log_text("Cannot open file",true);
676 goto exit;
679 track.filesize = rb->filesize(fd);
681 /* Clear the id3 struct */
682 rb->memset(&track.id3, 0, sizeof(struct mp3entry));
684 if (!rb->get_metadata(&(track.id3), fd, filename))
686 log_text("Cannot read metadata",true);
687 goto exit;
690 if (track.filesize > audiosize)
692 audiobufsize=audiosize;
694 } else
696 audiobufsize=track.filesize;
699 n = rb->read(fd, audiobuf, audiobufsize);
701 if (n != audiobufsize)
703 log_text("Read failed.",true);
704 goto exit;
708 /* Initialise the function pointers in the codec API */
709 init_ci();
711 /* Prepare the codec struct for playing the whole file */
712 ci.filesize = track.filesize;
713 ci.id3 = &track.id3;
714 ci.curpos = 0;
716 if (use_dsp)
717 rb->dsp_configure(ci.dsp, DSP_RESET, 0);
719 if (checksum)
720 crc32 = 0xffffffff;
722 rebuffertick=0;
723 starttick = *rb->current_tick;
725 codec_playing = true;
727 rb->codec_thread_do_callback(codec_thread, NULL);
729 /* Wait for codec thread to die */
730 while (codec_playing)
732 rb->sleep(HZ);
733 rb->snprintf(str,sizeof(str),"%d of %d",elapsed,(int)track.id3.length);
734 log_text(str,false);
736 ticks = endtick - starttick;
738 /* Be sure it is done */
739 rb->codec_thread_do_callback(NULL, NULL);
740 rb->backlight_on();
741 log_text(str,true);
743 if (checksum)
745 rb->snprintf(str, sizeof(str), "CRC32 - %08x", (unsigned)crc32);
746 log_text(str,true);
748 else if (wavinfo.fd < 0)
750 /* Display benchmark information */
751 rb->snprintf(str,sizeof(str),"Decode time - %d.%02ds",(int)ticks/100,(int)ticks%100);
752 log_text(str,true);
754 duration = track.id3.length / 10;
755 rb->snprintf(str,sizeof(str),"File duration - %d.%02ds",(int)duration/100,(int)duration%100);
756 log_text(str,true);
758 if (ticks > 0)
759 speed = duration * 10000 / ticks;
760 else
761 speed = 0;
763 rb->snprintf(str,sizeof(str),"%d.%02d%% realtime",(int)speed/100,(int)speed%100);
764 log_text(str,true);
766 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
767 /* show effective clockrate in MHz needed for realtime decoding */
768 if (speed > 0)
770 int freq = CPUFREQ_MAX;
772 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
773 if(!boost)
774 freq = CPUFREQ_NORMAL;
775 #endif
777 speed = freq / speed;
778 rb->snprintf(str,sizeof(str),"%d.%02dMHz needed for realtime",
779 (int)speed/100,(int)speed%100);
780 log_text(str,true);
782 #endif
785 res = PLUGIN_OK;
787 exit:
788 rb->backlight_on();
790 if (fd >= 0)
792 rb->close(fd);
795 return res;
798 #ifdef HAVE_TOUCHSCREEN
799 void cleanup(void)
801 rb->screens[0]->set_viewport(NULL);
803 #endif
805 void plugin_quit(void)
807 #ifdef HAVE_TOUCHSCREEN
808 struct viewport vp;
809 struct screen *lcd = rb->screens[SCREEN_MAIN];
810 rb->viewport_set_defaults(&vp, SCREEN_MAIN);
811 int font_height = rb->font_get(vp.font)->height;
812 int yoff;
814 vp.x = 10;
815 vp.width = lcd->lcdwidth - 20;
816 vp.y = lcd->lcdheight - 60;
817 vp.height = 50;
818 vp.flags = VP_FLAG_ALIGN_CENTER;
820 yoff = vp.height/2 - font_height/2;
821 lcd->set_viewport(&vp);
822 atexit(cleanup);
823 lcd->clear_viewport();
824 lcd->set_foreground(LCD_WHITE);
825 lcd->putsxy(0, yoff, "OK");
826 lcd->drawrect(vp.x, vp.y, vp.width, vp.height);
827 lcd->update_viewport();
828 short x,y;
829 if (rb->touchscreen_get_mode() == TOUCHSCREEN_POINT)
831 while(1)
833 rb->get_action(CONTEXT_STD, TIMEOUT_BLOCK);
834 if (rb->action_get_touchscreen_press_in_vp(&x, &y, &vp) & BUTTON_REL)
835 break;
838 else
839 #endif
840 while (rb->button_get(true) != TESTCODEC_EXITBUTTON);
843 /* plugin entry point */
844 enum plugin_status plugin_start(const void* parameter)
846 int result, selection = 0;
847 enum plugin_status res = PLUGIN_OK;
848 int scandir;
849 struct dirent *entry;
850 DIR* dir;
851 char* ch;
852 char dirpath[MAX_PATH];
853 char filename[MAX_PATH];
854 size_t buffer_size;
856 if (parameter == NULL)
858 rb->splash(HZ*2, "No File");
859 return PLUGIN_ERROR;
862 wavbuffer = rb->plugin_get_buffer(&buffer_size);
863 dspbuffer = wavbuffer + buffer_size / 2;
865 codec_mallocbuf = rb->plugin_get_audio_buffer(&audiosize);
866 /* Align codec_mallocbuf to pointer size, tlsf wants that */
867 codec_mallocbuf = (void*)(((intptr_t)codec_mallocbuf +
868 sizeof(intptr_t)-1) & ~(sizeof(intptr_t)-1));
869 audiobuf = SKIPBYTES(codec_mallocbuf, CODEC_SIZE);
870 audiosize -= CODEC_SIZE;
872 rb->lcd_clear_display();
873 rb->lcd_update();
875 enum
877 SPEED_TEST = 0,
878 SPEED_TEST_DIR,
879 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
880 BOOST,
881 #endif
882 WRITE_WAV,
883 SPEED_TEST_WITH_DSP,
884 SPEED_TEST_DIR_WITH_DSP,
885 WRITE_WAV_WITH_DSP,
886 CHECKSUM,
887 CHECKSUM_DIR,
888 QUIT,
891 MENUITEM_STRINGLIST(
892 menu, "test_codec", NULL,
893 "Speed test",
894 "Speed test folder",
895 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
896 "Boosting",
897 #endif
898 "Write WAV",
899 "Speed test with DSP",
900 "Speed test folder with DSP",
901 "Write WAV with DSP",
902 "Checksum",
903 "Checksum folder",
904 "Quit",
908 show_menu:
909 rb->lcd_clear_display();
911 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
912 menu:
913 #endif
915 result = rb->do_menu(&menu, &selection, NULL, false);
916 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
918 if (result == BOOST)
920 rb->set_option("Boosting", &boost, INT,
921 boost_settings, 2, NULL);
922 goto menu;
924 if(boost)
925 rb->cpu_boost(true);
926 #endif
928 if (result == QUIT)
930 res = PLUGIN_OK;
931 goto exit;
934 scandir = 0;
936 if ((checksum = (result == CHECKSUM || result == CHECKSUM_DIR)))
937 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
938 result -= 7;
939 #else
940 result -= 6;
941 #endif
943 if ((use_dsp = ((result >= SPEED_TEST_WITH_DSP)
944 && (result <= WRITE_WAV_WITH_DSP)))) {
945 result -= 3;
947 if (result == SPEED_TEST) {
948 wavinfo.fd = -1;
949 log_init(false);
950 } else if (result == SPEED_TEST_DIR) {
951 wavinfo.fd = -1;
952 scandir = 1;
954 /* Only create a log file when we are testing a folder */
955 if (!log_init(true)) {
956 rb->splash(HZ*2, "Cannot create logfile");
957 res = PLUGIN_ERROR;
958 goto exit;
960 } else if (result == WRITE_WAV) {
961 log_init(false);
962 init_wav("/test.wav");
963 if (wavinfo.fd < 0) {
964 rb->splash(HZ*2, "Cannot create /test.wav");
965 res = PLUGIN_ERROR;
966 goto exit;
968 } else if (result == MENU_ATTACHED_USB) {
969 res = PLUGIN_USB_CONNECTED;
970 goto exit;
971 } else if (result < 0) {
972 res = PLUGIN_OK;
973 goto exit;
976 if (scandir) {
977 /* Test all files in the same directory as the file selected by the
978 user */
980 rb->strlcpy(dirpath,parameter,sizeof(dirpath));
981 ch = rb->strrchr(dirpath,'/');
982 ch[1]=0;
984 DEBUGF("Scanning directory \"%s\"\n",dirpath);
985 dir = rb->opendir(dirpath);
986 if (dir) {
987 entry = rb->readdir(dir);
988 while (entry) {
989 struct dirinfo info = rb->dir_get_info(dir, entry);
990 if (!(info.attribute & ATTR_DIRECTORY)) {
991 rb->snprintf(filename,sizeof(filename),"%s%s",dirpath,entry->d_name);
992 test_track(filename);
993 log_text("", true);
996 /* Read next entry */
997 entry = rb->readdir(dir);
1000 rb->closedir(dir);
1002 } else {
1003 /* Just test the file */
1004 res = test_track(parameter);
1006 /* Close WAV file (if there was one) */
1007 if (wavinfo.fd >= 0) {
1008 close_wav();
1009 log_text("Wrote /test.wav",true);
1011 plugin_quit();
1014 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
1015 if(boost)
1016 rb->cpu_boost(false);
1017 #endif
1019 rb->button_clear_queue();
1020 goto show_menu;
1022 exit:
1023 log_close();
1025 return res;