1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
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
45 #define TESTCODEC_EXITBUTTON BUTTON_SELECT
48 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
49 static unsigned int boost
=1;
51 static const struct opt_items boost_settings
[2] = {
58 /* Log functions copied from test_disk.c */
60 static int max_line
= 0;
61 static int log_fd
= -1;
63 static void log_close(void)
69 static bool log_init(bool use_logfile
)
72 char logfilename
[MAX_PATH
];
74 rb
->lcd_getstringsize("A", NULL
, &h
);
75 max_line
= LCD_HEIGHT
/ h
;
77 rb
->lcd_clear_display();
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
));
86 rb
->create_numbered_filename(logfilename
, "/", "test_codec_log_", ".txt",
87 2 IF_CNFN_NUM_(, NULL
));
89 log_fd
= rb
->open(logfilename
, O_RDWR
|O_CREAT
|O_TRUNC
, 0666);
96 static void log_text(char *text
, bool advance
)
98 rb
->lcd_puts(0, line
, text
);
102 if (++line
>= max_line
)
105 rb
->fdprintf(log_fd
, "%s\n", text
);
119 static void* audiobuf
;
120 static void* codec_mallocbuf
;
121 static size_t audiosize
;
122 static size_t audiobufsize
;
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
;
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
)
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
)
175 buf
[1] = (x
& 0xff00) >> 8;
176 buf
[2] = (x
& 0xff0000) >> 16;
179 static inline void int2le16(unsigned char* buf
, int16_t x
)
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);
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
));
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
);
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
;
245 int out_count
= rb
->dsp_output_count(ci
.dsp
, count
);
247 int inp_count
= rb
->dsp_input_count(ci
.dsp
, out_count
);
252 if (inp_count
> count
)
255 out_count
= rb
->dsp_process(ci
.dsp
, dest
, src
, inp_count
);
260 written_count
+= out_count
;
261 dest
+= out_count
* 4;
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);
278 static void pcmbuf_insert_null(const void *ch1
, const void *ch2
, int count
)
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
;
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
);
319 /*keep track of how much time we spent buffering*/
320 rebuffertick
+= *rb
->current_tick
-temp
;
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();
341 count
= process_dsp(ch1
, ch2
, count
);
342 wavinfo
.totalsamples
+= count
;
345 unsigned char *s
= dspbuffer
, *d
= dspbuffer
;
356 crc32
= rb
->crc_32(dspbuffer
, count
* 2 * channels
, crc32
);
358 rb
->write(wavinfo
.fd
, dspbuffer
, count
* 2 * channels
);
362 if (wavinfo
.sampledepth
<= 16) {
366 switch(wavinfo
.stereomode
)
368 case STEREO_INTERLEAVED
:
370 int2le16(p
,*data1_16
++);
372 int2le16(p
,*data1_16
++);
377 case STEREO_NONINTERLEAVED
:
379 int2le16(p
,*data1_16
++);
381 int2le16(p
,*data2_16
++);
389 int2le16(p
,*data1_16
++);
398 switch(wavinfo
.stereomode
)
400 case STEREO_INTERLEAVED
:
402 int2le16(p
, clip_sample((*data1_32
++ + dc_bias
) >> scale
));
404 int2le16(p
, clip_sample((*data1_32
++ + dc_bias
) >> scale
));
409 case STEREO_NONINTERLEAVED
:
411 int2le16(p
, clip_sample((*data1_32
++ + dc_bias
) >> scale
));
413 int2le16(p
, clip_sample((*data2_32
++ + dc_bias
) >> scale
));
421 int2le16(p
, clip_sample((*data1_32
++ + dc_bias
) >> scale
));
428 wavinfo
.totalsamples
+= count
;
430 crc32
= rb
->crc_32(wavbuffer
, p
- wavbuffer
, crc32
);
432 rb
->write(wavinfo
.fd
, wavbuffer
, p
- wavbuffer
);
436 /* Set song position in WPS (value in ms). */
437 static void set_elapsed(unsigned long 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
)
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
;
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
)
490 ci
.id3
->offset
= ci
.curpos
;
494 /* Seek file buffer to position <newpos> beginning of file. */
495 static bool seek_buffer(size_t newpos
)
502 /* Codec should call this function when it has done the seeking. */
503 static void seek_complete(void)
508 /* Codec calls this to know what it should do next. */
509 static enum codec_command_action
get_command(intptr_t *param
)
512 return CODEC_ACTION_NULL
; /* just continue processing */
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
)
526 rb
->dsp_configure(ci
.dsp
, setting
, value
);
529 case DSP_SWITCH_FREQUENCY
:
530 case DSP_SET_FREQUENCY
:
531 DEBUGF("samplerate=%d\n",(int)value
);
532 wavinfo
.samplerate
= (int)value
;
535 case DSP_SET_SAMPLE_DEPTH
:
536 DEBUGF("sampledepth = %d\n",(int)value
);
537 wavinfo
.sampledepth
=(int)value
;
540 case DSP_SET_STEREO_MODE
:
541 DEBUGF("Stereo mode = %d\n",(int)value
);
542 wavinfo
.stereomode
=(int)value
;
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
,
555 ci
.codec_get_buffer
= codec_get_buffer
;
557 if (wavinfo
.fd
>= 0 || checksum
) {
558 ci
.pcmbuf_insert
= pcmbuf_insert_wav_checksum
;
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 --- */
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
;
593 #ifdef ROCKBOX_HAS_LOGF
597 ci
.qsort
= rb
->qsort
;
598 ci
.global_settings
= rb
->global_settings
;
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
;
607 ci
.cpucache_invalidate
= rb
->cpucache_invalidate
;
608 ci
.cpucache_flush
= rb
->cpucache_flush
;
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
;
619 #if defined(CPU_ARM) && (CONFIG_PLATFORM & PLATFORM_NATIVE)
620 ci
.__div0
= rb
->__div0
;
624 static void codec_thread(void)
626 const char* codecname
;
629 codecname
= rb
->get_codec_filename(track
.id3
.codectype
);
632 res
= rb
->codec_load_file(codecname
, &ci
);
636 /* Decode the file */
637 res
= rb
->codec_run_proc();
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
)
651 enum plugin_status res
= PLUGIN_ERROR
;
655 unsigned long duration
;
660 /* Display filename (excluding any path)*/
661 ch
= rb
->strrchr(filename
, '/');
667 rb
->snprintf(str
,sizeof(str
),"%s",ch
);
670 log_text("Loading...",false);
672 fd
= rb
->open(filename
,O_RDONLY
);
675 log_text("Cannot open file",true);
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);
690 if (track
.filesize
> audiosize
)
692 audiobufsize
=audiosize
;
696 audiobufsize
=track
.filesize
;
699 n
= rb
->read(fd
, audiobuf
, audiobufsize
);
701 if (n
!= audiobufsize
)
703 log_text("Read failed.",true);
708 /* Initialise the function pointers in the codec API */
711 /* Prepare the codec struct for playing the whole file */
712 ci
.filesize
= track
.filesize
;
717 rb
->dsp_configure(ci
.dsp
, DSP_RESET
, 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
)
733 rb
->snprintf(str
,sizeof(str
),"%d of %d",elapsed
,(int)track
.id3
.length
);
736 ticks
= endtick
- starttick
;
738 /* Be sure it is done */
739 rb
->codec_thread_do_callback(NULL
, NULL
);
745 rb
->snprintf(str
, sizeof(str
), "CRC32 - %08x", (unsigned)crc32
);
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);
754 duration
= track
.id3
.length
/ 10;
755 rb
->snprintf(str
,sizeof(str
),"File duration - %d.%02ds",(int)duration
/100,(int)duration
%100);
759 speed
= duration
* 10000 / ticks
;
763 rb
->snprintf(str
,sizeof(str
),"%d.%02d%% realtime",(int)speed
/100,(int)speed
%100);
766 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
767 /* show effective clockrate in MHz needed for realtime decoding */
770 int freq
= CPUFREQ_MAX
;
772 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
774 freq
= CPUFREQ_NORMAL
;
777 speed
= freq
/ speed
;
778 rb
->snprintf(str
,sizeof(str
),"%d.%02dMHz needed for realtime",
779 (int)speed
/100,(int)speed
%100);
798 #ifdef HAVE_TOUCHSCREEN
801 rb
->screens
[0]->set_viewport(NULL
);
805 void plugin_quit(void)
807 #ifdef HAVE_TOUCHSCREEN
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
;
815 vp
.width
= lcd
->lcdwidth
- 20;
816 vp
.y
= lcd
->lcdheight
- 60;
818 vp
.flags
= VP_FLAG_ALIGN_CENTER
;
820 yoff
= vp
.height
/2 - font_height
/2;
821 lcd
->set_viewport(&vp
);
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();
829 if (rb
->touchscreen_get_mode() == TOUCHSCREEN_POINT
)
833 rb
->get_action(CONTEXT_STD
, TIMEOUT_BLOCK
);
834 if (rb
->action_get_touchscreen_press_in_vp(&x
, &y
, &vp
) & BUTTON_REL
)
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
;
849 struct dirent
*entry
;
852 char dirpath
[MAX_PATH
];
853 char filename
[MAX_PATH
];
856 if (parameter
== NULL
)
858 rb
->splash(HZ
*2, "No File");
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();
879 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
884 SPEED_TEST_DIR_WITH_DSP
,
892 menu
, "test_codec", NULL
,
895 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
899 "Speed test with DSP",
900 "Speed test folder with DSP",
901 "Write WAV with DSP",
909 rb
->lcd_clear_display();
911 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
915 result
= rb
->do_menu(&menu
, &selection
, NULL
, false);
916 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
920 rb
->set_option("Boosting", &boost
, INT
,
921 boost_settings
, 2, NULL
);
936 if ((checksum
= (result
== CHECKSUM
|| result
== CHECKSUM_DIR
)))
937 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
943 if ((use_dsp
= ((result
>= SPEED_TEST_WITH_DSP
)
944 && (result
<= WRITE_WAV_WITH_DSP
)))) {
947 if (result
== SPEED_TEST
) {
950 } else if (result
== SPEED_TEST_DIR
) {
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");
960 } else if (result
== WRITE_WAV
) {
962 init_wav("/test.wav");
963 if (wavinfo
.fd
< 0) {
964 rb
->splash(HZ
*2, "Cannot create /test.wav");
968 } else if (result
== MENU_ATTACHED_USB
) {
969 res
= PLUGIN_USB_CONNECTED
;
971 } else if (result
< 0) {
977 /* Test all files in the same directory as the file selected by the
980 rb
->strlcpy(dirpath
,parameter
,sizeof(dirpath
));
981 ch
= rb
->strrchr(dirpath
,'/');
984 DEBUGF("Scanning directory \"%s\"\n",dirpath
);
985 dir
= rb
->opendir(dirpath
);
987 entry
= rb
->readdir(dir
);
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
);
996 /* Read next entry */
997 entry
= rb
->readdir(dir
);
1003 /* Just test the file */
1004 res
= test_track(parameter
);
1006 /* Close WAV file (if there was one) */
1007 if (wavinfo
.fd
>= 0) {
1009 log_text("Wrote /test.wav",true);
1014 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
1016 rb
->cpu_boost(false);
1019 rb
->button_clear_queue();