rockbox/apps/plugins/wav2wv.c
Andrew Mahone 23d9812273 loader-initialized global plugin API:
struct plugin_api *rb is declared in PLUGIN_HEADER, and pointed to by
__header.api

the loader uses this pointer to initialize rb before calling entry_point

entry_point is no longer passed a pointer to the plugin API

all plugins, and pluginlib functions, are modified to refer to the
global rb

pluginlib functions which only served to copy the API pointer are
removed

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19776 a1c6a512-1295-4272-9138-f99709370657
2009-01-16 10:34:40 +00:00

311 lines
9.2 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
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 void *parameter)
{
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;
}