Merge branch 'android-notification' into android-test-plugins
[kugel-rb.git] / apps / plugins / test_codec.c
blob7e058d667e912eac59f212630fa1f599bf41addd
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_BOTTOMMIDDLE
39 #else
40 #define TESTCODEC_EXITBUTTON BUTTON_SELECT
41 #endif
43 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
44 static unsigned int boost =1;
46 static const struct opt_items boost_settings[2] = {
47 { "No", -1 },
48 { "Yes", -1 },
51 #endif
53 /* Log functions copied from test_disk.c */
54 static int line = 0;
55 static int max_line = 0;
56 static int log_fd = -1;
58 static void log_close(void)
60 if (log_fd >= 0)
61 rb->close(log_fd);
64 static bool log_init(bool use_logfile)
66 int h;
67 char logfilename[MAX_PATH];
69 rb->lcd_getstringsize("A", NULL, &h);
70 max_line = LCD_HEIGHT / h;
71 line = 0;
72 rb->lcd_clear_display();
73 rb->lcd_update();
75 if (use_logfile) {
76 log_close();
77 #if (CONFIG_PLATFORM & PLATFORM_HOSTED) && !defined(SIMULATOR)
78 rb->get_user_file_path(ROCKBOX_DIR, NEED_WRITE|IS_FILE|FORCE_BUFFER_COPY,
79 logfilename, sizeof(logfilename));
80 rb->create_numbered_filename(logfilename, logfilename, "test_codec_log_", ".txt",
81 2 IF_CNFN_NUM_(, NULL));
82 #else
83 rb->create_numbered_filename(logfilename, "/", "test_codec_log_", ".txt",
84 2 IF_CNFN_NUM_(, NULL));
85 #endif
86 log_fd = rb->open(logfilename, O_RDWR|O_CREAT|O_TRUNC, 0666);
87 return log_fd >= 0;
90 return true;
93 static void log_text(char *text, bool advance)
95 rb->lcd_puts(0, line, text);
96 rb->lcd_update();
97 if (advance)
99 if (++line >= max_line)
100 line = 0;
101 if (log_fd >= 0)
102 rb->fdprintf(log_fd, "%s\n", text);
106 struct wavinfo_t
108 int fd;
109 int samplerate;
110 int channels;
111 int sampledepth;
112 int stereomode;
113 int totalsamples;
116 static void* audiobuf;
117 static void* codec_mallocbuf;
118 static size_t audiosize;
119 static size_t audiobufsize;
120 static int offset;
121 static int fd;
123 /* Our local implementation of the codec API */
124 static struct codec_api ci;
126 struct test_track_info {
127 struct mp3entry id3; /* TAG metadata */
128 size_t filesize; /* File total length */
131 static struct test_track_info track;
132 static bool taginfo_ready = true;
134 static bool use_dsp;
136 static bool checksum;
137 static uint32_t crc32;
139 static volatile unsigned int elapsed;
140 static volatile bool codec_playing;
141 static volatile long endtick;
142 static volatile long rebuffertick;
143 struct wavinfo_t wavinfo;
145 static unsigned char wav_header[44] =
147 'R','I','F','F', // 0 - ChunkID
148 0,0,0,0, // 4 - ChunkSize (filesize-8)
149 'W','A','V','E', // 8 - Format
150 'f','m','t',' ', // 12 - SubChunkID
151 16,0,0,0, // 16 - SubChunk1ID // 16 for PCM
152 1,0, // 20 - AudioFormat (1=16-bit)
153 0,0, // 22 - NumChannels
154 0,0,0,0, // 24 - SampleRate in Hz
155 0,0,0,0, // 28 - Byte Rate (SampleRate*NumChannels*(BitsPerSample/8)
156 0,0, // 32 - BlockAlign (== NumChannels * BitsPerSample/8)
157 16,0, // 34 - BitsPerSample
158 'd','a','t','a', // 36 - Subchunk2ID
159 0,0,0,0 // 40 - Subchunk2Size
162 static inline void int2le32(unsigned char* buf, int32_t x)
164 buf[0] = (x & 0xff);
165 buf[1] = (x & 0xff00) >> 8;
166 buf[2] = (x & 0xff0000) >> 16;
167 buf[3] = (x & 0xff000000) >>24;
170 static inline void int2le24(unsigned char* buf, int32_t x)
172 buf[0] = (x & 0xff);
173 buf[1] = (x & 0xff00) >> 8;
174 buf[2] = (x & 0xff0000) >> 16;
177 static inline void int2le16(unsigned char* buf, int16_t x)
179 buf[0] = (x & 0xff);
180 buf[1] = (x & 0xff00) >> 8;
183 static unsigned char *wavbuffer;
184 static unsigned char *dspbuffer;
186 void init_wav(char* filename)
188 wavinfo.totalsamples = 0;
190 wavinfo.fd = rb->creat(filename, 0666);
192 if (wavinfo.fd >= 0)
194 /* Write WAV header - we go back and fill in the details at the end */
195 rb->write(wavinfo.fd, wav_header, sizeof(wav_header));
200 void close_wav(void)
202 int filesize = rb->filesize(wavinfo.fd);
203 int channels = (wavinfo.stereomode == STEREO_MONO) ? 1 : 2;
204 int bps = 16; /* TODO */
206 /* We assume 16-bit, Stereo */
208 rb->lseek(wavinfo.fd,0,SEEK_SET);
210 int2le32(wav_header+4, filesize-8); /* ChunkSize */
212 int2le16(wav_header+22, channels);
214 int2le32(wav_header+24, wavinfo.samplerate);
216 int2le32(wav_header+28, wavinfo.samplerate * channels * (bps / 8)); /* ByteRate */
218 int2le16(wav_header+32, channels * (bps / 8));
220 int2le32(wav_header+40, filesize - 44); /* Subchunk2Size */
222 rb->write(wavinfo.fd, wav_header, sizeof(wav_header));
224 rb->close(wavinfo.fd);
227 /* Returns buffer to malloc array. Only codeclib should need this. */
228 static void* codec_get_buffer(size_t *size)
230 DEBUGF("codec_get_buffer(%"PRIuPTR")\n",(uintptr_t)size);
231 *size = CODEC_SIZE;
232 return codec_mallocbuf;
235 static int process_dsp(const void *ch1, const void *ch2, int count)
237 const char *src[2] = { ch1, ch2 };
238 int written_count = 0;
239 char *dest = dspbuffer;
241 while (count > 0)
243 int out_count = rb->dsp_output_count(ci.dsp, count);
245 int inp_count = rb->dsp_input_count(ci.dsp, out_count);
247 if (inp_count <= 0)
248 break;
250 if (inp_count > count)
251 inp_count = count;
253 out_count = rb->dsp_process(ci.dsp, dest, src, inp_count);
255 if (out_count <= 0)
256 break;
258 written_count += out_count;
259 dest += out_count * 4;
261 count -= inp_count;
264 return written_count;
267 static inline int32_t clip_sample(int32_t sample)
269 if ((int16_t)sample != sample)
270 sample = 0x7fff ^ (sample >> 31);
272 return sample;
275 /* Null output */
276 static void pcmbuf_insert_null(const void *ch1, const void *ch2, int count)
278 if (use_dsp)
279 process_dsp(ch1, ch2, count);
281 /* Prevent idle poweroff */
282 rb->reset_poweroff_timer();
286 * Helper function used when the file is larger then the available memory.
287 * Rebuffers the file by setting the start of the audio buffer to be
288 * new_offset and filling from there.
290 static int fill_buffer(int new_offset){
291 size_t n, bytestoread;
292 long temp = *rb->current_tick;
293 rb->lseek(fd,new_offset,SEEK_SET);
295 if(new_offset + audiobufsize <= track.filesize)
296 bytestoread = audiobufsize;
297 else
298 bytestoread = track.filesize-new_offset;
300 n = rb->read(fd, audiobuf,bytestoread);
302 if (n != bytestoread)
304 log_text("Read failed.",true);
305 DEBUGF("read fail: got %d bytes, expected %d\n", (int)n, (int)audiobufsize);
306 rb->backlight_on();
308 if (fd >= 0)
310 rb->close(fd);
313 return -1;
315 offset = new_offset;
317 /*keep track of how much time we spent buffering*/
318 rebuffertick += *rb->current_tick-temp;
320 return 0;
323 /* WAV output or calculate crc32 of output*/
324 static void pcmbuf_insert_wav_checksum(const void *ch1, const void *ch2, int count)
326 const int16_t* data1_16;
327 const int16_t* data2_16;
328 const int32_t* data1_32;
329 const int32_t* data2_32;
330 unsigned char* p = wavbuffer;
331 const int scale = wavinfo.sampledepth - 15;
332 const int dc_bias = 1 << (scale - 1);
333 int channels = (wavinfo.stereomode == STEREO_MONO) ? 1 : 2;
335 /* Prevent idle poweroff */
336 rb->reset_poweroff_timer();
338 if (use_dsp) {
339 count = process_dsp(ch1, ch2, count);
340 wavinfo.totalsamples += count;
341 if (channels == 1)
343 unsigned char *s = dspbuffer, *d = dspbuffer;
344 int c = count;
345 while (c-- > 0)
347 *d++ = *s++;
348 *d++ = *s++;
349 s++;
350 s++;
353 if (checksum)
354 crc32 = rb->crc_32(dspbuffer, count * 2 * channels, crc32);
355 else
356 rb->write(wavinfo.fd, dspbuffer, count * 2 * channels);
358 else
360 if (wavinfo.sampledepth <= 16) {
361 data1_16 = ch1;
362 data2_16 = ch2;
364 switch(wavinfo.stereomode)
366 case STEREO_INTERLEAVED:
367 while (count--) {
368 int2le16(p,*data1_16++);
369 p += 2;
370 int2le16(p,*data1_16++);
371 p += 2;
373 break;
375 case STEREO_NONINTERLEAVED:
376 while (count--) {
377 int2le16(p,*data1_16++);
378 p += 2;
379 int2le16(p,*data2_16++);
380 p += 2;
383 break;
385 case STEREO_MONO:
386 while (count--) {
387 int2le16(p,*data1_16++);
388 p += 2;
390 break;
392 } else {
393 data1_32 = ch1;
394 data2_32 = ch2;
396 switch(wavinfo.stereomode)
398 case STEREO_INTERLEAVED:
399 while (count--) {
400 int2le16(p, clip_sample((*data1_32++ + dc_bias) >> scale));
401 p += 2;
402 int2le16(p, clip_sample((*data1_32++ + dc_bias) >> scale));
403 p += 2;
405 break;
407 case STEREO_NONINTERLEAVED:
408 while (count--) {
409 int2le16(p, clip_sample((*data1_32++ + dc_bias) >> scale));
410 p += 2;
411 int2le16(p, clip_sample((*data2_32++ + dc_bias) >> scale));
412 p += 2;
415 break;
417 case STEREO_MONO:
418 while (count--) {
419 int2le16(p, clip_sample((*data1_32++ + dc_bias) >> scale));
420 p += 2;
422 break;
426 wavinfo.totalsamples += count;
427 if (checksum)
428 crc32 = rb->crc_32(wavbuffer, p - wavbuffer, crc32);
429 else
430 rb->write(wavinfo.fd, wavbuffer, p - wavbuffer);
431 } /* else */
434 /* Set song position in WPS (value in ms). */
435 static void set_elapsed(unsigned long value)
437 elapsed = value;
441 /* Read next <size> amount bytes from file buffer to <ptr>.
442 Will return number of bytes read or 0 if end of file. */
443 static size_t read_filebuf(void *ptr, size_t size)
445 if (ci.curpos > (off_t)track.filesize)
447 return 0;
448 } else {
449 size_t realsize = MIN(track.filesize-ci.curpos,size);
451 /* check if we have enough bytes ready*/
452 if(realsize >(audiobufsize - (ci.curpos-offset)))
454 /*rebuffer so that we start at ci.curpos*/
455 fill_buffer(ci.curpos);
458 rb->memcpy(ptr, audiobuf + (ci.curpos-offset), realsize);
459 ci.curpos += realsize;
460 return realsize;
465 /* Request pointer to file buffer which can be used to read
466 <realsize> amount of data. <reqsize> tells the buffer system
467 how much data it should try to allocate. If <realsize> is 0,
468 end of file is reached. */
469 static void* request_buffer(size_t *realsize, size_t reqsize)
471 *realsize = MIN(track.filesize-ci.curpos,reqsize);
473 /*check if we have enough bytes ready - requested > bufsize-currentbufpos*/
474 if(*realsize>(audiobufsize - (ci.curpos-offset)))
476 /*rebuffer so that we start at ci.curpos*/
477 fill_buffer(ci.curpos);
480 return (audiobuf + (ci.curpos-offset));
483 /* Advance file buffer position by <amount> amount of bytes. */
484 static void advance_buffer(size_t amount)
486 ci.curpos += amount;
490 /* Advance file buffer to a pointer location inside file buffer. */
491 static void advance_buffer_loc(void *ptr)
493 ci.curpos = ptr - (audiobuf - offset);
497 /* Seek file buffer to position <newpos> beginning of file. */
498 static bool seek_buffer(size_t newpos)
500 ci.curpos = newpos;
501 return true;
505 /* Codec should call this function when it has done the seeking. */
506 static void seek_complete(void)
508 /* Do nothing */
511 /* Request file change from file buffer. Returns true is next
512 track is available and changed. If return value is false,
513 codec should exit immediately with PLUGIN_OK status. */
514 static bool request_next_track(void)
516 /* We are only decoding a single track */
517 return false;
521 /* Free the buffer area of the current codec after its loaded */
522 static void discard_codec(void)
524 /* ??? */
528 static void set_offset(size_t value)
530 /* ??? */
531 (void)value;
535 /* Configure different codec buffer parameters. */
536 static void configure(int setting, intptr_t value)
538 if (use_dsp)
539 rb->dsp_configure(ci.dsp, setting, value);
540 switch(setting)
542 case DSP_SWITCH_FREQUENCY:
543 case DSP_SET_FREQUENCY:
544 DEBUGF("samplerate=%d\n",(int)value);
545 wavinfo.samplerate = (int)value;
546 break;
548 case DSP_SET_SAMPLE_DEPTH:
549 DEBUGF("sampledepth = %d\n",(int)value);
550 wavinfo.sampledepth=(int)value;
551 break;
553 case DSP_SET_STEREO_MODE:
554 DEBUGF("Stereo mode = %d\n",(int)value);
555 wavinfo.stereomode=(int)value;
556 break;
561 static void init_ci(void)
563 /* --- Our "fake" implementations of the codec API functions. --- */
565 ci.codec_get_buffer = codec_get_buffer;
567 if (wavinfo.fd >= 0 || checksum) {
568 ci.pcmbuf_insert = pcmbuf_insert_wav_checksum;
569 } else {
570 ci.pcmbuf_insert = pcmbuf_insert_null;
573 ci.set_elapsed = set_elapsed;
574 ci.read_filebuf = read_filebuf;
575 ci.request_buffer = request_buffer;
576 ci.advance_buffer = advance_buffer;
577 ci.advance_buffer_loc = advance_buffer_loc;
578 ci.seek_buffer = seek_buffer;
579 ci.seek_complete = seek_complete;
580 ci.request_next_track = request_next_track;
581 ci.discard_codec = discard_codec;
582 ci.set_offset = set_offset;
583 ci.configure = configure;
584 ci.dsp = (struct dsp_config *)rb->dsp_configure(NULL, DSP_MYDSP,
585 CODEC_IDX_AUDIO);
587 /* --- "Core" functions --- */
589 /* kernel/ system */
590 ci.sleep = rb->sleep;
591 ci.yield = rb->yield;
593 /* strings and memory */
594 ci.strcpy = rb->strcpy;
595 ci.strlen = rb->strlen;
596 ci.strcmp = rb->strcmp;
597 ci.strcat = rb->strcat;
598 ci.memset = rb->memset;
599 ci.memcpy = rb->memcpy;
600 ci.memmove = rb->memmove;
601 ci.memcmp = rb->memcmp;
602 ci.memchr = rb->memchr;
603 ci.strcasestr = rb->strcasestr;
604 #if defined(DEBUG) || defined(SIMULATOR)
605 ci.debugf = rb->debugf;
606 #endif
607 #ifdef ROCKBOX_HAS_LOGF
608 ci.logf = rb->logf;
609 #endif
611 ci.qsort = rb->qsort;
612 ci.global_settings = rb->global_settings;
614 #ifdef RB_PROFILE
615 ci.profile_thread = rb->profile_thread;
616 ci.profstop = rb->profstop;
617 ci.profile_func_enter = rb->profile_func_enter;
618 ci.profile_func_exit = rb->profile_func_exit;
619 #endif
621 ci.cpucache_invalidate = rb->cpucache_invalidate;
622 ci.cpucache_flush = rb->cpucache_flush;
624 #if NUM_CORES > 1
625 ci.create_thread = rb->create_thread;
626 ci.thread_thaw = rb->thread_thaw;
627 ci.thread_wait = rb->thread_wait;
628 ci.semaphore_init = rb->semaphore_init;
629 ci.semaphore_wait = rb->semaphore_wait;
630 ci.semaphore_release = rb->semaphore_release;
631 #endif
633 #if defined(CPU_ARM) && (CONFIG_PLATFORM & PLATFORM_NATIVE)
634 ci.__div0 = rb->__div0;
635 #endif
638 static void codec_thread(void)
640 const char* codecname;
641 int res;
643 codecname = rb->get_codec_filename(track.id3.codectype);
645 /* Load the codec and start decoding. */
646 res = rb->codec_load_file(codecname,&ci);
648 /* Signal to the main thread that we are done */
649 endtick = *rb->current_tick - rebuffertick;
650 codec_playing = false;
653 static enum plugin_status test_track(const char* filename)
655 size_t n;
656 enum plugin_status res = PLUGIN_ERROR;
657 long starttick;
658 long ticks;
659 unsigned long speed;
660 unsigned long duration;
661 const char* ch;
662 char str[MAX_PATH];
663 offset=0;
665 /* Display filename (excluding any path)*/
666 ch = rb->strrchr(filename, '/');
667 if (ch==NULL)
668 ch = filename;
669 else
670 ch++;
672 rb->snprintf(str,sizeof(str),"%s",ch);
673 log_text(str,true);
675 log_text("Loading...",false);
677 fd = rb->open(filename,O_RDONLY);
678 if (fd < 0)
680 log_text("Cannot open file",true);
681 goto exit;
684 track.filesize = rb->filesize(fd);
686 /* Clear the id3 struct */
687 rb->memset(&track.id3, 0, sizeof(struct mp3entry));
689 if (!rb->get_metadata(&(track.id3), fd, filename))
691 log_text("Cannot read metadata",true);
692 goto exit;
695 if (track.filesize > audiosize)
697 audiobufsize=audiosize;
699 } else
701 audiobufsize=track.filesize;
704 n = rb->read(fd, audiobuf, audiobufsize);
706 if (n != audiobufsize)
708 log_text("Read failed.",true);
709 goto exit;
713 /* Initialise the function pointers in the codec API */
714 init_ci();
716 /* Prepare the codec struct for playing the whole file */
717 ci.filesize = track.filesize;
718 ci.id3 = &track.id3;
719 ci.taginfo_ready = &taginfo_ready;
720 ci.curpos = 0;
721 ci.stop_codec = false;
722 ci.new_track = 0;
723 ci.seek_time = 0;
725 if (use_dsp)
726 rb->dsp_configure(ci.dsp, DSP_RESET, 0);
728 if (checksum)
729 crc32 = 0xffffffff;
731 rebuffertick=0;
732 starttick = *rb->current_tick;
734 codec_playing = true;
736 rb->codec_thread_do_callback(codec_thread, NULL);
738 /* Wait for codec thread to die */
739 while (codec_playing)
741 rb->sleep(HZ);
742 rb->snprintf(str,sizeof(str),"%d of %d",elapsed,(int)track.id3.length);
743 log_text(str,false);
745 ticks = endtick - starttick;
747 /* Be sure it is done */
748 rb->codec_thread_do_callback(NULL, NULL);
749 rb->backlight_on();
750 log_text(str,true);
752 if (checksum)
754 rb->snprintf(str, sizeof(str), "CRC32 - %08x", (unsigned)crc32);
755 log_text(str,true);
757 else if (wavinfo.fd < 0)
759 /* Display benchmark information */
760 rb->snprintf(str,sizeof(str),"Decode time - %d.%02ds",(int)ticks/100,(int)ticks%100);
761 log_text(str,true);
763 duration = track.id3.length / 10;
764 rb->snprintf(str,sizeof(str),"File duration - %d.%02ds",(int)duration/100,(int)duration%100);
765 log_text(str,true);
767 if (ticks > 0)
768 speed = duration * 10000 / ticks;
769 else
770 speed = 0;
772 rb->snprintf(str,sizeof(str),"%d.%02d%% realtime",(int)speed/100,(int)speed%100);
773 log_text(str,true);
775 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
776 /* show effective clockrate in MHz needed for realtime decoding */
777 if (speed > 0)
779 int freq = CPUFREQ_MAX;
781 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
782 if(!boost)
783 freq = CPUFREQ_NORMAL;
784 #endif
786 speed = freq / speed;
787 rb->snprintf(str,sizeof(str),"%d.%02dMHz needed for realtime",
788 (int)speed/100,(int)speed%100);
789 log_text(str,true);
791 #endif
794 res = PLUGIN_OK;
796 exit:
797 rb->backlight_on();
799 if (fd >= 0)
801 rb->close(fd);
804 return res;
807 #ifdef HAVE_TOUCHSCREEN
808 void cleanup(void)
810 rb->screens[0]->set_viewport(NULL);
812 #endif
814 void plugin_quit(void)
816 #ifdef HAVE_TOUCHSCREEN
817 struct viewport vp;
818 struct screen *lcd = rb->screens[SCREEN_MAIN];
819 rb->viewport_set_defaults(&vp, SCREEN_MAIN);
820 int font_height = rb->font_get(vp.font)->height;
821 int yoff;
823 vp.x = 10;
824 vp.width = lcd->lcdwidth - 20;
825 vp.y = lcd->lcdheight - 60;
826 vp.height = 50;
827 vp.flags = VP_FLAG_ALIGN_CENTER;
829 yoff = vp.height/2 - font_height/2;
830 lcd->set_viewport(&vp);
831 atexit(cleanup);
832 lcd->clear_viewport();
833 lcd->set_foreground(LCD_WHITE);
834 lcd->putsxy(0, yoff, "OK");
835 lcd->drawrect(vp.x, vp.y, vp.width, vp.height);
836 lcd->update_viewport();
837 short x,y;
838 if (rb->touchscreen_get_mode() == TOUCHSCREEN_POINT)
840 while(1)
842 rb->get_action(CONTEXT_STD, TIMEOUT_BLOCK);
843 if (rb->action_get_touchscreen_press_in_vp(&x, &y, &vp) & BUTTON_REL)
844 break;
847 else
848 #endif
849 while (rb->button_get(true) != TESTCODEC_EXITBUTTON);
852 /* plugin entry point */
853 enum plugin_status plugin_start(const void* parameter)
855 int result, selection = 0;
856 enum plugin_status res = PLUGIN_OK;
857 int scandir;
858 struct dirent *entry;
859 DIR* dir;
860 char* ch;
861 char dirpath[MAX_PATH];
862 char filename[MAX_PATH];
863 size_t buffer_size;
865 if (parameter == NULL)
867 rb->splash(HZ*2, "No File");
868 return PLUGIN_ERROR;
871 wavbuffer = rb->plugin_get_buffer(&buffer_size);
872 dspbuffer = wavbuffer + buffer_size / 2;
874 codec_mallocbuf = rb->plugin_get_audio_buffer(&audiosize);
875 /* Align codec_mallocbuf to pointer size, tlsf wants that */
876 codec_mallocbuf = (void*)(((intptr_t)codec_mallocbuf +
877 sizeof(intptr_t)-1) & ~(sizeof(intptr_t)-1));
878 audiobuf = SKIPBYTES(codec_mallocbuf, CODEC_SIZE);
879 audiosize -= CODEC_SIZE;
881 rb->lcd_clear_display();
882 rb->lcd_update();
884 enum
886 SPEED_TEST = 0,
887 SPEED_TEST_DIR,
888 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
889 BOOST,
890 #endif
891 WRITE_WAV,
892 SPEED_TEST_WITH_DSP,
893 SPEED_TEST_DIR_WITH_DSP,
894 WRITE_WAV_WITH_DSP,
895 CHECKSUM,
896 CHECKSUM_DIR,
897 QUIT,
900 MENUITEM_STRINGLIST(
901 menu, "test_codec", NULL,
902 "Speed test",
903 "Speed test folder",
904 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
905 "Boosting",
906 #endif
907 "Write WAV",
908 "Speed test with DSP",
909 "Speed test folder with DSP",
910 "Write WAV with DSP",
911 "Checksum",
912 "Checksum folder",
913 "Quit",
917 show_menu:
918 rb->lcd_clear_display();
920 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
921 menu:
922 #endif
924 result = rb->do_menu(&menu, &selection, NULL, false);
925 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
927 if (result == BOOST)
929 rb->set_option("Boosting", &boost, INT,
930 boost_settings, 2, NULL);
931 goto menu;
933 if(boost)
934 rb->cpu_boost(true);
935 #endif
937 if (result == QUIT)
939 res = PLUGIN_OK;
940 goto exit;
943 scandir = 0;
945 if ((checksum = (result == CHECKSUM || result == CHECKSUM_DIR)))
946 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
947 result -= 7;
948 #else
949 result -= 6;
950 #endif
952 if ((use_dsp = ((result >= SPEED_TEST_WITH_DSP)
953 && (result <= WRITE_WAV_WITH_DSP)))) {
954 result -= 3;
956 if (result == SPEED_TEST) {
957 wavinfo.fd = -1;
958 log_init(false);
959 } else if (result == SPEED_TEST_DIR) {
960 wavinfo.fd = -1;
961 scandir = 1;
963 /* Only create a log file when we are testing a folder */
964 if (!log_init(true)) {
965 rb->splash(HZ*2, "Cannot create logfile");
966 res = PLUGIN_ERROR;
967 goto exit;
969 } else if (result == WRITE_WAV) {
970 log_init(false);
971 init_wav("/test.wav");
972 if (wavinfo.fd < 0) {
973 rb->splash(HZ*2, "Cannot create /test.wav");
974 res = PLUGIN_ERROR;
975 goto exit;
977 } else if (result == MENU_ATTACHED_USB) {
978 res = PLUGIN_USB_CONNECTED;
979 goto exit;
980 } else if (result < 0) {
981 res = PLUGIN_OK;
982 goto exit;
985 if (scandir) {
986 /* Test all files in the same directory as the file selected by the
987 user */
989 rb->strlcpy(dirpath,parameter,sizeof(dirpath));
990 ch = rb->strrchr(dirpath,'/');
991 ch[1]=0;
993 DEBUGF("Scanning directory \"%s\"\n",dirpath);
994 dir = rb->opendir(dirpath);
995 if (dir) {
996 entry = rb->readdir(dir);
997 while (entry) {
998 struct dirinfo info = rb->dir_get_info(dir, entry);
999 if (!(info.attribute & ATTR_DIRECTORY)) {
1000 rb->snprintf(filename,sizeof(filename),"%s%s",dirpath,entry->d_name);
1001 test_track(filename);
1002 log_text("", true);
1005 /* Read next entry */
1006 entry = rb->readdir(dir);
1009 rb->closedir(dir);
1011 } else {
1012 /* Just test the file */
1013 res = test_track(parameter);
1015 /* Close WAV file (if there was one) */
1016 if (wavinfo.fd >= 0) {
1017 close_wav();
1018 log_text("Wrote /test.wav",true);
1020 plugin_quit();
1023 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
1024 if(boost)
1025 rb->cpu_boost(false);
1026 #endif
1028 rb->button_clear_queue();
1029 goto show_menu;
1031 exit:
1032 log_close();
1034 return res;