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;
63 progress
= (int)(((int64_t) samples_converted
* 100 +
64 (total_samples
/2)) / total_samples
);
67 realtime
= (int)(((int64_t) samples_converted
* 100 * HZ
/
68 sample_rate
+ (elapsed_ticks
/2)) / elapsed_ticks
);
71 compression
= (int)(((int64_t)(bytes_read
- bytes_written
) * 100 +
72 (bytes_read
/2)) / bytes_read
);
74 rb
->lcd_putsf(0, 2, "elapsed time: %ld secs",
75 (long)(elapsed_ticks
+ (HZ
/2)) / HZ
);
76 rb
->lcd_putsf(0, 4, "progress: %d%%", progress
);
77 rb
->lcd_putsf(0, 6, "realtime: %d%% ", realtime
);
78 rb
->lcd_putsf(0, 8, "compression: %d%% ", compression
);
80 #ifdef HAVE_LCD_BITMAP
85 #define TEMP_SAMPLES 4096
87 static int32_t temp_buffer
[TEMP_SAMPLES
] IDATA_ATTR
;
89 static int wav2wv(const char *infile
)
91 int in_fd
, out_fd
, num_chans
, error
= false, last_buttons
;
92 uint32_t total_bytes_read
= 0, total_bytes_written
= 0;
93 uint32_t total_samples
, samples_remaining
;
94 int32_t *input_buffer
= (int32_t *) audiobuf
;
95 unsigned char *output_buffer
= (unsigned char *)(audiobuf
+ 0x100000);
96 char outfile
[MAX_PATH
];
97 const char *inextension
;
103 rb
->lcd_clear_display();
104 rb
->lcd_puts_scroll(0, 0, (unsigned char *)infile
);
105 #ifdef HAVE_LCD_BITMAP
109 last_buttons
= rb
->button_status ();
110 start_tick
= *rb
->current_tick
;
111 inextension
= infile
+ rb
->strlen(infile
) - 3;
112 if (rb
->strcasecmp (inextension
, "wav")) {
113 rb
->splash(HZ
*2, "only for wav files!");
117 in_fd
= rb
->open(infile
, O_RDONLY
);
120 rb
->splash(HZ
*2, "could not open file!");
124 if (rb
->read (in_fd
, &raw_header
, sizeof (raw_header
)) != sizeof (raw_header
)) {
125 rb
->splash(HZ
*2, "could not read file!");
130 total_bytes_read
+= sizeof (raw_header
);
131 rb
->memcpy (&native_header
, &raw_header
, sizeof (raw_header
));
132 little_endian_to_native (&native_header
, WAV_HEADER_FORMAT
);
134 if (rb
->strncmp (native_header
.ckID
, "RIFF", 4) ||
135 rb
->strncmp (native_header
.fmt_ckID
, "fmt ", 4) ||
136 rb
->strncmp (native_header
.data_ckID
, "data", 4) ||
137 native_header
.FormatTag
!= 1 || native_header
.BitsPerSample
!= 16) {
138 rb
->splash(HZ
*2, "incompatible wav file!");
143 wpc
= WavpackOpenFileOutput ();
145 rb
->memset (&config
, 0, sizeof (config
));
146 config
.bits_per_sample
= 16;
147 config
.bytes_per_sample
= 2;
148 config
.sample_rate
= native_header
.SampleRate
;
149 num_chans
= config
.num_channels
= native_header
.NumChannels
;
150 total_samples
= native_header
.data_ckSize
/ native_header
.BlockAlign
;
152 /* config.flags |= CONFIG_HIGH_FLAG; */
154 if (!WavpackSetConfiguration (wpc
, &config
, total_samples
)) {
155 rb
->splash(HZ
*2, "internal error!");
160 WavpackAddWrapper (wpc
, &raw_header
, sizeof (raw_header
));
162 rb
->strcpy(outfile
, infile
);
163 outextension
= outfile
+ rb
->strlen(outfile
) - 3;
164 outextension
[1] = outextension
[2];
166 out_fd
= rb
->creat(outfile
, 0666);
169 rb
->splash(HZ
*2, "could not create file!");
174 wvupdate (start_tick
, native_header
.SampleRate
, total_samples
, 0, 0, 0);
176 for (samples_remaining
= total_samples
; samples_remaining
;) {
177 uint32_t samples_count
, samples_to_pack
, bytes_count
;
182 samples_count
= SAMPLES_PER_BLOCK
;
184 if (samples_count
> samples_remaining
)
185 samples_count
= samples_remaining
;
187 bytes_count
= samples_count
* num_chans
* 2;
189 if (rb
->read (in_fd
, input_buffer
, bytes_count
) != (int32_t) bytes_count
) {
190 rb
->splash(HZ
*2, "could not read file!");
195 total_bytes_read
+= bytes_count
;
196 WavpackStartBlock (wpc
, output_buffer
, output_buffer
+ 0x100000);
197 samples_to_pack
= samples_count
;
198 cp
= (signed char *) input_buffer
;
200 while (samples_to_pack
) {
201 uint32_t samples_this_pass
= TEMP_SAMPLES
/ num_chans
;
203 if (samples_this_pass
> samples_to_pack
)
204 samples_this_pass
= samples_to_pack
;
207 cnt
= samples_this_pass
;
211 value
= *cp
++ & 0xff;
214 value
= *cp
++ & 0xff;
220 value
= *cp
++ & 0xff;
225 if (!WavpackPackSamples (wpc
, temp_buffer
, samples_this_pass
)) {
226 rb
->splash(HZ
*2, "internal error!");
231 samples_to_pack
-= samples_this_pass
;
237 bytes_count
= WavpackFinishBlock (wpc
);
239 if (rb
->write (out_fd
, output_buffer
, bytes_count
) != (int32_t) bytes_count
) {
240 rb
->splash(HZ
*2, "could not write file!");
245 total_bytes_written
+= bytes_count
;
246 samples_remaining
-= samples_count
;
248 wvupdate (start_tick
, native_header
.SampleRate
, total_samples
,
249 total_samples
- samples_remaining
, total_bytes_read
, total_bytes_written
);
251 buttons
= rb
->button_status ();
253 if (last_buttons
== BUTTON_NONE
&& buttons
!= BUTTON_NONE
) {
254 rb
->splash(HZ
*2, "operation aborted!");
259 last_buttons
= buttons
;
266 rb
->remove (outfile
);
269 rb
->splash(HZ
*3, "operation successful");
271 rb
->reload_directory();
275 enum plugin_status
plugin_start(const void *parameter
)
280 audiobuf
= rb
->plugin_get_audio_buffer((size_t *)&audiobuflen
);
282 if (audiobuflen
< 0x200000) {
283 rb
->splash(HZ
*2, "not enough memory!");
287 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
293 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
294 rb
->cpu_boost(false);