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 ssize_t 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: %ld secs",
84 (long)(elapsed_ticks
+ (HZ
/2)) / HZ
);
85 rb
->lcd_puts(0, 2, (unsigned char *)buf
);
87 rb
->snprintf(buf
, 32, "progress: %d%%", progress
);
88 rb
->lcd_puts(0, 4, (unsigned char *)buf
);
90 rb
->snprintf(buf
, 32, "realtime: %d%% ", realtime
);
91 rb
->lcd_puts(0, 6, (unsigned char *)buf
);
93 rb
->snprintf(buf
, 32, "compression: %d%% ", compression
);
94 rb
->lcd_puts(0, 8, (unsigned char *)buf
);
96 #ifdef HAVE_LCD_BITMAP
101 #define TEMP_SAMPLES 4096
103 static int32_t temp_buffer
[TEMP_SAMPLES
] IDATA_ATTR
;
105 static int wav2wv (char *filename
)
107 int in_fd
, out_fd
, num_chans
, error
= false, last_buttons
;
108 unsigned int32_t total_bytes_read
= 0, total_bytes_written
= 0;
109 unsigned int32_t total_samples
, samples_remaining
;
110 int32_t *input_buffer
= (int32_t *) audiobuf
;
111 unsigned char *output_buffer
= (unsigned char *)(audiobuf
+ 0x100000);
112 char *extension
, save_a
;
113 WavpackConfig config
;
117 rb
->lcd_clear_display();
118 rb
->lcd_puts_scroll(0, 0, (unsigned char *)filename
);
119 #ifdef HAVE_LCD_BITMAP
123 last_buttons
= rb
->button_status ();
124 start_tick
= *rb
->current_tick
;
125 extension
= filename
+ rb
->strlen (filename
) - 3;
127 if (rb
->strcasecmp (extension
, "wav")) {
128 rb
->splash(HZ
*2, "only for wav files!");
132 in_fd
= rb
->open(filename
, O_RDONLY
);
135 rb
->splash(HZ
*2, "could not open file!");
139 if (rb
->read (in_fd
, &raw_header
, sizeof (raw_header
)) != sizeof (raw_header
)) {
140 rb
->splash(HZ
*2, "could not read file!");
144 total_bytes_read
+= sizeof (raw_header
);
145 rb
->memcpy (&native_header
, &raw_header
, sizeof (raw_header
));
146 little_endian_to_native (&native_header
, WAV_HEADER_FORMAT
);
148 if (rb
->strncmp (native_header
.ckID
, "RIFF", 4) ||
149 rb
->strncmp (native_header
.fmt_ckID
, "fmt ", 4) ||
150 rb
->strncmp (native_header
.data_ckID
, "data", 4) ||
151 native_header
.FormatTag
!= 1 || native_header
.BitsPerSample
!= 16) {
152 rb
->splash(HZ
*2, "incompatible wav file!");
156 wpc
= WavpackOpenFileOutput ();
158 rb
->memset (&config
, 0, sizeof (config
));
159 config
.bits_per_sample
= 16;
160 config
.bytes_per_sample
= 2;
161 config
.sample_rate
= native_header
.SampleRate
;
162 num_chans
= config
.num_channels
= native_header
.NumChannels
;
163 total_samples
= native_header
.data_ckSize
/ native_header
.BlockAlign
;
165 /* config.flags |= CONFIG_HIGH_FLAG; */
167 if (!WavpackSetConfiguration (wpc
, &config
, total_samples
)) {
168 rb
->splash(HZ
*2, "internal error!");
173 WavpackAddWrapper (wpc
, &raw_header
, sizeof (raw_header
));
174 save_a
= extension
[1];
175 extension
[1] = extension
[2];
178 out_fd
= rb
->creat (filename
);
180 extension
[2] = extension
[1];
181 extension
[1] = save_a
;
184 rb
->splash(HZ
*2, "could not create file!");
189 wvupdate (start_tick
, native_header
.SampleRate
, total_samples
, 0, 0, 0);
191 for (samples_remaining
= total_samples
; samples_remaining
;) {
192 unsigned int32_t samples_count
, samples_to_pack
, bytes_count
;
197 samples_count
= SAMPLES_PER_BLOCK
;
199 if (samples_count
> samples_remaining
)
200 samples_count
= samples_remaining
;
202 bytes_count
= samples_count
* num_chans
* 2;
204 if (rb
->read (in_fd
, input_buffer
, bytes_count
) != (int32_t) bytes_count
) {
205 rb
->splash(HZ
*2, "could not read file!");
210 total_bytes_read
+= bytes_count
;
211 WavpackStartBlock (wpc
, output_buffer
, output_buffer
+ 0x100000);
212 samples_to_pack
= samples_count
;
213 cp
= (signed char *) input_buffer
;
215 while (samples_to_pack
) {
216 unsigned int32_t samples_this_pass
= TEMP_SAMPLES
/ num_chans
;
218 if (samples_this_pass
> samples_to_pack
)
219 samples_this_pass
= samples_to_pack
;
222 cnt
= samples_this_pass
;
226 value
= *cp
++ & 0xff;
229 value
= *cp
++ & 0xff;
235 value
= *cp
++ & 0xff;
240 if (!WavpackPackSamples (wpc
, temp_buffer
, samples_this_pass
)) {
241 rb
->splash(HZ
*2, "internal error!");
246 samples_to_pack
-= samples_this_pass
;
252 bytes_count
= WavpackFinishBlock (wpc
);
254 if (rb
->write (out_fd
, output_buffer
, bytes_count
) != (int32_t) bytes_count
) {
255 rb
->splash(HZ
*2, "could not write file!");
260 total_bytes_written
+= bytes_count
;
261 samples_remaining
-= samples_count
;
263 wvupdate (start_tick
, native_header
.SampleRate
, total_samples
,
264 total_samples
- samples_remaining
, total_bytes_read
, total_bytes_written
);
266 buttons
= rb
->button_status ();
268 if (last_buttons
== BUTTON_NONE
&& buttons
!= BUTTON_NONE
) {
269 rb
->splash(HZ
*2, "operation aborted!");
274 last_buttons
= buttons
;
281 save_a
= extension
[1];
282 extension
[1] = extension
[2];
284 rb
->remove (filename
);
285 extension
[2] = extension
[1];
286 extension
[1] = save_a
;
289 rb
->splash(HZ
*3, "operation successful");
294 enum plugin_status
plugin_start(struct plugin_api
* api
, void *parameter
)
297 /* This doesn't start profiling or anything, it just gives the
298 * profiling functions that are compiled in someplace to call,
299 * this is needed here to let this compile with profiling support
300 * since it calls code from a codec that is compiled with profiling
310 audiobuf
= rb
->plugin_get_audio_buffer((size_t *)&audiobuflen
);
312 if (audiobuflen
< 0x200000) {
313 rb
->splash(HZ
*2, "not enough memory!");
317 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
323 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
324 rb
->cpu_boost(false);
326 /* Return PLUGIN_USB_CONNECTED to force a file-tree refresh */
327 return PLUGIN_USB_CONNECTED
;