1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007 Peter D'Hoye
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
23 static struct plugin_api
* rb
;
25 /* temp byte buffer */
26 uint8_t samples
[10 * 1024]; /* read 10KB at the time */
28 static struct wav_header
33 int8_t formatchunkid
[4];
34 int32_t formatchunksize
;
40 uint16_t bitspersample
;
41 int8_t datachunkid
[4];
42 int32_t datachunksize
;
45 #define WAV_HEADER_FORMAT "4L44LSSLLSS4L"
55 /* TO DO: limit used LCD height, so the waveform isn't streched vertically? */
57 #define LEFTZERO (LCD_HEIGHT / 4)
58 #define RIGHTZERO (3 * (LCD_HEIGHT / 4))
59 #define YSCALE ((0x8000 / (LCD_HEIGHT / 4)) + 1)
62 static char *audiobuf
;
63 static ssize_t audiobuflen
;
64 static uint32_t mempeakcount
= 0;
65 static uint32_t filepeakcount
= 0;
66 static uint32_t fppmp
= 0; /* file peaks per mem peaks */
67 static uint32_t zoomlevel
= 1;
68 static uint32_t leftmargin
= 0;
69 static uint32_t center
= 0;
70 static uint32_t ppp
= 1;
72 /* helper function copied from libwavpack bits.c */
73 void little_endian_to_native (void *data
, char *format
)
75 unsigned char *cp
= (unsigned char *) data
;
80 *(long *)cp
= letoh32(*(long *)cp
);
85 *(short *)cp
= letoh16(*(short *)cp
);
90 if (*format
>= '0' && *format
<= '9')
101 display some info about it
102 store peak info in aufiobuf for display routine */
103 static int readwavpeaks(char *filename
)
105 register uint32_t bytes_read
;
106 register uint32_t fppmp_count
;
107 register int16_t sampleval
;
108 register uint16_t* sampleshort
= NULL
;
111 uint32_t total_bytes_read
= 0;
116 uint32_t peakcount
= 0;
117 struct peakstruct
* peak
= NULL
;
119 if(rb
->strcasecmp (filename
+ rb
->strlen (filename
) - 3, "wav"))
121 rb
->splash(HZ
*2, "Only for wav files!");
125 file
= rb
->open(filename
, O_RDONLY
);
129 rb
->splash(HZ
*2, "Could not open file!");
133 if(rb
->read(file
, &header
, sizeof (header
)) != sizeof (header
))
135 rb
->splash(HZ
*2, "Could not read file!");
140 total_bytes_read
+= sizeof (header
);
141 little_endian_to_native(&header
, WAV_HEADER_FORMAT
);
143 if (rb
->strncmp(header
.chunkid
, "RIFF", 4) ||
144 rb
->strncmp(header
.formatchunkid
, "fmt ", 4) ||
145 rb
->strncmp(header
.datachunkid
, "data", 4) ||
146 (header
.bitspersample
!= 16) ||
147 header
.audioformat
!= 1)
149 rb
->splash(HZ
*2, "Incompatible wav file!");
154 rb
->lcd_clear_display();
155 rb
->lcd_puts(0, 0, "Viewing file:");
156 rb
->lcd_puts_scroll(0, 1, (unsigned char *)filename
);
159 rb
->snprintf(tstr
,127, "Channels: %s",
160 header
.numchannels
== 1 ? "mono" : "stereo");
161 rb
->lcd_puts(0, 2, tstr
);
163 rb
->snprintf(tstr
,127, "Bits/sample: %d", header
.bitspersample
);
164 rb
->lcd_puts(0, 3, tstr
);
166 rb
->snprintf(tstr
,127, "Samplerate: %d Hz", (int)(header
.samplerate
));
167 rb
->lcd_puts(0, 4, tstr
);
169 seconds
= header
.datachunksize
/ header
.byterate
;
170 hours
= seconds
/ 3600;
171 seconds
-= hours
* 3600;
172 minutes
= seconds
/ 60;
173 seconds
-= minutes
* 60;
174 rb
->snprintf(tstr
,127, "Length (hh:mm:ss): %02d:%02d:%02d", hours
,
177 rb
->lcd_puts(0, 5, tstr
);
178 rb
->lcd_puts(0, 6, "Searching for peaks... ");
181 /* calculate room for peaks */
182 filepeakcount
= header
.datachunksize
/
183 (header
.numchannels
* (header
.bitspersample
/ 8));
184 mempeakcount
= audiobuflen
/ sizeof(struct peakstruct
);
185 fppmp
= (filepeakcount
/ mempeakcount
) + 1;
186 peak
= (struct peakstruct
*)audiobuf
;
190 while(total_bytes_read
< (header
.datachunksize
+
191 sizeof(struct wav_header
)))
193 bytes_read
= rb
->read(file
, &samples
, sizeof(samples
));
194 total_bytes_read
+= bytes_read
;
198 rb
->splash(HZ
*2, "File read error!");
202 if(((bytes_read
/4)*4) != bytes_read
)
204 rb
->splash(HZ
*2, "bytes_read/*4 err: %ld",(long int)bytes_read
);
209 sampleshort
= (int16_t*)samples
;
210 sampleval
= letoh16(*sampleshort
);
211 peak
->lmin
= sampleval
;
212 peak
->lmax
= sampleval
;
213 sampleval
= letoh16(*(sampleshort
+1));
214 peak
->rmin
= sampleval
;
215 peak
->rmax
= sampleval
;
219 sampleval
= letoh16(*sampleshort
++);
220 if(sampleval
< peak
->lmin
)
221 peak
->lmin
= sampleval
;
222 else if (sampleval
> peak
->lmax
)
223 peak
->lmax
= sampleval
;
225 sampleval
= letoh16(*sampleshort
++);
226 if(sampleval
< peak
->rmin
)
227 peak
->rmin
= sampleval
;
228 else if (sampleval
> peak
->rmax
)
229 peak
->rmax
= sampleval
;
239 sampleval
= letoh16(*sampleshort
);
240 peak
->lmin
= sampleval
;
241 peak
->lmax
= sampleval
;
242 sampleval
= letoh16(*(sampleshort
+1));
243 peak
->rmin
= sampleval
;
244 peak
->rmax
= sampleval
;
248 /* update progress */
249 rb
->snprintf(tstr
,127, "Searching for peaks... %d%%",(int)
250 (total_bytes_read
/ ((header
.datachunksize
+
251 sizeof(struct wav_header
)) / 100)));
252 rb
->lcd_puts(0, 6, tstr
);
255 /* allow user to abort */
256 if(ACTION_KBD_ABORT
== rb
->get_action(CONTEXT_KEYBOARD
,TIMEOUT_NOBLOCK
))
258 rb
->splash(HZ
*2, "ABORTED");
264 rb
->lcd_puts(0, 6, "Searching for peaks... done");
272 int displaypeaks(void)
275 register int lymin
= INT_MAX
;
276 register int lymax
= INT_MIN
;
277 register int rymin
= INT_MAX
;
278 register int rymax
= INT_MIN
;
279 register unsigned int peakcount
= 0;
280 struct peakstruct
* peak
= (struct peakstruct
*)audiobuf
+ leftmargin
;
283 unsigned org_forecolor
= rb
->lcd_get_foreground();
284 rb
->lcd_set_foreground(LCD_LIGHTGRAY
);
287 if(!zoomlevel
) zoomlevel
= 1;
288 ppp
= (mempeakcount
/ LCD_WIDTH
) / zoomlevel
; /* peaks per pixel */
290 rb
->lcd_clear_display();
292 rb
->lcd_drawline(0, LEFTZERO
- (0x8000 / YSCALE
), LCD_WIDTH
-1,
293 LEFTZERO
- (0x8000 / YSCALE
));
294 rb
->lcd_drawline(0, LEFTZERO
, LCD_WIDTH
-1, LEFTZERO
);
295 rb
->lcd_drawline(0, LEFTZERO
+ (0x8000 / YSCALE
), LCD_WIDTH
-1,
296 LEFTZERO
+ (0x8000 / YSCALE
));
297 rb
->lcd_drawline(0, RIGHTZERO
- (0x8000 / YSCALE
), LCD_WIDTH
-1,
298 RIGHTZERO
- (0x8000 / YSCALE
));
299 rb
->lcd_drawline(0, RIGHTZERO
, LCD_WIDTH
-1, RIGHTZERO
);
300 rb
->lcd_drawline(0, RIGHTZERO
+ (0x8000 / YSCALE
), LCD_WIDTH
-1,
301 RIGHTZERO
+ (0x8000 / YSCALE
));
304 rb
->lcd_set_foreground(LCD_BLACK
);
308 rb
->lcd_drawline(leftmargin
/ (mempeakcount
/ LCD_WIDTH
), LCD_HEIGHT
/ 2,
309 (leftmargin
/ (mempeakcount
/ LCD_WIDTH
)) +
310 (LCD_WIDTH
/ zoomlevel
),
313 while((x
< LCD_WIDTH
) && (peakcount
< mempeakcount
))
315 if(peak
->lmin
< lymin
)
317 if(peak
->lmax
> lymax
)
319 if(peak
->rmin
< rymin
)
321 if(peak
->rmax
> rymax
)
324 if(0 == (peakcount
% ppp
))
327 rb
->lcd_drawline(x
, LEFTZERO
- (lymax
/ YSCALE
), x
,
328 LEFTZERO
- (lymin
/ YSCALE
));
329 rb
->lcd_drawline(x
, RIGHTZERO
- (rymax
/ YSCALE
), x
,
330 RIGHTZERO
- (rymin
/ YSCALE
));
342 rb
->lcd_set_foreground(org_forecolor
);
350 rb
->lcd_clear_display();
351 rb
->lcd_puts(0, 0, "WAVVIEW USAGE:");
352 rb
->lcd_puts(0, 2, "up/down: zoom out/in");
353 rb
->lcd_puts(0, 3, "left/right: pan left/right");
354 rb
->lcd_puts(0, 4, "select: refresh/continue");
355 rb
->lcd_puts(0, 5, "stop/off: quit");
359 enum plugin_status
plugin_start(struct plugin_api
* api
, void *parameter
)
361 unsigned int quit
= 0;
362 unsigned int action
= 0;
363 unsigned int dodisplay
= 1;
370 audiobuf
= rb
->plugin_get_audio_buffer((size_t *)&audiobuflen
);
374 rb
->splash(HZ
*2, "unable to get audio buffer!");
378 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
382 retval
= readwavpeaks(parameter
); /* read WAV file and create peaks array */
384 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
385 rb
->cpu_boost(false);
391 /* press any key to continue */
394 retval
= rb
->get_action(CONTEXT_KEYBOARD
,TIMEOUT_BLOCK
);
395 if(ACTION_KBD_ABORT
== retval
)
397 else if(ACTION_KBD_SELECT
== retval
)
401 /* start with the overview */
408 center
= mempeakcount
/ 2;
416 if(center
< (mempeakcount
/ (zoomlevel
* 2)))
417 center
= mempeakcount
/ (zoomlevel
* 2);
418 if(center
> (((zoomlevel
* 2) - 1) * (mempeakcount
/
420 center
= ((zoomlevel
* 2) - 1) * (mempeakcount
/
422 leftmargin
= center
- (mempeakcount
/ (zoomlevel
* 2));
425 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
432 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
433 rb
->cpu_boost(false);
436 action
= rb
->get_action(CONTEXT_KEYBOARD
, TIMEOUT_BLOCK
);
443 rb
->splash(HZ
/2, "ZOOM: %dx",(int)zoomlevel
);
445 case ACTION_KBD_DOWN
:
446 if(zoomlevel
< (mempeakcount
/ LCD_WIDTH
/ 2))
448 rb
->splash(HZ
/2, "ZOOM: %dx",(int)zoomlevel
);
450 case ACTION_KBD_LEFT
:
451 center
-= 10 * (mempeakcount
/ LCD_WIDTH
) / zoomlevel
;
453 case ACTION_KBD_RIGHT
:
454 center
+= 10 * (mempeakcount
/ LCD_WIDTH
) / zoomlevel
;
456 case ACTION_KBD_ABORT
:
459 case ACTION_KBD_SELECT
:
462 case ACTION_KBD_PAGE_FLIP
:
463 /* menu key shows help */
467 retval
= rb
->get_action(CONTEXT_KEYBOARD
,TIMEOUT_BLOCK
);
468 if((ACTION_KBD_SELECT
== retval
) ||
469 (ACTION_KBD_ABORT
== retval
))