1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005 David Bryant
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 ****************************************************************************/
21 #include "lib/profile_plugin.h"
24 #include <codecs/libwavpack/wavpack.h>
28 #define SAMPLES_PER_BLOCK 22050
30 static struct plugin_api
* rb
;
32 void *memset(void *s
, int c
, size_t n
) {
33 return(rb
->memset(s
,c
,n
));
36 void *memcpy(void *dest
, const void *src
, size_t n
) {
37 return(rb
->memcpy(dest
,src
,n
));
40 static char *audiobuf
;
41 static int audiobuflen
;
43 static struct wav_header
{
44 char ckID
[4]; /* RIFF chuck header */
48 char fmt_ckID
[4]; /* format chunk header */
50 ushort FormatTag
, NumChannels
;
51 uint32_t SampleRate
, BytesPerSecond
;
52 ushort BlockAlign
, BitsPerSample
;
54 char data_ckID
[4]; /* data chunk header */
56 } raw_header
, native_header
;
58 #define WAV_HEADER_FORMAT "4L44LSSLLSS4L"
60 static void wvupdate (int32_t start_tick
,
62 uint32_t total_samples
,
63 uint32_t samples_converted
,
65 uint32_t bytes_written
)
67 int32_t elapsed_ticks
= *rb
->current_tick
- start_tick
;
68 int compression
= 0, progress
= 0, realtime
= 0;
72 progress
= (int)(((int64_t) samples_converted
* 100 +
73 (total_samples
/2)) / total_samples
);
76 realtime
= (int)(((int64_t) samples_converted
* 100 * HZ
/
77 sample_rate
+ (elapsed_ticks
/2)) / elapsed_ticks
);
80 compression
= (int)(((int64_t)(bytes_read
- bytes_written
) * 100 +
81 (bytes_read
/2)) / bytes_read
);
83 rb
->snprintf(buf
, 32, "elapsed time: %d secs", (elapsed_ticks
+ (HZ
/2)) / HZ
);
84 rb
->lcd_puts(0, 2, (unsigned char *)buf
);
86 rb
->snprintf(buf
, 32, "progress: %d%%", progress
);
87 rb
->lcd_puts(0, 4, (unsigned char *)buf
);
89 rb
->snprintf(buf
, 32, "realtime: %d%% ", realtime
);
90 rb
->lcd_puts(0, 6, (unsigned char *)buf
);
92 rb
->snprintf(buf
, 32, "compression: %d%% ", compression
);
93 rb
->lcd_puts(0, 8, (unsigned char *)buf
);
95 #ifdef HAVE_LCD_BITMAP
100 #define TEMP_SAMPLES 4096
102 static int32_t temp_buffer
[TEMP_SAMPLES
] IDATA_ATTR
;
104 static int wav2wv (char *filename
)
106 int in_fd
, out_fd
, num_chans
, error
= false, last_buttons
;
107 unsigned int32_t total_bytes_read
= 0, total_bytes_written
= 0;
108 unsigned int32_t total_samples
, samples_remaining
;
109 int32_t *input_buffer
= (int32_t *) audiobuf
;
110 unsigned char *output_buffer
= (unsigned char *)(audiobuf
+ 0x100000);
111 char *extension
, save_a
;
112 WavpackConfig config
;
116 rb
->lcd_clear_display();
117 rb
->lcd_puts_scroll(0, 0, (unsigned char *)filename
);
118 #ifdef HAVE_LCD_BITMAP
122 last_buttons
= rb
->button_status ();
123 start_tick
= *rb
->current_tick
;
124 extension
= filename
+ rb
->strlen (filename
) - 3;
126 if (rb
->strcasecmp (extension
, "wav")) {
127 rb
->splash(HZ
*2, true, "only for wav files!");
131 in_fd
= rb
->open(filename
, O_RDONLY
);
134 rb
->splash(HZ
*2, true, "could not open file!");
138 if (rb
->read (in_fd
, &raw_header
, sizeof (raw_header
)) != sizeof (raw_header
)) {
139 rb
->splash(HZ
*2, true, "could not read file!");
143 total_bytes_read
+= sizeof (raw_header
);
144 rb
->memcpy (&native_header
, &raw_header
, sizeof (raw_header
));
145 little_endian_to_native (&native_header
, WAV_HEADER_FORMAT
);
147 if (rb
->strncmp (native_header
.ckID
, "RIFF", 4) ||
148 rb
->strncmp (native_header
.fmt_ckID
, "fmt ", 4) ||
149 rb
->strncmp (native_header
.data_ckID
, "data", 4) ||
150 native_header
.FormatTag
!= 1 || native_header
.BitsPerSample
!= 16) {
151 rb
->splash(HZ
*2, true, "incompatible wav file!");
155 wpc
= WavpackOpenFileOutput ();
157 rb
->memset (&config
, 0, sizeof (config
));
158 config
.bits_per_sample
= 16;
159 config
.bytes_per_sample
= 2;
160 config
.sample_rate
= native_header
.SampleRate
;
161 num_chans
= config
.num_channels
= native_header
.NumChannels
;
162 total_samples
= native_header
.data_ckSize
/ native_header
.BlockAlign
;
164 /* config.flags |= CONFIG_HIGH_FLAG; */
166 if (!WavpackSetConfiguration (wpc
, &config
, total_samples
)) {
167 rb
->splash(HZ
*2, true, "internal error!");
172 WavpackAddWrapper (wpc
, &raw_header
, sizeof (raw_header
));
173 save_a
= extension
[1];
174 extension
[1] = extension
[2];
177 out_fd
= rb
->creat (filename
);
179 extension
[2] = extension
[1];
180 extension
[1] = save_a
;
183 rb
->splash(HZ
*2, true, "could not create file!");
188 wvupdate (start_tick
, native_header
.SampleRate
, total_samples
, 0, 0, 0);
190 for (samples_remaining
= total_samples
; samples_remaining
;) {
191 unsigned int32_t samples_count
, samples_to_pack
, bytes_count
;
196 samples_count
= SAMPLES_PER_BLOCK
;
198 if (samples_count
> samples_remaining
)
199 samples_count
= samples_remaining
;
201 bytes_count
= samples_count
* num_chans
* 2;
203 if (rb
->read (in_fd
, input_buffer
, bytes_count
) != (int32_t) bytes_count
) {
204 rb
->splash(HZ
*2, true, "could not read file!");
209 total_bytes_read
+= bytes_count
;
210 WavpackStartBlock (wpc
, output_buffer
, output_buffer
+ 0x100000);
211 samples_to_pack
= samples_count
;
212 cp
= (signed char *) input_buffer
;
214 while (samples_to_pack
) {
215 unsigned int32_t samples_this_pass
= TEMP_SAMPLES
/ num_chans
;
217 if (samples_this_pass
> samples_to_pack
)
218 samples_this_pass
= samples_to_pack
;
221 cnt
= samples_this_pass
;
225 value
= *cp
++ & 0xff;
228 value
= *cp
++ & 0xff;
234 value
= *cp
++ & 0xff;
239 if (!WavpackPackSamples (wpc
, temp_buffer
, samples_this_pass
)) {
240 rb
->splash(HZ
*2, true, "internal error!");
245 samples_to_pack
-= samples_this_pass
;
251 bytes_count
= WavpackFinishBlock (wpc
);
253 if (rb
->write (out_fd
, output_buffer
, bytes_count
) != (int32_t) bytes_count
) {
254 rb
->splash(HZ
*2, true, "could not write file!");
259 total_bytes_written
+= bytes_count
;
260 samples_remaining
-= samples_count
;
262 wvupdate (start_tick
, native_header
.SampleRate
, total_samples
,
263 total_samples
- samples_remaining
, total_bytes_read
, total_bytes_written
);
265 buttons
= rb
->button_status ();
267 if (last_buttons
== BUTTON_NONE
&& buttons
!= BUTTON_NONE
) {
268 rb
->splash(HZ
*2, true, "operation aborted!");
273 last_buttons
= buttons
;
280 save_a
= extension
[1];
281 extension
[1] = extension
[2];
283 rb
->remove (filename
);
284 extension
[2] = extension
[1];
285 extension
[1] = save_a
;
288 rb
->splash(HZ
*3, true, "operation successful");
293 enum plugin_status
plugin_start(struct plugin_api
* api
, void *parameter
)
296 /* This doesn't start profiling or anything, it just gives the
297 * profiling functions that are compiled in someplace to call,
298 * this is needed here to let this compile with profiling support
299 * since it calls code from a codec that is compiled with profiling
309 audiobuf
= rb
->plugin_get_audio_buffer(&audiobuflen
);
311 if (audiobuflen
< 0x200000) {
312 rb
->splash(HZ
*2, true, "not enough memory!");
316 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
322 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
323 rb
->cpu_boost(false);
325 /* Return PLUGIN_USB_CONNECTED to force a file-tree refresh */
326 return PLUGIN_USB_CONNECTED
;