Remove get_user_file_path for plugins
[kugel-rb.git] / apps / plugins / test_codec.c
blob3d0745fe17f51ddfbb3590ed6fb81e4ca1e84ab8
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;
135 static bool taginfo_ready = true;
137 static bool use_dsp;
139 static bool checksum;
140 static uint32_t crc32;
142 static volatile unsigned int elapsed;
143 static volatile bool codec_playing;
144 static volatile long endtick;
145 static volatile long rebuffertick;
146 struct wavinfo_t wavinfo;
148 static unsigned char wav_header[44] =
150 'R','I','F','F', // 0 - ChunkID
151 0,0,0,0, // 4 - ChunkSize (filesize-8)
152 'W','A','V','E', // 8 - Format
153 'f','m','t',' ', // 12 - SubChunkID
154 16,0,0,0, // 16 - SubChunk1ID // 16 for PCM
155 1,0, // 20 - AudioFormat (1=16-bit)
156 0,0, // 22 - NumChannels
157 0,0,0,0, // 24 - SampleRate in Hz
158 0,0,0,0, // 28 - Byte Rate (SampleRate*NumChannels*(BitsPerSample/8)
159 0,0, // 32 - BlockAlign (== NumChannels * BitsPerSample/8)
160 16,0, // 34 - BitsPerSample
161 'd','a','t','a', // 36 - Subchunk2ID
162 0,0,0,0 // 40 - Subchunk2Size
165 static inline void int2le32(unsigned char* buf, int32_t x)
167 buf[0] = (x & 0xff);
168 buf[1] = (x & 0xff00) >> 8;
169 buf[2] = (x & 0xff0000) >> 16;
170 buf[3] = (x & 0xff000000) >>24;
173 static inline void int2le24(unsigned char* buf, int32_t x)
175 buf[0] = (x & 0xff);
176 buf[1] = (x & 0xff00) >> 8;
177 buf[2] = (x & 0xff0000) >> 16;
180 static inline void int2le16(unsigned char* buf, int16_t x)
182 buf[0] = (x & 0xff);
183 buf[1] = (x & 0xff00) >> 8;
186 static unsigned char *wavbuffer;
187 static unsigned char *dspbuffer;
189 void init_wav(char* filename)
191 wavinfo.totalsamples = 0;
193 wavinfo.fd = rb->creat(filename, 0666);
195 if (wavinfo.fd >= 0)
197 /* Write WAV header - we go back and fill in the details at the end */
198 rb->write(wavinfo.fd, wav_header, sizeof(wav_header));
203 void close_wav(void)
205 int filesize = rb->filesize(wavinfo.fd);
206 int channels = (wavinfo.stereomode == STEREO_MONO) ? 1 : 2;
207 int bps = 16; /* TODO */
209 /* We assume 16-bit, Stereo */
211 rb->lseek(wavinfo.fd,0,SEEK_SET);
213 int2le32(wav_header+4, filesize-8); /* ChunkSize */
215 int2le16(wav_header+22, channels);
217 int2le32(wav_header+24, wavinfo.samplerate);
219 int2le32(wav_header+28, wavinfo.samplerate * channels * (bps / 8)); /* ByteRate */
221 int2le16(wav_header+32, channels * (bps / 8));
223 int2le32(wav_header+40, filesize - 44); /* Subchunk2Size */
225 rb->write(wavinfo.fd, wav_header, sizeof(wav_header));
227 rb->close(wavinfo.fd);
230 /* Returns buffer to malloc array. Only codeclib should need this. */
231 static void* codec_get_buffer(size_t *size)
233 DEBUGF("codec_get_buffer(%"PRIuPTR")\n",(uintptr_t)size);
234 *size = CODEC_SIZE;
235 return codec_mallocbuf;
238 static int process_dsp(const void *ch1, const void *ch2, int count)
240 const char *src[2] = { ch1, ch2 };
241 int written_count = 0;
242 char *dest = dspbuffer;
244 while (count > 0)
246 int out_count = rb->dsp_output_count(ci.dsp, count);
248 int inp_count = rb->dsp_input_count(ci.dsp, out_count);
250 if (inp_count <= 0)
251 break;
253 if (inp_count > count)
254 inp_count = count;
256 out_count = rb->dsp_process(ci.dsp, dest, src, inp_count);
258 if (out_count <= 0)
259 break;
261 written_count += out_count;
262 dest += out_count * 4;
264 count -= inp_count;
267 return written_count;
270 static inline int32_t clip_sample(int32_t sample)
272 if ((int16_t)sample != sample)
273 sample = 0x7fff ^ (sample >> 31);
275 return sample;
278 /* Null output */
279 static void pcmbuf_insert_null(const void *ch1, const void *ch2, int count)
281 if (use_dsp)
282 process_dsp(ch1, ch2, count);
284 /* Prevent idle poweroff */
285 rb->reset_poweroff_timer();
289 * Helper function used when the file is larger then the available memory.
290 * Rebuffers the file by setting the start of the audio buffer to be
291 * new_offset and filling from there.
293 static int fill_buffer(int new_offset){
294 size_t n, bytestoread;
295 long temp = *rb->current_tick;
296 rb->lseek(fd,new_offset,SEEK_SET);
298 if(new_offset + audiobufsize <= track.filesize)
299 bytestoread = audiobufsize;
300 else
301 bytestoread = track.filesize-new_offset;
303 n = rb->read(fd, audiobuf,bytestoread);
305 if (n != bytestoread)
307 log_text("Read failed.",true);
308 DEBUGF("read fail: got %d bytes, expected %d\n", (int)n, (int)audiobufsize);
309 rb->backlight_on();
311 if (fd >= 0)
313 rb->close(fd);
316 return -1;
318 offset = new_offset;
320 /*keep track of how much time we spent buffering*/
321 rebuffertick += *rb->current_tick-temp;
323 return 0;
326 /* WAV output or calculate crc32 of output*/
327 static void pcmbuf_insert_wav_checksum(const void *ch1, const void *ch2, int count)
329 const int16_t* data1_16;
330 const int16_t* data2_16;
331 const int32_t* data1_32;
332 const int32_t* data2_32;
333 unsigned char* p = wavbuffer;
334 const int scale = wavinfo.sampledepth - 15;
335 const int dc_bias = 1 << (scale - 1);
336 int channels = (wavinfo.stereomode == STEREO_MONO) ? 1 : 2;
338 /* Prevent idle poweroff */
339 rb->reset_poweroff_timer();
341 if (use_dsp) {
342 count = process_dsp(ch1, ch2, count);
343 wavinfo.totalsamples += count;
344 if (channels == 1)
346 unsigned char *s = dspbuffer, *d = dspbuffer;
347 int c = count;
348 while (c-- > 0)
350 *d++ = *s++;
351 *d++ = *s++;
352 s++;
353 s++;
356 if (checksum)
357 crc32 = rb->crc_32(dspbuffer, count * 2 * channels, crc32);
358 else
359 rb->write(wavinfo.fd, dspbuffer, count * 2 * channels);
361 else
363 if (wavinfo.sampledepth <= 16) {
364 data1_16 = ch1;
365 data2_16 = ch2;
367 switch(wavinfo.stereomode)
369 case STEREO_INTERLEAVED:
370 while (count--) {
371 int2le16(p,*data1_16++);
372 p += 2;
373 int2le16(p,*data1_16++);
374 p += 2;
376 break;
378 case STEREO_NONINTERLEAVED:
379 while (count--) {
380 int2le16(p,*data1_16++);
381 p += 2;
382 int2le16(p,*data2_16++);
383 p += 2;
386 break;
388 case STEREO_MONO:
389 while (count--) {
390 int2le16(p,*data1_16++);
391 p += 2;
393 break;
395 } else {
396 data1_32 = ch1;
397 data2_32 = ch2;
399 switch(wavinfo.stereomode)
401 case STEREO_INTERLEAVED:
402 while (count--) {
403 int2le16(p, clip_sample((*data1_32++ + dc_bias) >> scale));
404 p += 2;
405 int2le16(p, clip_sample((*data1_32++ + dc_bias) >> scale));
406 p += 2;
408 break;
410 case STEREO_NONINTERLEAVED:
411 while (count--) {
412 int2le16(p, clip_sample((*data1_32++ + dc_bias) >> scale));
413 p += 2;
414 int2le16(p, clip_sample((*data2_32++ + dc_bias) >> scale));
415 p += 2;
418 break;
420 case STEREO_MONO:
421 while (count--) {
422 int2le16(p, clip_sample((*data1_32++ + dc_bias) >> scale));
423 p += 2;
425 break;
429 wavinfo.totalsamples += count;
430 if (checksum)
431 crc32 = rb->crc_32(wavbuffer, p - wavbuffer, crc32);
432 else
433 rb->write(wavinfo.fd, wavbuffer, p - wavbuffer);
434 } /* else */
437 /* Set song position in WPS (value in ms). */
438 static void set_elapsed(unsigned long value)
440 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;
493 /* Advance file buffer to a pointer location inside file buffer. */
494 static void advance_buffer_loc(void *ptr)
496 ci.curpos = ptr - (audiobuf - offset);
500 /* Seek file buffer to position <newpos> beginning of file. */
501 static bool seek_buffer(size_t newpos)
503 ci.curpos = newpos;
504 return true;
508 /* Codec should call this function when it has done the seeking. */
509 static void seek_complete(void)
511 /* Do nothing */
514 /* Request file change from file buffer. Returns true is next
515 track is available and changed. If return value is false,
516 codec should exit immediately with PLUGIN_OK status. */
517 static bool request_next_track(void)
519 /* We are only decoding a single track */
520 return false;
524 /* Free the buffer area of the current codec after its loaded */
525 static void discard_codec(void)
527 /* ??? */
531 static void set_offset(size_t value)
533 /* ??? */
534 (void)value;
538 /* Configure different codec buffer parameters. */
539 static void configure(int setting, intptr_t value)
541 if (use_dsp)
542 rb->dsp_configure(ci.dsp, setting, value);
543 switch(setting)
545 case DSP_SWITCH_FREQUENCY:
546 case DSP_SET_FREQUENCY:
547 DEBUGF("samplerate=%d\n",(int)value);
548 wavinfo.samplerate = (int)value;
549 break;
551 case DSP_SET_SAMPLE_DEPTH:
552 DEBUGF("sampledepth = %d\n",(int)value);
553 wavinfo.sampledepth=(int)value;
554 break;
556 case DSP_SET_STEREO_MODE:
557 DEBUGF("Stereo mode = %d\n",(int)value);
558 wavinfo.stereomode=(int)value;
559 break;
564 static void init_ci(void)
566 /* --- Our "fake" implementations of the codec API functions. --- */
568 ci.codec_get_buffer = codec_get_buffer;
570 if (wavinfo.fd >= 0 || checksum) {
571 ci.pcmbuf_insert = pcmbuf_insert_wav_checksum;
572 } else {
573 ci.pcmbuf_insert = pcmbuf_insert_null;
576 ci.set_elapsed = set_elapsed;
577 ci.read_filebuf = read_filebuf;
578 ci.request_buffer = request_buffer;
579 ci.advance_buffer = advance_buffer;
580 ci.advance_buffer_loc = advance_buffer_loc;
581 ci.seek_buffer = seek_buffer;
582 ci.seek_complete = seek_complete;
583 ci.request_next_track = request_next_track;
584 ci.discard_codec = discard_codec;
585 ci.set_offset = set_offset;
586 ci.configure = configure;
587 ci.dsp = (struct dsp_config *)rb->dsp_configure(NULL, DSP_MYDSP,
588 CODEC_IDX_AUDIO);
590 /* --- "Core" functions --- */
592 /* kernel/ system */
593 ci.sleep = rb->sleep;
594 ci.yield = rb->yield;
596 /* strings and memory */
597 ci.strcpy = rb->strcpy;
598 ci.strlen = rb->strlen;
599 ci.strcmp = rb->strcmp;
600 ci.strcat = rb->strcat;
601 ci.memset = rb->memset;
602 ci.memcpy = rb->memcpy;
603 ci.memmove = rb->memmove;
604 ci.memcmp = rb->memcmp;
605 ci.memchr = rb->memchr;
606 ci.strcasestr = rb->strcasestr;
607 #if defined(DEBUG) || defined(SIMULATOR)
608 ci.debugf = rb->debugf;
609 #endif
610 #ifdef ROCKBOX_HAS_LOGF
611 ci.logf = rb->logf;
612 #endif
614 ci.qsort = rb->qsort;
615 ci.global_settings = rb->global_settings;
617 #ifdef RB_PROFILE
618 ci.profile_thread = rb->profile_thread;
619 ci.profstop = rb->profstop;
620 ci.profile_func_enter = rb->profile_func_enter;
621 ci.profile_func_exit = rb->profile_func_exit;
622 #endif
624 ci.cpucache_invalidate = rb->cpucache_invalidate;
625 ci.cpucache_flush = rb->cpucache_flush;
627 #if NUM_CORES > 1
628 ci.create_thread = rb->create_thread;
629 ci.thread_thaw = rb->thread_thaw;
630 ci.thread_wait = rb->thread_wait;
631 ci.semaphore_init = rb->semaphore_init;
632 ci.semaphore_wait = rb->semaphore_wait;
633 ci.semaphore_release = rb->semaphore_release;
634 #endif
636 #if defined(CPU_ARM) && (CONFIG_PLATFORM & PLATFORM_NATIVE)
637 ci.__div0 = rb->__div0;
638 #endif
641 static void codec_thread(void)
643 const char* codecname;
644 int res;
646 codecname = rb->get_codec_filename(track.id3.codectype);
648 /* Load the codec and start decoding. */
649 res = rb->codec_load_file(codecname,&ci);
651 /* Signal to the main thread that we are done */
652 endtick = *rb->current_tick - rebuffertick;
653 codec_playing = false;
656 static enum plugin_status test_track(const char* filename)
658 size_t n;
659 enum plugin_status res = PLUGIN_ERROR;
660 long starttick;
661 long ticks;
662 unsigned long speed;
663 unsigned long duration;
664 const char* ch;
665 char str[MAX_PATH];
666 offset=0;
668 /* Display filename (excluding any path)*/
669 ch = rb->strrchr(filename, '/');
670 if (ch==NULL)
671 ch = filename;
672 else
673 ch++;
675 rb->snprintf(str,sizeof(str),"%s",ch);
676 log_text(str,true);
678 log_text("Loading...",false);
680 fd = rb->open(filename,O_RDONLY);
681 if (fd < 0)
683 log_text("Cannot open file",true);
684 goto exit;
687 track.filesize = rb->filesize(fd);
689 /* Clear the id3 struct */
690 rb->memset(&track.id3, 0, sizeof(struct mp3entry));
692 if (!rb->get_metadata(&(track.id3), fd, filename))
694 log_text("Cannot read metadata",true);
695 goto exit;
698 if (track.filesize > audiosize)
700 audiobufsize=audiosize;
702 } else
704 audiobufsize=track.filesize;
707 n = rb->read(fd, audiobuf, audiobufsize);
709 if (n != audiobufsize)
711 log_text("Read failed.",true);
712 goto exit;
716 /* Initialise the function pointers in the codec API */
717 init_ci();
719 /* Prepare the codec struct for playing the whole file */
720 ci.filesize = track.filesize;
721 ci.id3 = &track.id3;
722 ci.taginfo_ready = &taginfo_ready;
723 ci.curpos = 0;
724 ci.stop_codec = false;
725 ci.new_track = 0;
726 ci.seek_time = 0;
728 if (use_dsp)
729 rb->dsp_configure(ci.dsp, DSP_RESET, 0);
731 if (checksum)
732 crc32 = 0xffffffff;
734 rebuffertick=0;
735 starttick = *rb->current_tick;
737 codec_playing = true;
739 rb->codec_thread_do_callback(codec_thread, NULL);
741 /* Wait for codec thread to die */
742 while (codec_playing)
744 rb->sleep(HZ);
745 rb->snprintf(str,sizeof(str),"%d of %d",elapsed,(int)track.id3.length);
746 log_text(str,false);
748 ticks = endtick - starttick;
750 /* Be sure it is done */
751 rb->codec_thread_do_callback(NULL, NULL);
752 rb->backlight_on();
753 log_text(str,true);
755 if (checksum)
757 rb->snprintf(str, sizeof(str), "CRC32 - %08x", (unsigned)crc32);
758 log_text(str,true);
760 else if (wavinfo.fd < 0)
762 /* Display benchmark information */
763 rb->snprintf(str,sizeof(str),"Decode time - %d.%02ds",(int)ticks/100,(int)ticks%100);
764 log_text(str,true);
766 duration = track.id3.length / 10;
767 rb->snprintf(str,sizeof(str),"File duration - %d.%02ds",(int)duration/100,(int)duration%100);
768 log_text(str,true);
770 if (ticks > 0)
771 speed = duration * 10000 / ticks;
772 else
773 speed = 0;
775 rb->snprintf(str,sizeof(str),"%d.%02d%% realtime",(int)speed/100,(int)speed%100);
776 log_text(str,true);
778 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
779 /* show effective clockrate in MHz needed for realtime decoding */
780 if (speed > 0)
782 int freq = CPUFREQ_MAX;
784 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
785 if(!boost)
786 freq = CPUFREQ_NORMAL;
787 #endif
789 speed = freq / speed;
790 rb->snprintf(str,sizeof(str),"%d.%02dMHz needed for realtime",
791 (int)speed/100,(int)speed%100);
792 log_text(str,true);
794 #endif
797 res = PLUGIN_OK;
799 exit:
800 rb->backlight_on();
802 if (fd >= 0)
804 rb->close(fd);
807 return res;
810 #ifdef HAVE_TOUCHSCREEN
811 void cleanup(void)
813 rb->screens[0]->set_viewport(NULL);
815 #endif
817 void plugin_quit(void)
819 #ifdef HAVE_TOUCHSCREEN
820 struct viewport vp;
821 struct screen *lcd = rb->screens[SCREEN_MAIN];
822 rb->viewport_set_defaults(&vp, SCREEN_MAIN);
823 int font_height = rb->font_get(vp.font)->height;
824 int yoff;
826 vp.x = 10;
827 vp.width = lcd->lcdwidth - 20;
828 vp.y = lcd->lcdheight - 60;
829 vp.height = 50;
830 vp.flags = VP_FLAG_ALIGN_CENTER;
832 yoff = vp.height/2 - font_height/2;
833 lcd->set_viewport(&vp);
834 atexit(cleanup);
835 lcd->clear_viewport();
836 lcd->set_foreground(LCD_WHITE);
837 lcd->putsxy(0, yoff, "OK");
838 lcd->drawrect(vp.x, vp.y, vp.width, vp.height);
839 lcd->update_viewport();
840 short x,y;
841 if (rb->touchscreen_get_mode() == TOUCHSCREEN_POINT)
843 while(1)
845 rb->get_action(CONTEXT_STD, TIMEOUT_BLOCK);
846 if (rb->action_get_touchscreen_press_in_vp(&x, &y, &vp) & BUTTON_REL)
847 break;
850 else
851 #endif
852 while (rb->button_get(true) != TESTCODEC_EXITBUTTON);
855 /* plugin entry point */
856 enum plugin_status plugin_start(const void* parameter)
858 int result, selection = 0;
859 enum plugin_status res = PLUGIN_OK;
860 int scandir;
861 struct dirent *entry;
862 DIR* dir;
863 char* ch;
864 char dirpath[MAX_PATH];
865 char filename[MAX_PATH];
866 size_t buffer_size;
868 if (parameter == NULL)
870 rb->splash(HZ*2, "No File");
871 return PLUGIN_ERROR;
874 wavbuffer = rb->plugin_get_buffer(&buffer_size);
875 dspbuffer = wavbuffer + buffer_size / 2;
877 codec_mallocbuf = rb->plugin_get_audio_buffer(&audiosize);
878 /* Align codec_mallocbuf to pointer size, tlsf wants that */
879 codec_mallocbuf = (void*)(((intptr_t)codec_mallocbuf +
880 sizeof(intptr_t)-1) & ~(sizeof(intptr_t)-1));
881 audiobuf = SKIPBYTES(codec_mallocbuf, CODEC_SIZE);
882 audiosize -= CODEC_SIZE;
884 rb->lcd_clear_display();
885 rb->lcd_update();
887 enum
889 SPEED_TEST = 0,
890 SPEED_TEST_DIR,
891 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
892 BOOST,
893 #endif
894 WRITE_WAV,
895 SPEED_TEST_WITH_DSP,
896 SPEED_TEST_DIR_WITH_DSP,
897 WRITE_WAV_WITH_DSP,
898 CHECKSUM,
899 CHECKSUM_DIR,
900 QUIT,
903 MENUITEM_STRINGLIST(
904 menu, "test_codec", NULL,
905 "Speed test",
906 "Speed test folder",
907 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
908 "Boosting",
909 #endif
910 "Write WAV",
911 "Speed test with DSP",
912 "Speed test folder with DSP",
913 "Write WAV with DSP",
914 "Checksum",
915 "Checksum folder",
916 "Quit",
920 show_menu:
921 rb->lcd_clear_display();
923 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
924 menu:
925 #endif
927 result = rb->do_menu(&menu, &selection, NULL, false);
928 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
930 if (result == BOOST)
932 rb->set_option("Boosting", &boost, INT,
933 boost_settings, 2, NULL);
934 goto menu;
936 if(boost)
937 rb->cpu_boost(true);
938 #endif
940 if (result == QUIT)
942 res = PLUGIN_OK;
943 goto exit;
946 scandir = 0;
948 if ((checksum = (result == CHECKSUM || result == CHECKSUM_DIR)))
949 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
950 result -= 7;
951 #else
952 result -= 6;
953 #endif
955 if ((use_dsp = ((result >= SPEED_TEST_WITH_DSP)
956 && (result <= WRITE_WAV_WITH_DSP)))) {
957 result -= 3;
959 if (result == SPEED_TEST) {
960 wavinfo.fd = -1;
961 log_init(false);
962 } else if (result == SPEED_TEST_DIR) {
963 wavinfo.fd = -1;
964 scandir = 1;
966 /* Only create a log file when we are testing a folder */
967 if (!log_init(true)) {
968 rb->splash(HZ*2, "Cannot create logfile");
969 res = PLUGIN_ERROR;
970 goto exit;
972 } else if (result == WRITE_WAV) {
973 log_init(false);
974 init_wav("/test.wav");
975 if (wavinfo.fd < 0) {
976 rb->splash(HZ*2, "Cannot create /test.wav");
977 res = PLUGIN_ERROR;
978 goto exit;
980 } else if (result == MENU_ATTACHED_USB) {
981 res = PLUGIN_USB_CONNECTED;
982 goto exit;
983 } else if (result < 0) {
984 res = PLUGIN_OK;
985 goto exit;
988 if (scandir) {
989 /* Test all files in the same directory as the file selected by the
990 user */
992 rb->strlcpy(dirpath,parameter,sizeof(dirpath));
993 ch = rb->strrchr(dirpath,'/');
994 ch[1]=0;
996 DEBUGF("Scanning directory \"%s\"\n",dirpath);
997 dir = rb->opendir(dirpath);
998 if (dir) {
999 entry = rb->readdir(dir);
1000 while (entry) {
1001 struct dirinfo info = rb->dir_get_info(dir, entry);
1002 if (!(info.attribute & ATTR_DIRECTORY)) {
1003 rb->snprintf(filename,sizeof(filename),"%s%s",dirpath,entry->d_name);
1004 test_track(filename);
1005 log_text("", true);
1008 /* Read next entry */
1009 entry = rb->readdir(dir);
1012 rb->closedir(dir);
1014 } else {
1015 /* Just test the file */
1016 res = test_track(parameter);
1018 /* Close WAV file (if there was one) */
1019 if (wavinfo.fd >= 0) {
1020 close_wav();
1021 log_text("Wrote /test.wav",true);
1023 plugin_quit();
1026 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
1027 if(boost)
1028 rb->cpu_boost(false);
1029 #endif
1031 rb->button_clear_queue();
1032 goto show_menu;
1034 exit:
1035 log_close();
1037 return res;