1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005 David Bryant
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 ****************************************************************************/
23 #include "lib/profile_plugin.h"
26 #include <codecs/libwavpack/wavpack.h>
30 #define SAMPLES_PER_BLOCK 22050
32 static char *audiobuf
;
33 static ssize_t audiobuflen
;
35 static struct wav_header
{
36 char ckID
[4]; /* RIFF chuck header */
40 char fmt_ckID
[4]; /* format chunk header */
42 ushort FormatTag
, NumChannels
;
43 uint32_t SampleRate
, BytesPerSecond
;
44 ushort BlockAlign
, BitsPerSample
;
46 char data_ckID
[4]; /* data chunk header */
48 } raw_header
, native_header
;
50 #define WAV_HEADER_FORMAT "4L44LSSLLSS4L"
52 static void wvupdate (int32_t start_tick
,
54 uint32_t total_samples
,
55 uint32_t samples_converted
,
57 uint32_t bytes_written
)
59 int32_t elapsed_ticks
= *rb
->current_tick
- start_tick
;
60 int compression
= 0, progress
= 0, realtime
= 0;
64 progress
= (int)(((int64_t) samples_converted
* 100 +
65 (total_samples
/2)) / total_samples
);
68 realtime
= (int)(((int64_t) samples_converted
* 100 * HZ
/
69 sample_rate
+ (elapsed_ticks
/2)) / elapsed_ticks
);
72 compression
= (int)(((int64_t)(bytes_read
- bytes_written
) * 100 +
73 (bytes_read
/2)) / bytes_read
);
75 rb
->snprintf(buf
, 32, "elapsed time: %ld secs",
76 (long)(elapsed_ticks
+ (HZ
/2)) / HZ
);
77 rb
->lcd_puts(0, 2, (unsigned char *)buf
);
79 rb
->snprintf(buf
, 32, "progress: %d%%", progress
);
80 rb
->lcd_puts(0, 4, (unsigned char *)buf
);
82 rb
->snprintf(buf
, 32, "realtime: %d%% ", realtime
);
83 rb
->lcd_puts(0, 6, (unsigned char *)buf
);
85 rb
->snprintf(buf
, 32, "compression: %d%% ", compression
);
86 rb
->lcd_puts(0, 8, (unsigned char *)buf
);
88 #ifdef HAVE_LCD_BITMAP
93 #define TEMP_SAMPLES 4096
95 static int32_t temp_buffer
[TEMP_SAMPLES
] IDATA_ATTR
;
97 static int wav2wv(const char *infile
)
99 int in_fd
, out_fd
, num_chans
, error
= false, last_buttons
;
100 uint32_t total_bytes_read
= 0, total_bytes_written
= 0;
101 uint32_t total_samples
, samples_remaining
;
102 int32_t *input_buffer
= (int32_t *) audiobuf
;
103 unsigned char *output_buffer
= (unsigned char *)(audiobuf
+ 0x100000);
104 char outfile
[MAX_PATH
];
105 const char *inextension
;
107 WavpackConfig config
;
111 rb
->lcd_clear_display();
112 rb
->lcd_puts_scroll(0, 0, (unsigned char *)infile
);
113 #ifdef HAVE_LCD_BITMAP
117 last_buttons
= rb
->button_status ();
118 start_tick
= *rb
->current_tick
;
119 inextension
= infile
+ rb
->strlen(infile
) - 3;
120 if (rb
->strcasecmp (inextension
, "wav")) {
121 rb
->splash(HZ
*2, "only for wav files!");
125 in_fd
= rb
->open(infile
, O_RDONLY
);
128 rb
->splash(HZ
*2, "could not open file!");
132 if (rb
->read (in_fd
, &raw_header
, sizeof (raw_header
)) != sizeof (raw_header
)) {
133 rb
->splash(HZ
*2, "could not read file!");
137 total_bytes_read
+= sizeof (raw_header
);
138 rb
->memcpy (&native_header
, &raw_header
, sizeof (raw_header
));
139 little_endian_to_native (&native_header
, WAV_HEADER_FORMAT
);
141 if (rb
->strncmp (native_header
.ckID
, "RIFF", 4) ||
142 rb
->strncmp (native_header
.fmt_ckID
, "fmt ", 4) ||
143 rb
->strncmp (native_header
.data_ckID
, "data", 4) ||
144 native_header
.FormatTag
!= 1 || native_header
.BitsPerSample
!= 16) {
145 rb
->splash(HZ
*2, "incompatible wav file!");
149 wpc
= WavpackOpenFileOutput ();
151 rb
->memset (&config
, 0, sizeof (config
));
152 config
.bits_per_sample
= 16;
153 config
.bytes_per_sample
= 2;
154 config
.sample_rate
= native_header
.SampleRate
;
155 num_chans
= config
.num_channels
= native_header
.NumChannels
;
156 total_samples
= native_header
.data_ckSize
/ native_header
.BlockAlign
;
158 /* config.flags |= CONFIG_HIGH_FLAG; */
160 if (!WavpackSetConfiguration (wpc
, &config
, total_samples
)) {
161 rb
->splash(HZ
*2, "internal error!");
166 WavpackAddWrapper (wpc
, &raw_header
, sizeof (raw_header
));
168 rb
->strcpy(outfile
, infile
);
169 outextension
= outfile
+ rb
->strlen(outfile
) - 3;
170 outextension
[1] = outextension
[2];
172 out_fd
= rb
->creat(outfile
, 0666);
175 rb
->splash(HZ
*2, "could not create file!");
180 wvupdate (start_tick
, native_header
.SampleRate
, total_samples
, 0, 0, 0);
182 for (samples_remaining
= total_samples
; samples_remaining
;) {
183 uint32_t samples_count
, samples_to_pack
, bytes_count
;
188 samples_count
= SAMPLES_PER_BLOCK
;
190 if (samples_count
> samples_remaining
)
191 samples_count
= samples_remaining
;
193 bytes_count
= samples_count
* num_chans
* 2;
195 if (rb
->read (in_fd
, input_buffer
, bytes_count
) != (int32_t) bytes_count
) {
196 rb
->splash(HZ
*2, "could not read file!");
201 total_bytes_read
+= bytes_count
;
202 WavpackStartBlock (wpc
, output_buffer
, output_buffer
+ 0x100000);
203 samples_to_pack
= samples_count
;
204 cp
= (signed char *) input_buffer
;
206 while (samples_to_pack
) {
207 uint32_t samples_this_pass
= TEMP_SAMPLES
/ num_chans
;
209 if (samples_this_pass
> samples_to_pack
)
210 samples_this_pass
= samples_to_pack
;
213 cnt
= samples_this_pass
;
217 value
= *cp
++ & 0xff;
220 value
= *cp
++ & 0xff;
226 value
= *cp
++ & 0xff;
231 if (!WavpackPackSamples (wpc
, temp_buffer
, samples_this_pass
)) {
232 rb
->splash(HZ
*2, "internal error!");
237 samples_to_pack
-= samples_this_pass
;
243 bytes_count
= WavpackFinishBlock (wpc
);
245 if (rb
->write (out_fd
, output_buffer
, bytes_count
) != (int32_t) bytes_count
) {
246 rb
->splash(HZ
*2, "could not write file!");
251 total_bytes_written
+= bytes_count
;
252 samples_remaining
-= samples_count
;
254 wvupdate (start_tick
, native_header
.SampleRate
, total_samples
,
255 total_samples
- samples_remaining
, total_bytes_read
, total_bytes_written
);
257 buttons
= rb
->button_status ();
259 if (last_buttons
== BUTTON_NONE
&& buttons
!= BUTTON_NONE
) {
260 rb
->splash(HZ
*2, "operation aborted!");
265 last_buttons
= buttons
;
272 rb
->remove (outfile
);
275 rb
->splash(HZ
*3, "operation successful");
280 enum plugin_status
plugin_start(const void *parameter
)
285 audiobuf
= rb
->plugin_get_audio_buffer((size_t *)&audiobuflen
);
287 if (audiobuflen
< 0x200000) {
288 rb
->splash(HZ
*2, "not enough memory!");
292 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
298 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
299 rb
->cpu_boost(false);
301 /* Return PLUGIN_USB_CONNECTED to force a file-tree refresh */
302 return PLUGIN_USB_CONNECTED
;