very minor code police. also fix a possible but unlikely missed cpu_boost(false)
[Rockbox.git] / apps / plugins / wav2wv.c
blob1a37ee22ec5bbfc2701864786b9b7e782859ef52
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
21 #include "plugin.h"
22 #ifdef RB_PROFILE
23 #include "lib/profile_plugin.h"
24 #endif
26 #include <codecs/libwavpack/wavpack.h>
28 PLUGIN_HEADER
30 #define SAMPLES_PER_BLOCK 22050
32 static const struct plugin_api* rb;
34 void *memset(void *s, int c, size_t n) {
35 return(rb->memset(s,c,n));
38 void *memcpy(void *dest, const void *src, size_t n) {
39 return(rb->memcpy(dest,src,n));
42 static char *audiobuf;
43 static ssize_t audiobuflen;
45 static struct wav_header {
46 char ckID [4]; /* RIFF chuck header */
47 int32_t ckSize;
48 char formType [4];
50 char fmt_ckID [4]; /* format chunk header */
51 int32_t fmt_ckSize;
52 ushort FormatTag, NumChannels;
53 uint32_t SampleRate, BytesPerSecond;
54 ushort BlockAlign, BitsPerSample;
56 char data_ckID [4]; /* data chunk header */
57 int32_t data_ckSize;
58 } raw_header, native_header;
60 #define WAV_HEADER_FORMAT "4L44LSSLLSS4L"
62 static void wvupdate (int32_t start_tick,
63 int32_t sample_rate,
64 uint32_t total_samples,
65 uint32_t samples_converted,
66 uint32_t bytes_read,
67 uint32_t bytes_written)
69 int32_t elapsed_ticks = *rb->current_tick - start_tick;
70 int compression = 0, progress = 0, realtime = 0;
71 char buf[32];
73 if (total_samples)
74 progress = (int)(((int64_t) samples_converted * 100 +
75 (total_samples/2)) / total_samples);
77 if (elapsed_ticks)
78 realtime = (int)(((int64_t) samples_converted * 100 * HZ /
79 sample_rate + (elapsed_ticks/2)) / elapsed_ticks);
81 if (bytes_read)
82 compression = (int)(((int64_t)(bytes_read - bytes_written) * 100 +
83 (bytes_read/2)) / bytes_read);
85 rb->snprintf(buf, 32, "elapsed time: %ld secs",
86 (long)(elapsed_ticks + (HZ/2)) / HZ);
87 rb->lcd_puts(0, 2, (unsigned char *)buf);
89 rb->snprintf(buf, 32, "progress: %d%%", progress);
90 rb->lcd_puts(0, 4, (unsigned char *)buf);
92 rb->snprintf(buf, 32, "realtime: %d%% ", realtime);
93 rb->lcd_puts(0, 6, (unsigned char *)buf);
95 rb->snprintf(buf, 32, "compression: %d%% ", compression);
96 rb->lcd_puts(0, 8, (unsigned char *)buf);
98 #ifdef HAVE_LCD_BITMAP
99 rb->lcd_update();
100 #endif
103 #define TEMP_SAMPLES 4096
105 static int32_t temp_buffer [TEMP_SAMPLES] IDATA_ATTR;
107 static int wav2wv(const char *infile)
109 int in_fd, out_fd, num_chans, error = false, last_buttons;
110 unsigned int32_t total_bytes_read = 0, total_bytes_written = 0;
111 unsigned int32_t total_samples, samples_remaining;
112 int32_t *input_buffer = (int32_t *) audiobuf;
113 unsigned char *output_buffer = (unsigned char *)(audiobuf + 0x100000);
114 char outfile[MAX_PATH];
115 const char *inextension;
116 char *outextension;
117 WavpackConfig config;
118 WavpackContext *wpc;
119 int32_t start_tick;
121 rb->lcd_clear_display();
122 rb->lcd_puts_scroll(0, 0, (unsigned char *)infile);
123 #ifdef HAVE_LCD_BITMAP
124 rb->lcd_update();
125 #endif
127 last_buttons = rb->button_status ();
128 start_tick = *rb->current_tick;
129 inextension = infile + rb->strlen(infile) - 3;
130 if (rb->strcasecmp (inextension, "wav")) {
131 rb->splash(HZ*2, "only for wav files!");
132 return 1;
135 in_fd = rb->open(infile, O_RDONLY);
137 if (in_fd < 0) {
138 rb->splash(HZ*2, "could not open file!");
139 return true;
142 if (rb->read (in_fd, &raw_header, sizeof (raw_header)) != sizeof (raw_header)) {
143 rb->splash(HZ*2, "could not read file!");
144 return true;
147 total_bytes_read += sizeof (raw_header);
148 rb->memcpy (&native_header, &raw_header, sizeof (raw_header));
149 little_endian_to_native (&native_header, WAV_HEADER_FORMAT);
151 if (rb->strncmp (native_header.ckID, "RIFF", 4) ||
152 rb->strncmp (native_header.fmt_ckID, "fmt ", 4) ||
153 rb->strncmp (native_header.data_ckID, "data", 4) ||
154 native_header.FormatTag != 1 || native_header.BitsPerSample != 16) {
155 rb->splash(HZ*2, "incompatible wav file!");
156 return true;
159 wpc = WavpackOpenFileOutput ();
161 rb->memset (&config, 0, sizeof (config));
162 config.bits_per_sample = 16;
163 config.bytes_per_sample = 2;
164 config.sample_rate = native_header.SampleRate;
165 num_chans = config.num_channels = native_header.NumChannels;
166 total_samples = native_header.data_ckSize / native_header.BlockAlign;
168 /* config.flags |= CONFIG_HIGH_FLAG; */
170 if (!WavpackSetConfiguration (wpc, &config, total_samples)) {
171 rb->splash(HZ*2, "internal error!");
172 rb->close (in_fd);
173 return true;
176 WavpackAddWrapper (wpc, &raw_header, sizeof (raw_header));
178 rb->strcpy(outfile, infile);
179 outextension = outfile + rb->strlen(outfile) - 3;
180 outextension[1] = outextension[2];
181 outextension[2] = 0;
182 out_fd = rb->creat(outfile);
184 if (out_fd < 0) {
185 rb->splash(HZ*2, "could not create file!");
186 rb->close (in_fd);
187 return true;
190 wvupdate (start_tick, native_header.SampleRate, total_samples, 0, 0, 0);
192 for (samples_remaining = total_samples; samples_remaining;) {
193 unsigned int32_t samples_count, samples_to_pack, bytes_count;
194 int cnt, buttons;
195 int32_t value, *lp;
196 signed char *cp;
198 samples_count = SAMPLES_PER_BLOCK;
200 if (samples_count > samples_remaining)
201 samples_count = samples_remaining;
203 bytes_count = samples_count * num_chans * 2;
205 if (rb->read (in_fd, input_buffer, bytes_count) != (int32_t) bytes_count) {
206 rb->splash(HZ*2, "could not read file!");
207 error = true;
208 break;
211 total_bytes_read += bytes_count;
212 WavpackStartBlock (wpc, output_buffer, output_buffer + 0x100000);
213 samples_to_pack = samples_count;
214 cp = (signed char *) input_buffer;
216 while (samples_to_pack) {
217 unsigned int32_t samples_this_pass = TEMP_SAMPLES / num_chans;
219 if (samples_this_pass > samples_to_pack)
220 samples_this_pass = samples_to_pack;
222 lp = temp_buffer;
223 cnt = samples_this_pass;
225 if (num_chans == 2)
226 while (cnt--) {
227 value = *cp++ & 0xff;
228 value += *cp++ << 8;
229 *lp++ = value;
230 value = *cp++ & 0xff;
231 value += *cp++ << 8;
232 *lp++ = value;
234 else
235 while (cnt--) {
236 value = *cp++ & 0xff;
237 value += *cp++ << 8;
238 *lp++ = value;
241 if (!WavpackPackSamples (wpc, temp_buffer, samples_this_pass)) {
242 rb->splash(HZ*2, "internal error!");
243 error = true;
244 break;
247 samples_to_pack -= samples_this_pass;
250 if (error)
251 break;
253 bytes_count = WavpackFinishBlock (wpc);
255 if (rb->write (out_fd, output_buffer, bytes_count) != (int32_t) bytes_count) {
256 rb->splash(HZ*2, "could not write file!");
257 error = true;
258 break;
261 total_bytes_written += bytes_count;
262 samples_remaining -= samples_count;
264 wvupdate (start_tick, native_header.SampleRate, total_samples,
265 total_samples - samples_remaining, total_bytes_read, total_bytes_written);
267 buttons = rb->button_status ();
269 if (last_buttons == BUTTON_NONE && buttons != BUTTON_NONE) {
270 rb->splash(HZ*2, "operation aborted!");
271 error = true;
272 break;
274 else
275 last_buttons = buttons;
278 rb->close (out_fd);
279 rb->close (in_fd);
281 if (error) {
282 rb->remove (outfile);
284 else
285 rb->splash(HZ*3, "operation successful");
287 return error;
290 enum plugin_status plugin_start(const struct plugin_api* api, const void *parameter)
292 #ifdef RB_PROFILE
293 /* This doesn't start profiling or anything, it just gives the
294 * profiling functions that are compiled in someplace to call,
295 * this is needed here to let this compile with profiling support
296 * since it calls code from a codec that is compiled with profiling
297 * support */
298 profile_init(api);
299 #endif
301 rb = api;
303 if (!parameter)
304 return PLUGIN_ERROR;
306 audiobuf = rb->plugin_get_audio_buffer((size_t *)&audiobuflen);
308 if (audiobuflen < 0x200000) {
309 rb->splash(HZ*2, "not enough memory!");
310 return PLUGIN_ERROR;
313 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
314 rb->cpu_boost(true);
315 #endif
317 wav2wv (parameter);
319 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
320 rb->cpu_boost(false);
321 #endif
322 /* Return PLUGIN_USB_CONNECTED to force a file-tree refresh */
323 return PLUGIN_USB_CONNECTED;