Removed 'mode' parameter from creat(). It wasn't pure posix anyway, it was ignored...
[Rockbox.git] / apps / plugins / wav2wv.c
blob2e2076c0ed8b4697136a857156ae36366359cdf6
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
19 #include "plugin.h"
20 #ifdef RB_PROFILE
21 #include "lib/profile_plugin.h"
22 #endif
24 #include <codecs/libwavpack/wavpack.h>
26 PLUGIN_HEADER
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 */
45 int32_t ckSize;
46 char formType [4];
48 char fmt_ckID [4]; /* format chunk header */
49 int32_t fmt_ckSize;
50 ushort FormatTag, NumChannels;
51 uint32_t SampleRate, BytesPerSecond;
52 ushort BlockAlign, BitsPerSample;
54 char data_ckID [4]; /* data chunk header */
55 int32_t data_ckSize;
56 } raw_header, native_header;
58 #define WAV_HEADER_FORMAT "4L44LSSLLSS4L"
60 static void wvupdate (int32_t start_tick,
61 int32_t sample_rate,
62 uint32_t total_samples,
63 uint32_t samples_converted,
64 uint32_t bytes_read,
65 uint32_t bytes_written)
67 int32_t elapsed_ticks = *rb->current_tick - start_tick;
68 int compression = 0, progress = 0, realtime = 0;
69 char buf[32];
71 if (total_samples)
72 progress = (int)(((int64_t) samples_converted * 100 +
73 (total_samples/2)) / total_samples);
75 if (elapsed_ticks)
76 realtime = (int)(((int64_t) samples_converted * 100 * HZ /
77 sample_rate + (elapsed_ticks/2)) / elapsed_ticks);
79 if (bytes_read)
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
96 rb->lcd_update();
97 #endif
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;
113 WavpackContext *wpc;
114 int32_t start_tick;
116 rb->lcd_clear_display();
117 rb->lcd_puts_scroll(0, 0, (unsigned char *)filename);
118 #ifdef HAVE_LCD_BITMAP
119 rb->lcd_update();
120 #endif
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!");
128 return 1;
131 in_fd = rb->open(filename, O_RDONLY);
133 if (in_fd < 0) {
134 rb->splash(HZ*2, true, "could not open file!");
135 return true;
138 if (rb->read (in_fd, &raw_header, sizeof (raw_header)) != sizeof (raw_header)) {
139 rb->splash(HZ*2, true, "could not read file!");
140 return true;
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!");
152 return true;
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!");
168 rb->close (in_fd);
169 return true;
172 WavpackAddWrapper (wpc, &raw_header, sizeof (raw_header));
173 save_a = extension [1];
174 extension [1] = extension [2];
175 extension [2] = 0;
177 out_fd = rb->creat (filename);
179 extension [2] = extension [1];
180 extension [1] = save_a;
182 if (out_fd < 0) {
183 rb->splash(HZ*2, true, "could not create file!");
184 rb->close (in_fd);
185 return true;
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;
192 int cnt, buttons;
193 int32_t value, *lp;
194 signed char *cp;
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!");
205 error = true;
206 break;
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;
220 lp = temp_buffer;
221 cnt = samples_this_pass;
223 if (num_chans == 2)
224 while (cnt--) {
225 value = *cp++ & 0xff;
226 value += *cp++ << 8;
227 *lp++ = value;
228 value = *cp++ & 0xff;
229 value += *cp++ << 8;
230 *lp++ = value;
232 else
233 while (cnt--) {
234 value = *cp++ & 0xff;
235 value += *cp++ << 8;
236 *lp++ = value;
239 if (!WavpackPackSamples (wpc, temp_buffer, samples_this_pass)) {
240 rb->splash(HZ*2, true, "internal error!");
241 error = true;
242 break;
245 samples_to_pack -= samples_this_pass;
248 if (error)
249 break;
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!");
255 error = true;
256 break;
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!");
269 error = true;
270 break;
272 else
273 last_buttons = buttons;
276 rb->close (out_fd);
277 rb->close (in_fd);
279 if (error) {
280 save_a = extension [1];
281 extension [1] = extension [2];
282 extension [2] = 0;
283 rb->remove (filename);
284 extension [2] = extension [1];
285 extension [1] = save_a;
287 else
288 rb->splash(HZ*3, true, "operation successful");
290 return error;
293 enum plugin_status plugin_start(struct plugin_api* api, void *parameter)
295 #ifdef RB_PROFILE
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
300 * support */
301 profile_init(api);
302 #endif
304 rb = api;
306 if (!parameter)
307 return PLUGIN_ERROR;
309 audiobuf = rb->plugin_get_audio_buffer(&audiobuflen);
311 if (audiobuflen < 0x200000) {
312 rb->splash(HZ*2, true, "not enough memory!");
313 return PLUGIN_ERROR;
316 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
317 rb->cpu_boost(true);
318 #endif
320 wav2wv (parameter);
322 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
323 rb->cpu_boost(false);
324 #endif
325 /* Return PLUGIN_USB_CONNECTED to force a file-tree refresh */
326 return PLUGIN_USB_CONNECTED;