rockbox/apps/plugins/wav2wv.c
Daniel Stenberg 2acc0ac542 Updated our source code header to explicitly mention that we are GPL v2 or
later. We still need to hunt down snippets used that are not. 1324 modified
files...
http://www.rockbox.org/mail/archive/rockbox-dev-archive-2008-06/0060.shtml


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17847 a1c6a512-1295-4272-9138-f99709370657
2008-06-28 18:10:04 +00:00

324 lines
9.6 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005 David Bryant
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "plugin.h"
#ifdef RB_PROFILE
#include "lib/profile_plugin.h"
#endif
#include <codecs/libwavpack/wavpack.h>
PLUGIN_HEADER
#define SAMPLES_PER_BLOCK 22050
static const 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 ssize_t audiobuflen;
static struct wav_header {
char ckID [4]; /* RIFF chuck header */
int32_t ckSize;
char formType [4];
char fmt_ckID [4]; /* format chunk header */
int32_t fmt_ckSize;
ushort FormatTag, NumChannels;
uint32_t SampleRate, BytesPerSecond;
ushort BlockAlign, BitsPerSample;
char data_ckID [4]; /* data chunk header */
int32_t data_ckSize;
} raw_header, native_header;
#define WAV_HEADER_FORMAT "4L44LSSLLSS4L"
static void wvupdate (int32_t start_tick,
int32_t sample_rate,
uint32_t total_samples,
uint32_t samples_converted,
uint32_t bytes_read,
uint32_t bytes_written)
{
int32_t elapsed_ticks = *rb->current_tick - start_tick;
int compression = 0, progress = 0, realtime = 0;
char buf[32];
if (total_samples)
progress = (int)(((int64_t) samples_converted * 100 +
(total_samples/2)) / total_samples);
if (elapsed_ticks)
realtime = (int)(((int64_t) samples_converted * 100 * HZ /
sample_rate + (elapsed_ticks/2)) / elapsed_ticks);
if (bytes_read)
compression = (int)(((int64_t)(bytes_read - bytes_written) * 100 +
(bytes_read/2)) / bytes_read);
rb->snprintf(buf, 32, "elapsed time: %ld secs",
(long)(elapsed_ticks + (HZ/2)) / HZ);
rb->lcd_puts(0, 2, (unsigned char *)buf);
rb->snprintf(buf, 32, "progress: %d%%", progress);
rb->lcd_puts(0, 4, (unsigned char *)buf);
rb->snprintf(buf, 32, "realtime: %d%% ", realtime);
rb->lcd_puts(0, 6, (unsigned char *)buf);
rb->snprintf(buf, 32, "compression: %d%% ", compression);
rb->lcd_puts(0, 8, (unsigned char *)buf);
#ifdef HAVE_LCD_BITMAP
rb->lcd_update();
#endif
}
#define TEMP_SAMPLES 4096
static int32_t temp_buffer [TEMP_SAMPLES] IDATA_ATTR;
static int wav2wv(const char *infile)
{
int in_fd, out_fd, num_chans, error = false, last_buttons;
unsigned int32_t total_bytes_read = 0, total_bytes_written = 0;
unsigned int32_t total_samples, samples_remaining;
int32_t *input_buffer = (int32_t *) audiobuf;
unsigned char *output_buffer = (unsigned char *)(audiobuf + 0x100000);
char outfile[MAX_PATH];
const char *inextension;
char *outextension;
WavpackConfig config;
WavpackContext *wpc;
int32_t start_tick;
rb->lcd_clear_display();
rb->lcd_puts_scroll(0, 0, (unsigned char *)infile);
#ifdef HAVE_LCD_BITMAP
rb->lcd_update();
#endif
last_buttons = rb->button_status ();
start_tick = *rb->current_tick;
inextension = infile + rb->strlen(infile) - 3;
if (rb->strcasecmp (inextension, "wav")) {
rb->splash(HZ*2, "only for wav files!");
return 1;
}
in_fd = rb->open(infile, O_RDONLY);
if (in_fd < 0) {
rb->splash(HZ*2, "could not open file!");
return true;
}
if (rb->read (in_fd, &raw_header, sizeof (raw_header)) != sizeof (raw_header)) {
rb->splash(HZ*2, "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, "incompatible wav file!");
return true;
}
wpc = WavpackOpenFileOutput ();
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;
/* config.flags |= CONFIG_HIGH_FLAG; */
if (!WavpackSetConfiguration (wpc, &config, total_samples)) {
rb->splash(HZ*2, "internal error!");
rb->close (in_fd);
return true;
}
WavpackAddWrapper (wpc, &raw_header, sizeof (raw_header));
rb->strcpy(outfile, infile);
outextension = outfile + rb->strlen(outfile) - 3;
outextension[1] = outextension[2];
outextension[2] = 0;
out_fd = rb->creat(outfile);
if (out_fd < 0) {
rb->splash(HZ*2, "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 int32_t samples_count, samples_to_pack, bytes_count;
int cnt, buttons;
int32_t value, *lp;
signed 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) != (int32_t) bytes_count) {
rb->splash(HZ*2, "could not read file!");
error = true;
break;
}
total_bytes_read += bytes_count;
WavpackStartBlock (wpc, output_buffer, output_buffer + 0x100000);
samples_to_pack = samples_count;
cp = (signed char *) input_buffer;
while (samples_to_pack) {
unsigned int32_t samples_this_pass = TEMP_SAMPLES / num_chans;
if (samples_this_pass > samples_to_pack)
samples_this_pass = samples_to_pack;
lp = temp_buffer;
cnt = samples_this_pass;
if (num_chans == 2)
while (cnt--) {
value = *cp++ & 0xff;
value += *cp++ << 8;
*lp++ = value;
value = *cp++ & 0xff;
value += *cp++ << 8;
*lp++ = value;
}
else
while (cnt--) {
value = *cp++ & 0xff;
value += *cp++ << 8;
*lp++ = value;
}
if (!WavpackPackSamples (wpc, temp_buffer, samples_this_pass)) {
rb->splash(HZ*2, "internal error!");
error = true;
break;
}
samples_to_pack -= samples_this_pass;
}
if (error)
break;
bytes_count = WavpackFinishBlock (wpc);
if (rb->write (out_fd, output_buffer, bytes_count) != (int32_t) bytes_count) {
rb->splash(HZ*2, "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, "operation aborted!");
error = true;
break;
}
else
last_buttons = buttons;
}
rb->close (out_fd);
rb->close (in_fd);
if (error) {
rb->remove (outfile);
}
else
rb->splash(HZ*3, "operation successful");
return error;
}
enum plugin_status plugin_start(const struct plugin_api* api, const void *parameter)
{
#ifdef RB_PROFILE
/* This doesn't start profiling or anything, it just gives the
* profiling functions that are compiled in someplace to call,
* this is needed here to let this compile with profiling support
* since it calls code from a codec that is compiled with profiling
* support */
profile_init(api);
#endif
rb = api;
if (!parameter)
return PLUGIN_ERROR;
audiobuf = rb->plugin_get_audio_buffer((size_t *)&audiobuflen);
if (audiobuflen < 0x200000) {
rb->splash(HZ*2, "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_USB_CONNECTED to force a file-tree refresh */
return PLUGIN_USB_CONNECTED;
}