Prepare new maemo release
[maemo-rb.git] / apps / plugins / test_codec.c
blob920be54d5632282d23a8b1a6a4a0bef6df30e5ac
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"
22 #include "lib/pluginlib_touchscreen.h"
23 #include "lib/pluginlib_exit.h"
24 #include "lib/pluginlib_actions.h"
26 /* this set the context to use with PLA */
27 static const struct button_mapping *plugin_contexts[] = { pla_main_ctx };
29 #define TESTCODEC_EXITBUTTON PLA_EXIT
30 #define TESTCODEC_EXITBUTTON2 PLA_CANCEL
33 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
34 static unsigned int boost =1;
36 static const struct opt_items boost_settings[2] = {
37 { "No", -1 },
38 { "Yes", -1 },
40 #endif
42 /* Log functions copied from test_disk.c */
43 static int line = 0;
44 static int max_line = 0;
45 static int log_fd = -1;
47 static void log_close(void)
49 if (log_fd >= 0)
50 rb->close(log_fd);
53 static bool log_init(bool use_logfile)
55 int h;
56 char logfilename[MAX_PATH];
58 rb->lcd_getstringsize("A", NULL, &h);
59 max_line = LCD_HEIGHT / h;
60 line = 0;
61 rb->lcd_clear_display();
62 rb->lcd_update();
64 if (use_logfile) {
65 log_close();
66 rb->create_numbered_filename(logfilename, HOME_DIR, "test_codec_log_", ".txt",
67 2 IF_CNFN_NUM_(, NULL));
68 log_fd = rb->open(logfilename, O_RDWR|O_CREAT|O_TRUNC, 0666);
69 return log_fd >= 0;
72 return true;
75 static void log_text(char *text, bool advance)
77 rb->lcd_puts(0, line, text);
78 rb->lcd_update();
79 if (advance)
81 if (++line >= max_line)
82 line = 0;
83 if (log_fd >= 0)
84 rb->fdprintf(log_fd, "%s\n", text);
88 struct wavinfo_t
90 int fd;
91 int samplerate;
92 int channels;
93 int sampledepth;
94 int stereomode;
95 int totalsamples;
98 static void* audiobuf;
99 static void* codec_mallocbuf;
100 static size_t audiosize;
101 static size_t audiobufsize;
102 static int offset;
103 static int fd;
105 /* Our local implementation of the codec API */
106 static struct codec_api ci;
108 struct test_track_info {
109 struct mp3entry id3; /* TAG metadata */
110 size_t filesize; /* File total length */
113 static struct test_track_info track;
115 static bool use_dsp;
117 static bool checksum;
118 static uint32_t crc32;
120 static volatile unsigned int elapsed;
121 static volatile bool codec_playing;
122 static volatile enum codec_command_action codec_action;
123 static volatile long endtick;
124 static volatile long rebuffertick;
125 struct wavinfo_t wavinfo;
127 static unsigned char wav_header[44] =
129 'R','I','F','F', // 0 - ChunkID
130 0,0,0,0, // 4 - ChunkSize (filesize-8)
131 'W','A','V','E', // 8 - Format
132 'f','m','t',' ', // 12 - SubChunkID
133 16,0,0,0, // 16 - SubChunk1ID // 16 for PCM
134 1,0, // 20 - AudioFormat (1=16-bit)
135 0,0, // 22 - NumChannels
136 0,0,0,0, // 24 - SampleRate in Hz
137 0,0,0,0, // 28 - Byte Rate (SampleRate*NumChannels*(BitsPerSample/8)
138 0,0, // 32 - BlockAlign (== NumChannels * BitsPerSample/8)
139 16,0, // 34 - BitsPerSample
140 'd','a','t','a', // 36 - Subchunk2ID
141 0,0,0,0 // 40 - Subchunk2Size
144 static inline void int2le32(unsigned char* buf, int32_t x)
146 buf[0] = (x & 0xff);
147 buf[1] = (x & 0xff00) >> 8;
148 buf[2] = (x & 0xff0000) >> 16;
149 buf[3] = (x & 0xff000000) >>24;
152 static inline void int2le24(unsigned char* buf, int32_t x)
154 buf[0] = (x & 0xff);
155 buf[1] = (x & 0xff00) >> 8;
156 buf[2] = (x & 0xff0000) >> 16;
159 static inline void int2le16(unsigned char* buf, int16_t x)
161 buf[0] = (x & 0xff);
162 buf[1] = (x & 0xff00) >> 8;
165 static unsigned char *wavbuffer;
166 static unsigned char *dspbuffer;
167 static int dspbuffer_count;
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 *size = CODEC_SIZE;
214 return codec_mallocbuf;
217 static int process_dsp(const void *ch1, const void *ch2, int count)
219 struct dsp_buffer src;
220 src.remcount = count;
221 src.pin[0] = ch1;
222 src.pin[1] = ch2;
223 src.proc_mask = 0;
225 struct dsp_buffer dst;
226 dst.remcount = 0;
227 dst.p16out = (int16_t *)dspbuffer;
228 dst.bufcount = dspbuffer_count;
230 while (1)
232 int old_remcount = dst.remcount;
233 rb->dsp_process(ci.dsp, &src, &dst);
235 if (dst.bufcount <= 0 ||
236 (src.remcount <= 0 && dst.remcount <= old_remcount))
238 /* Dest is full or no input left and DSP purged */
239 break;
243 return dst.remcount;
246 /* Null output */
247 static void pcmbuf_insert_null(const void *ch1, const void *ch2, int count)
249 if (use_dsp)
250 process_dsp(ch1, ch2, count);
252 /* Prevent idle poweroff */
253 rb->reset_poweroff_timer();
257 * Helper function used when the file is larger then the available memory.
258 * Rebuffers the file by setting the start of the audio buffer to be
259 * new_offset and filling from there.
261 static int fill_buffer(int new_offset){
262 size_t n, bytestoread;
263 long temp = *rb->current_tick;
264 rb->lseek(fd,new_offset,SEEK_SET);
266 if(new_offset + audiobufsize <= track.filesize)
267 bytestoread = audiobufsize;
268 else
269 bytestoread = track.filesize-new_offset;
271 n = rb->read(fd, audiobuf,bytestoread);
273 if (n != bytestoread)
275 log_text("Read failed.",true);
276 DEBUGF("read fail: got %d bytes, expected %d\n", (int)n, (int)audiobufsize);
277 rb->backlight_on();
279 if (fd >= 0)
281 rb->close(fd);
284 return -1;
286 offset = new_offset;
288 /*keep track of how much time we spent buffering*/
289 rebuffertick += *rb->current_tick-temp;
291 return 0;
294 /* WAV output or calculate crc32 of output*/
295 static void pcmbuf_insert_wav_checksum(const void *ch1, const void *ch2, int count)
297 /* Prevent idle poweroff */
298 rb->reset_poweroff_timer();
300 if (use_dsp) {
301 count = process_dsp(ch1, ch2, count);
302 wavinfo.totalsamples += count;
304 #ifdef ROCKBOX_BIG_ENDIAN
305 unsigned char* p = dspbuffer;
306 int i;
307 for (i = 0; i < count; i++) {
308 int2le16(p,*(int16_t *)p);
309 p += 2;
310 int2le16(p,*(int16_t *)p);
311 p += 2;
313 #endif
314 if (checksum) {
315 crc32 = rb->crc_32(dspbuffer, count * 2 * sizeof (int16_t), crc32);
316 } else {
317 rb->write(wavinfo.fd, dspbuffer, count * 2 * sizeof (int16_t));
320 else
322 const int16_t* data1_16;
323 const int16_t* data2_16;
324 const int32_t* data1_32;
325 const int32_t* data2_32;
326 unsigned char* p = wavbuffer;
327 const int scale = wavinfo.sampledepth - 15;
328 const int dc_bias = 1 << (scale - 1);
330 if (wavinfo.sampledepth <= 16) {
331 data1_16 = ch1;
332 data2_16 = ch2;
334 switch(wavinfo.stereomode)
336 case STEREO_INTERLEAVED:
337 while (count--) {
338 int2le16(p,*data1_16++);
339 p += 2;
340 int2le16(p,*data1_16++);
341 p += 2;
343 break;
345 case STEREO_NONINTERLEAVED:
346 while (count--) {
347 int2le16(p,*data1_16++);
348 p += 2;
349 int2le16(p,*data2_16++);
350 p += 2;
353 break;
355 case STEREO_MONO:
356 while (count--) {
357 int2le16(p,*data1_16++);
358 p += 2;
360 break;
362 } else {
363 data1_32 = ch1;
364 data2_32 = ch2;
366 switch(wavinfo.stereomode)
368 case STEREO_INTERLEAVED:
369 while (count--) {
370 int2le16(p, clip_sample_16((*data1_32++ + dc_bias) >> scale));
371 p += 2;
372 int2le16(p, clip_sample_16((*data1_32++ + dc_bias) >> scale));
373 p += 2;
375 break;
377 case STEREO_NONINTERLEAVED:
378 while (count--) {
379 int2le16(p, clip_sample_16((*data1_32++ + dc_bias) >> scale));
380 p += 2;
381 int2le16(p, clip_sample_16((*data2_32++ + dc_bias) >> scale));
382 p += 2;
385 break;
387 case STEREO_MONO:
388 while (count--) {
389 int2le16(p, clip_sample_16((*data1_32++ + dc_bias) >> scale));
390 p += 2;
392 break;
396 wavinfo.totalsamples += count;
397 if (checksum)
398 crc32 = rb->crc_32(wavbuffer, p - wavbuffer, crc32);
399 else
400 rb->write(wavinfo.fd, wavbuffer, p - wavbuffer);
401 } /* else */
404 /* Set song position in WPS (value in ms). */
405 static void set_elapsed(unsigned long value)
407 elapsed = value;
408 ci.id3->elapsed = value;
412 /* Read next <size> amount bytes from file buffer to <ptr>.
413 Will return number of bytes read or 0 if end of file. */
414 static size_t read_filebuf(void *ptr, size_t size)
416 if (ci.curpos > (off_t)track.filesize)
418 return 0;
419 } else {
420 size_t realsize = MIN(track.filesize-ci.curpos,size);
422 /* check if we have enough bytes ready*/
423 if(realsize >(audiobufsize - (ci.curpos-offset)))
425 /*rebuffer so that we start at ci.curpos*/
426 fill_buffer(ci.curpos);
429 rb->memcpy(ptr, audiobuf + (ci.curpos-offset), realsize);
430 ci.curpos += realsize;
431 return realsize;
436 /* Request pointer to file buffer which can be used to read
437 <realsize> amount of data. <reqsize> tells the buffer system
438 how much data it should try to allocate. If <realsize> is 0,
439 end of file is reached. */
440 static void* request_buffer(size_t *realsize, size_t reqsize)
442 *realsize = MIN(track.filesize-ci.curpos,reqsize);
444 /*check if we have enough bytes ready - requested > bufsize-currentbufpos*/
445 if(*realsize>(audiobufsize - (ci.curpos-offset)))
447 /*rebuffer so that we start at ci.curpos*/
448 fill_buffer(ci.curpos);
451 return (audiobuf + (ci.curpos-offset));
454 /* Advance file buffer position by <amount> amount of bytes. */
455 static void advance_buffer(size_t amount)
457 ci.curpos += amount;
458 ci.id3->offset = ci.curpos;
462 /* Seek file buffer to position <newpos> beginning of file. */
463 static bool seek_buffer(size_t newpos)
465 ci.curpos = newpos;
466 return true;
470 /* Codec should call this function when it has done the seeking. */
471 static void seek_complete(void)
473 /* Do nothing */
476 /* Codec calls this to know what it should do next. */
477 static enum codec_command_action get_command(intptr_t *param)
479 rb->yield();
480 return codec_action;
481 (void)param;
484 /* Some codecs call this to determine whether they should loop. */
485 static bool loop_track(void)
487 return false;
490 static void set_offset(size_t value)
492 ci.id3->offset = value;
496 /* Configure different codec buffer parameters. */
497 static void configure(int setting, intptr_t value)
499 if (use_dsp)
500 rb->dsp_configure(ci.dsp, setting, value);
501 switch(setting)
503 case DSP_SET_FREQUENCY:
504 DEBUGF("samplerate=%d\n",(int)value);
505 wavinfo.samplerate = use_dsp ? NATIVE_FREQUENCY : (int)value;
506 break;
508 case DSP_SET_SAMPLE_DEPTH:
509 DEBUGF("sampledepth = %d\n",(int)value);
510 wavinfo.sampledepth = use_dsp ? 16 : (int)value;
511 break;
513 case DSP_SET_STEREO_MODE:
514 DEBUGF("Stereo mode = %d\n",(int)value);
515 wavinfo.stereomode = use_dsp ? STEREO_INTERLEAVED : (int)value;
516 break;
521 static void init_ci(void)
523 /* --- Our "fake" implementations of the codec API functions. --- */
525 ci.dsp = rb->dsp_get_config(CODEC_IDX_AUDIO);
526 ci.codec_get_buffer = codec_get_buffer;
528 if (wavinfo.fd >= 0 || checksum) {
529 ci.pcmbuf_insert = pcmbuf_insert_wav_checksum;
530 } else {
531 ci.pcmbuf_insert = pcmbuf_insert_null;
534 ci.set_elapsed = set_elapsed;
535 ci.read_filebuf = read_filebuf;
536 ci.request_buffer = request_buffer;
537 ci.advance_buffer = advance_buffer;
538 ci.seek_buffer = seek_buffer;
539 ci.seek_complete = seek_complete;
540 ci.set_offset = set_offset;
541 ci.configure = configure;
542 ci.get_command = get_command;
543 ci.loop_track = loop_track;
545 /* --- "Core" functions --- */
547 /* kernel/ system */
548 ci.sleep = rb->sleep;
549 ci.yield = rb->yield;
551 /* strings and memory */
552 ci.strcpy = rb->strcpy;
553 ci.strlen = rb->strlen;
554 ci.strcmp = rb->strcmp;
555 ci.strcat = rb->strcat;
556 ci.memset = rb->memset;
557 ci.memcpy = rb->memcpy;
558 ci.memmove = rb->memmove;
559 ci.memcmp = rb->memcmp;
560 ci.memchr = rb->memchr;
561 #if defined(DEBUG) || defined(SIMULATOR)
562 ci.debugf = rb->debugf;
563 #endif
564 #ifdef ROCKBOX_HAS_LOGF
565 ci.logf = rb->logf;
566 #endif
568 ci.qsort = rb->qsort;
570 #ifdef RB_PROFILE
571 ci.profile_thread = rb->profile_thread;
572 ci.profstop = rb->profstop;
573 ci.profile_func_enter = rb->profile_func_enter;
574 ci.profile_func_exit = rb->profile_func_exit;
575 #endif
577 ci.commit_dcache = rb->commit_dcache;
578 ci.commit_discard_dcache = rb->commit_discard_dcache;
579 ci.commit_discard_idcache = rb->commit_discard_idcache;
581 #if NUM_CORES > 1
582 ci.create_thread = rb->create_thread;
583 ci.thread_thaw = rb->thread_thaw;
584 ci.thread_wait = rb->thread_wait;
585 ci.semaphore_init = rb->semaphore_init;
586 ci.semaphore_wait = rb->semaphore_wait;
587 ci.semaphore_release = rb->semaphore_release;
588 #endif
590 #if defined(CPU_ARM) && (CONFIG_PLATFORM & PLATFORM_NATIVE)
591 ci.__div0 = rb->__div0;
592 #endif
595 static void codec_thread(void)
597 const char* codecname;
598 int res;
600 codecname = rb->get_codec_filename(track.id3.codectype);
602 /* Load the codec */
603 res = rb->codec_load_file(codecname, &ci);
605 if (res >= 0)
607 /* Decode the file */
608 res = rb->codec_run_proc();
611 /* Clean up */
612 rb->codec_close();
614 /* Signal to the main thread that we are done */
615 endtick = *rb->current_tick - rebuffertick;
616 codec_playing = false;
619 static enum plugin_status test_track(const char* filename)
621 size_t n;
622 enum plugin_status res = PLUGIN_ERROR;
623 long starttick;
624 long ticks;
625 unsigned long speed;
626 unsigned long duration;
627 const char* ch;
628 char str[MAX_PATH];
629 offset=0;
631 /* Display filename (excluding any path)*/
632 ch = rb->strrchr(filename, '/');
633 if (ch==NULL)
634 ch = filename;
635 else
636 ch++;
638 rb->snprintf(str,sizeof(str),"%s",ch);
639 log_text(str,true);
641 log_text("Loading...",false);
643 fd = rb->open(filename,O_RDONLY);
644 if (fd < 0)
646 log_text("Cannot open file",true);
647 goto exit;
650 track.filesize = rb->filesize(fd);
652 /* Clear the id3 struct */
653 rb->memset(&track.id3, 0, sizeof(struct mp3entry));
655 if (!rb->get_metadata(&(track.id3), fd, filename))
657 log_text("Cannot read metadata",true);
658 goto exit;
661 if (track.filesize > audiosize)
663 audiobufsize=audiosize;
665 } else
667 audiobufsize=track.filesize;
670 n = rb->read(fd, audiobuf, audiobufsize);
672 if (n != audiobufsize)
674 log_text("Read failed.",true);
675 goto exit;
679 /* Initialise the function pointers in the codec API */
680 init_ci();
682 /* Prepare the codec struct for playing the whole file */
683 ci.filesize = track.filesize;
684 ci.id3 = &track.id3;
685 ci.curpos = 0;
687 if (use_dsp) {
688 rb->dsp_configure(ci.dsp, DSP_RESET, 0);
689 rb->dsp_configure(ci.dsp, DSP_FLUSH, 0);
692 if (checksum)
693 crc32 = 0xffffffff;
695 rebuffertick=0;
696 starttick = *rb->current_tick;
698 codec_playing = true;
699 codec_action = CODEC_ACTION_NULL;
701 rb->codec_thread_do_callback(codec_thread, NULL);
703 /* Wait for codec thread to die */
704 while (codec_playing)
706 int button = pluginlib_getaction(HZ, plugin_contexts,
707 ARRAYLEN(plugin_contexts));
708 if ((button == TESTCODEC_EXITBUTTON) || (button == TESTCODEC_EXITBUTTON2))
710 codec_action = CODEC_ACTION_HALT;
711 break;
714 rb->snprintf(str,sizeof(str),"%d of %d",elapsed,(int)track.id3.length);
715 log_text(str,false);
717 ticks = endtick - starttick;
719 /* Be sure it is done */
720 rb->codec_thread_do_callback(NULL, NULL);
721 rb->backlight_on();
722 log_text(str,true);
724 if (codec_action == CODEC_ACTION_HALT)
726 /* User aborted test */
728 else if (checksum)
730 rb->snprintf(str, sizeof(str), "CRC32 - %08x", (unsigned)crc32);
731 log_text(str,true);
733 else if (wavinfo.fd < 0)
735 /* Display benchmark information */
736 rb->snprintf(str,sizeof(str),"Decode time - %d.%02ds",(int)ticks/100,(int)ticks%100);
737 log_text(str,true);
739 duration = track.id3.length / 10;
740 rb->snprintf(str,sizeof(str),"File duration - %d.%02ds",(int)duration/100,(int)duration%100);
741 log_text(str,true);
743 if (ticks > 0)
744 speed = duration * 10000 / ticks;
745 else
746 speed = 0;
748 rb->snprintf(str,sizeof(str),"%d.%02d%% realtime",(int)speed/100,(int)speed%100);
749 log_text(str,true);
751 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
752 /* show effective clockrate in MHz needed for realtime decoding */
753 if (speed > 0)
755 int freq;
756 freq = *rb->cpu_frequency;
758 speed = freq / speed;
759 rb->snprintf(str,sizeof(str),"%d.%02dMHz needed for realtime",
760 (int)speed/100,(int)speed%100);
761 log_text(str,true);
763 #endif
766 res = PLUGIN_OK;
768 exit:
769 rb->backlight_on();
771 if (fd >= 0)
773 rb->close(fd);
776 return res;
779 #ifdef HAVE_TOUCHSCREEN
780 void cleanup(void)
782 rb->screens[0]->set_viewport(NULL);
784 #endif
786 void plugin_quit(void)
788 int btn;
789 #ifdef HAVE_TOUCHSCREEN
790 static struct touchbutton button[] = {{
791 .action = ACTION_STD_OK,
792 .title = "OK",
793 /* viewport runtime initialized, rest false/NULL */
795 struct viewport *vp = &button[0].vp;
796 struct screen *lcd = rb->screens[SCREEN_MAIN];
797 rb->viewport_set_defaults(vp, SCREEN_MAIN);
798 const int border = 10;
799 const int height = 50;
801 lcd->set_viewport(vp);
802 /* button matches the bottom center in the grid */
803 vp->x = lcd->lcdwidth/3;
804 vp->width = lcd->lcdwidth/3;
805 vp->height = height;
806 vp->y = lcd->lcdheight - height - border;
808 touchbutton_draw(button, ARRAYLEN(button));
809 lcd->update_viewport();
810 if (rb->touchscreen_get_mode() == TOUCHSCREEN_POINT)
812 while (codec_action != CODEC_ACTION_HALT &&
813 touchbutton_get(button, ARRAYLEN(button)) != ACTION_STD_OK);
815 else
816 #endif
817 do {
818 btn = pluginlib_getaction(TIMEOUT_BLOCK, plugin_contexts,
819 ARRAYLEN(plugin_contexts));
820 exit_on_usb(btn);
821 } while ((codec_action != CODEC_ACTION_HALT)
822 && (btn != TESTCODEC_EXITBUTTON)
823 && (btn != TESTCODEC_EXITBUTTON2));
826 /* plugin entry point */
827 enum plugin_status plugin_start(const void* parameter)
829 int result, selection = 0;
830 enum plugin_status res = PLUGIN_OK;
831 int scandir;
832 struct dirent *entry;
833 DIR* dir;
834 char* ch;
835 char dirpath[MAX_PATH];
836 char filename[MAX_PATH];
837 size_t buffer_size;
839 if (parameter == NULL)
841 rb->splash(HZ*2, "No File");
842 return PLUGIN_ERROR;
845 wavbuffer = rb->plugin_get_buffer(&buffer_size);
846 dspbuffer = wavbuffer + buffer_size / 2;
847 dspbuffer_count = (buffer_size - (dspbuffer - wavbuffer)) /
848 (2 * sizeof (int16_t));
850 codec_mallocbuf = rb->plugin_get_audio_buffer(&audiosize);
851 /* Align codec_mallocbuf to pointer size, tlsf wants that */
852 codec_mallocbuf = (void*)(((intptr_t)codec_mallocbuf +
853 sizeof(intptr_t)-1) & ~(sizeof(intptr_t)-1));
854 audiobuf = SKIPBYTES(codec_mallocbuf, CODEC_SIZE);
855 audiosize -= CODEC_SIZE;
857 rb->lcd_clear_display();
858 rb->lcd_update();
860 #ifdef HAVE_TOUCHSCREEN
861 rb->touchscreen_set_mode(rb->global_settings->touch_mode);
862 #endif
864 enum
866 SPEED_TEST = 0,
867 SPEED_TEST_DIR,
868 WRITE_WAV,
869 SPEED_TEST_WITH_DSP,
870 SPEED_TEST_DIR_WITH_DSP,
871 WRITE_WAV_WITH_DSP,
872 CHECKSUM,
873 CHECKSUM_DIR,
874 QUIT,
875 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
876 BOOST,
877 #endif
880 MENUITEM_STRINGLIST(
881 menu, "test_codec", NULL,
882 "Speed test",
883 "Speed test folder",
884 "Write WAV",
885 "Speed test with DSP",
886 "Speed test folder with DSP",
887 "Write WAV with DSP",
888 "Checksum",
889 "Checksum folder",
890 "Quit",
891 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
892 "Boosting",
893 #endif
897 show_menu:
898 rb->lcd_clear_display();
900 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
901 menu:
902 #endif
904 result = rb->do_menu(&menu, &selection, NULL, false);
906 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
907 if (result == BOOST)
909 rb->set_option("Boosting", &boost, INT,
910 boost_settings, 2, NULL);
911 goto menu;
913 if(boost)
914 rb->cpu_boost(true);
915 #endif
917 if (result == QUIT)
919 res = PLUGIN_OK;
920 goto exit;
923 scandir = 0;
925 /* Map test runs with checksum calcualtion to standard runs
926 * SPEED_TEST and SPEED_TEST_DIR and set the 'checksum' flag. */
927 if ((checksum = (result == CHECKSUM ||
928 result == CHECKSUM_DIR)))
929 result -= 6;
931 /* Map test runs with DSP to standard runs SPEED_TEST,
932 * SPEED_TEST_DIR and WRITE_WAV and set the 'use_dsp' flag. */
933 if ((use_dsp = (result >= SPEED_TEST_WITH_DSP &&
934 result <= WRITE_WAV_WITH_DSP)))
935 result -= 3;
937 if (result == SPEED_TEST) {
938 wavinfo.fd = -1;
939 log_init(false);
940 } else if (result == SPEED_TEST_DIR) {
941 wavinfo.fd = -1;
942 scandir = 1;
944 /* Only create a log file when we are testing a folder */
945 if (!log_init(true)) {
946 rb->splash(HZ*2, "Cannot create logfile");
947 res = PLUGIN_ERROR;
948 goto exit;
950 } else if (result == WRITE_WAV) {
951 log_init(false);
952 init_wav("/test.wav");
953 if (wavinfo.fd < 0) {
954 rb->splash(HZ*2, "Cannot create /test.wav");
955 res = PLUGIN_ERROR;
956 goto exit;
958 } else if (result == MENU_ATTACHED_USB) {
959 res = PLUGIN_USB_CONNECTED;
960 goto exit;
961 } else if (result < 0) {
962 res = PLUGIN_OK;
963 goto exit;
966 if (scandir) {
967 /* Test all files in the same directory as the file selected by the
968 user */
970 rb->strlcpy(dirpath,parameter,sizeof(dirpath));
971 ch = rb->strrchr(dirpath,'/');
972 ch[1]=0;
974 DEBUGF("Scanning directory \"%s\"\n",dirpath);
975 dir = rb->opendir(dirpath);
976 if (dir) {
977 entry = rb->readdir(dir);
978 while (entry) {
979 struct dirinfo info = rb->dir_get_info(dir, entry);
980 if (!(info.attribute & ATTR_DIRECTORY)) {
981 rb->snprintf(filename,sizeof(filename),"%s%s",dirpath,entry->d_name);
982 test_track(filename);
984 if (codec_action == CODEC_ACTION_HALT)
985 break;
987 log_text("", true);
990 /* Read next entry */
991 entry = rb->readdir(dir);
994 rb->closedir(dir);
996 } else {
997 /* Just test the file */
998 res = test_track(parameter);
1000 /* Close WAV file (if there was one) */
1001 if (wavinfo.fd >= 0) {
1002 close_wav();
1003 log_text("Wrote /test.wav",true);
1006 plugin_quit();
1008 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
1009 if(boost)
1010 rb->cpu_boost(false);
1011 #endif
1013 rb->button_clear_queue();
1014 goto show_menu;
1016 exit:
1017 log_close();
1019 return res;