From febd9750f1f89404a22a30be1313c1b4c4873f81 Mon Sep 17 00:00:00 2001 From: Dave Bryant Date: Mon, 4 Jul 2005 07:07:43 +0000 Subject: Created new viewer application to test WavPack encoding. Accepts .wav file and generates lossless .wv with the same name. Runs at about 150% realtime for now. Only problem is that folder display (and playlist?) do not get updated when finished and since files don't show extensions it's a little hard to tell which is which (wav is first by alpha). git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7010 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/SOURCES | 1 + apps/plugins/viewers.config | 2 + apps/plugins/wav2wv.c | 294 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 297 insertions(+) create mode 100644 apps/plugins/wav2wv.c (limited to 'apps') diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index 76d26e7e59..50cebb9f87 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES @@ -68,6 +68,7 @@ alpine_cdc.c #if CONFIG_HWCODEC == MASNONE /* software codec platforms */ iriverify.c +wav2wv.c #else splitedit.c metronome.c diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config index e0c794afc6..ddb80cd06a 100644 --- a/apps/plugins/viewers.config +++ b/apps/plugins/viewers.config @@ -20,3 +20,5 @@ m3u,iriverify.rock,00 00 00 00 00 00 mpc,mpc2wav.rock, 00 00 00 00 00 00 mid,midi2wav.rock, 20 70 70 3F 00 00 rsp,searchengine.rock, 0e 11 11 31 7e 60 +wav,wav2wv.rock, 00 00 00 00 00 00 + diff --git a/apps/plugins/wav2wv.c b/apps/plugins/wav2wv.c new file mode 100644 index 0000000000..24a7f8be6d --- /dev/null +++ b/apps/plugins/wav2wv.c @@ -0,0 +1,294 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 David Bryant + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "plugin.h" + +#include + +#define SAMPLES_PER_BLOCK 22050 + +static struct plugin_api* rb; + +void *memset(void *s, int c, size_t n) { + return(rb->memset(s,c,n)); +} + +void *memcpy(void *dest, const void *src, size_t n) { + return(rb->memcpy(dest,src,n)); +} + +static char *audiobuf; +static int audiobuflen; + +static struct wav_header { + char ckID [4]; /* RIFF chuck header */ + long ckSize; + char formType [4]; + + char fmt_ckID [4]; /* format chunk header */ + long fmt_ckSize; + ushort FormatTag, NumChannels; + ulong SampleRate, BytesPerSecond; + ushort BlockAlign, BitsPerSample; + + char data_ckID [4]; /* data chunk header */ + long data_ckSize; +} raw_header, native_header; + +#define WAV_HEADER_FORMAT "4L44LSSLLSS4L" + +static void wvupdate (long start_tick, + long sample_rate, + ulong total_samples, + ulong samples_converted, + ulong bytes_read, + ulong bytes_written) +{ + long elapsed_ticks = *rb->current_tick - start_tick; + int compression = 0, progress = 0, realtime = 0; + char buf[32]; + + if (total_samples) + progress = (int)(((long long) samples_converted * 100 + + (total_samples/2)) / total_samples); + + if (elapsed_ticks) + realtime = (int)(((long long) samples_converted * 100 * HZ / + sample_rate + (elapsed_ticks/2)) / elapsed_ticks); + + if (bytes_read) + compression = (int)(((long long)(bytes_read - bytes_written) * 100 + + (bytes_read/2)) / bytes_read); + + rb->snprintf(buf, 32, "elapsed time: %d secs", (elapsed_ticks + (HZ/2)) / HZ); + rb->lcd_puts(0, 2, buf); + + rb->snprintf(buf, 32, "progress: %d%%", progress); + rb->lcd_puts(0, 4, buf); + + rb->snprintf(buf, 32, "realtime: %d%% ", realtime); + rb->lcd_puts(0, 6, buf); + + rb->snprintf(buf, 32, "compression: %d%% ", compression); + rb->lcd_puts(0, 8, buf); + +#ifdef HAVE_LCD_BITMAP + rb->lcd_update(); +#endif +} + +static int wav2wv (char *filename) +{ + int in_fd, out_fd, num_chans, error = false, last_buttons; + unsigned long total_bytes_read = 0, total_bytes_written = 0; + unsigned long total_samples, samples_remaining; + long *input_buffer = (long *) audiobuf; + unsigned char *output_buffer = audiobuf + 0x100000; + char *extension, save_a; + WavpackConfig config; + WavpackContext *wpc; + long start_tick; + + rb->lcd_clear_display(); + rb->lcd_puts_scroll(0, 0, filename); +#ifdef HAVE_LCD_BITMAP + rb->lcd_update(); +#endif + + last_buttons = rb->button_status (); + start_tick = *rb->current_tick; + extension = filename + rb->strlen (filename) - 3; + + if (rb->strcasecmp (extension, "wav")) { + rb->splash(HZ*2, true, "only for wav files!"); + return 1; + } + + in_fd = rb->open(filename, O_RDONLY); + + if (in_fd < 0) { + rb->splash(HZ*2, true, "could not open file!"); + return true; + } + + if (rb->read (in_fd, &raw_header, sizeof (raw_header)) != sizeof (raw_header)) { + rb->splash(HZ*2, true, "could not read file!"); + return true; + } + + total_bytes_read += sizeof (raw_header); + rb->memcpy (&native_header, &raw_header, sizeof (raw_header)); + little_endian_to_native (&native_header, WAV_HEADER_FORMAT); + + if (rb->strncmp (native_header.ckID, "RIFF", 4) || + rb->strncmp (native_header.fmt_ckID, "fmt ", 4) || + rb->strncmp (native_header.data_ckID, "data", 4) || + native_header.FormatTag != 1 || native_header.BitsPerSample != 16) { + rb->splash(HZ*2, true, "incompatible wav file!"); + return true; + } + + wpc = WavpackOpenFileOutput (); + WavpackSetOutputBuffer (wpc, output_buffer, output_buffer + 0x100000); + + rb->memset (&config, 0, sizeof (config)); + config.bits_per_sample = 16; + config.bytes_per_sample = 2; + config.sample_rate = native_header.SampleRate; + num_chans = config.num_channels = native_header.NumChannels; + total_samples = native_header.data_ckSize / native_header.BlockAlign; + + if (!WavpackSetConfiguration (wpc, &config, total_samples)) { + rb->splash(HZ*2, true, "internal error!"); + rb->close (in_fd); + return true; + } + + WavpackAddWrapper (wpc, &raw_header, sizeof (raw_header)); + save_a = extension [1]; + extension [1] = extension [2]; + extension [2] = 0; + + out_fd = rb->creat (filename, O_WRONLY); + + extension [2] = extension [1]; + extension [1] = save_a; + + if (out_fd < 0) { + rb->splash(HZ*2, true, "could not create file!"); + rb->close (in_fd); + return true; + } + + wvupdate (start_tick, native_header.SampleRate, total_samples, 0, 0, 0); + + for (samples_remaining = total_samples; samples_remaining;) { + unsigned long samples_count, bytes_count; + int cnt, buttons; + long value, *lp; + char *cp; + + samples_count = SAMPLES_PER_BLOCK; + + if (samples_count > samples_remaining) + samples_count = samples_remaining; + + bytes_count = samples_count * num_chans * 2; + + if (rb->read (in_fd, input_buffer, bytes_count) != (long) bytes_count) { + rb->splash(HZ*2, true, "could not read file!"); + error = true; + break; + } + + total_bytes_read += bytes_count; + cp = (char *) input_buffer + bytes_count; + lp = input_buffer + samples_count * num_chans; + cnt = samples_count; + + if (num_chans == 2) + while (cnt--) { + value = *--cp << 8; + value += *--cp & 0xff; + *--lp = value; + value = *--cp << 8; + value += *--cp & 0xff; + *--lp = value; + } + else + while (cnt--) { + value = *--cp << 8; + value += *--cp & 0xff; + *--lp = value; + } + + bytes_count = WavpackPackSamples (wpc, input_buffer, samples_count); + + if (!bytes_count) { + rb->splash(HZ*2, true, "internal error!"); + error = true; + break; + } + + if (rb->write (out_fd, output_buffer, bytes_count) != (long) bytes_count) { + rb->splash(HZ*2, true, "could not write file!"); + error = true; + break; + } + + total_bytes_written += bytes_count; + samples_remaining -= samples_count; + + wvupdate (start_tick, native_header.SampleRate, total_samples, + total_samples - samples_remaining, total_bytes_read, total_bytes_written); + + buttons = rb->button_status (); + + if (last_buttons == BUTTON_NONE && buttons != BUTTON_NONE) { + rb->splash(HZ*2, true, "operation aborted!"); + error = true; + break; + } + else + last_buttons = buttons; + } + + rb->close (out_fd); + rb->close (in_fd); + + if (error) { + save_a = extension [1]; + extension [1] = extension [2]; + extension [2] = 0; + rb->remove (filename); + extension [2] = extension [1]; + extension [1] = save_a; + } + else + rb->splash(HZ*3, true, "operation successful"); + + return error; +} + +enum plugin_status plugin_start(struct plugin_api* api, void *parameter) +{ + TEST_PLUGIN_API(api); + + rb = api; + + if (!parameter) + return PLUGIN_ERROR; + + audiobuf = rb->plugin_get_audio_buffer(&audiobuflen); + + if (audiobuflen < 0x200000) { + rb->splash(HZ*2, true, "not enough memory!"); + return PLUGIN_ERROR; + } + +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(true); +#endif + + wav2wv (parameter); + +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(false); +#endif + return PLUGIN_OK; +} -- cgit v1.2.3