You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
435 lines
11 KiB
435 lines
11 KiB
/*
|
|
* $Id: pilot-wav.c,v 1.19 2006/10/12 14:21:21 desrod Exp $
|
|
*
|
|
* pilot-wav.c: Palm Voice Memo Wav Fetcher/Converter
|
|
*
|
|
* This is a palm conduit to fetch Memo Wav files from a Palm. It can also
|
|
* convert *.wav.pdb files that have already been fetched from the Palm.
|
|
*
|
|
* Copyright (C) 2003 by David Turner
|
|
* Based on pilot-foto Copyright (C) 2003 by Judd Montgomery
|
|
*
|
|
* 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.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
|
* Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "pi-file.h"
|
|
#include "pi-source.h"
|
|
#include "pi-userland.h"
|
|
|
|
/* Declare prototypes */
|
|
long write_header(FILE *out);
|
|
long write_data(char *buffer, int index, int size, long dataChunkSize, FILE *out);
|
|
int pdb_to_wav(char *filename);
|
|
int fetch_wavs(int sd, char *dbname);
|
|
int do_fetch(char *dbname);
|
|
|
|
#ifndef TRUE
|
|
# define TRUE 1
|
|
#endif
|
|
#ifndef FALSE
|
|
# define FALSE 0
|
|
#endif
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: write_header
|
|
*
|
|
* Summary: Writes out header of wave file with correct parameters
|
|
*
|
|
* Parameters: File out - output file pointer
|
|
*
|
|
* Returns: long - size of format chunk
|
|
*
|
|
***********************************************************************/
|
|
long write_header(FILE * out)
|
|
{
|
|
const char formatChunkID[4] = "fmt ";
|
|
long formatChunkSize;
|
|
|
|
short wFormatTag;
|
|
unsigned short wChannels;
|
|
unsigned long dwSamplesPerSec;
|
|
unsigned long dwAvgBytesPerSec;
|
|
unsigned short wBlockAlign;
|
|
unsigned short wBitsPerSample;
|
|
unsigned short cbSize;
|
|
unsigned short wSamplesPerBlock;
|
|
|
|
const char dataChunkID[4] = "data";
|
|
long dataChunkSize;
|
|
|
|
long wWaveLength;
|
|
|
|
/* In bytes, not including formatChunkID and formatChunkSize itself */
|
|
formatChunkSize = 20;
|
|
|
|
/* 17 = Intel IMA (DVI) ADPCM */
|
|
wFormatTag = 17;
|
|
|
|
/* Mono */
|
|
wChannels = 1;
|
|
dwSamplesPerSec = 8000;
|
|
|
|
/* This value varies with file - need formula */
|
|
dwAvgBytesPerSec = 4425;
|
|
wBlockAlign = 256;
|
|
wBitsPerSample = 4;
|
|
|
|
/* Extended format block size including(it appears) cbSize itself */
|
|
cbSize = 2;
|
|
wSamplesPerBlock = 505;
|
|
|
|
/* fill in at end of file with seek */
|
|
dataChunkSize = 0;
|
|
|
|
/* fill in at end of file with seek */
|
|
wWaveLength = 0;
|
|
|
|
/* RIFF Header */
|
|
fwrite("RIFF", 4, 1, out);
|
|
fwrite(&wWaveLength, 4, 1, out);
|
|
fwrite("WAVE", 4, 1, out);
|
|
|
|
/* Format Chunk */
|
|
fwrite(formatChunkID, 4, 1, out);
|
|
|
|
/* Length of Format Chunk - 4 (fmt ) - 4 (length value itself) */
|
|
fwrite(&formatChunkSize, 4, 1, out);
|
|
fwrite(&wFormatTag, 2, 1, out);
|
|
fwrite(&wChannels, 2, 1, out);
|
|
fwrite(&dwSamplesPerSec, 4, 1, out);
|
|
fwrite(&dwAvgBytesPerSec, 4, 1, out);
|
|
fwrite(&wBlockAlign, 2, 1, out);
|
|
fwrite(&wBitsPerSample, 2, 1, out);
|
|
|
|
/* Extended Format Chunk Fields */
|
|
|
|
/* Extended format block size including(it appears) cbSize itself */
|
|
fwrite(&cbSize, 2, 1, out);
|
|
fwrite(&wSamplesPerBlock, 2, 1, out);
|
|
|
|
/* Data Chunk */
|
|
fwrite(dataChunkID, 4, 1, out);
|
|
fwrite(&dataChunkSize, 4, 1, out);
|
|
|
|
return formatChunkSize;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: write_data
|
|
*
|
|
* Summary: Writes out data from record buffer updating dataChunkSize
|
|
*
|
|
* Parameters: char pointer buffer - self explanatory
|
|
* int size - size of data to be written
|
|
* FILE *out - pointer to output file
|
|
* long dataChunkSize - present data chunk size
|
|
*
|
|
* Returns: long - updated dataChunkSize
|
|
*
|
|
***********************************************************************/
|
|
long write_data(char *buffer, int index, int size, long dataChunkSize, FILE *out)
|
|
{
|
|
if (index == 0) {
|
|
fwrite(buffer + 122, size - 122, 1, out);
|
|
dataChunkSize += size - 122;
|
|
} else {
|
|
fwrite(buffer + 8, size - 8, 1, out);
|
|
dataChunkSize += size - 8;
|
|
}
|
|
return dataChunkSize;
|
|
}
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: fetch_wavs
|
|
*
|
|
* Summary: Grab the voice memos matching 'Vpad' on the device
|
|
*
|
|
* Parameters: None
|
|
*
|
|
* Returns: 0
|
|
*
|
|
***********************************************************************/
|
|
int fetch_wavs(int sd, char *dbname)
|
|
{
|
|
FILE *out;
|
|
recordid_t id_;
|
|
int index,
|
|
db,
|
|
attr,
|
|
category,
|
|
ret,
|
|
start;
|
|
|
|
struct DBInfo info;
|
|
char creator[5];
|
|
char type[5];
|
|
pi_buffer_t *buffer;
|
|
|
|
int booldb = TRUE;
|
|
|
|
long wWaveLength;
|
|
long formatChunkSize;
|
|
long dataChunkSize;
|
|
|
|
start = 0;
|
|
|
|
buffer = pi_buffer_new (65536);
|
|
|
|
while (dlp_ReadDBList(sd, 0, dlpOpenRead, start, buffer) > 0) {
|
|
memcpy(&info, buffer->data, sizeof(struct DBInfo));
|
|
start = info.index + 1;
|
|
creator[0] = (info.creator & 0xFF000000) >> 24;
|
|
creator[1] = (info.creator & 0x00FF0000) >> 16;
|
|
creator[2] = (info.creator & 0x0000FF00) >> 8;
|
|
creator[3] = (info.creator & 0x000000FF);
|
|
creator[4] = '\0';
|
|
type[0] = (info.type & 0xFF000000) >> 24;
|
|
type[1] = (info.type & 0x00FF0000) >> 16;
|
|
type[2] = (info.type & 0x0000FF00) >> 8;
|
|
type[3] = (info.type & 0x000000FF);
|
|
type[4] = '\0';
|
|
|
|
if (!strcmp(dbname, "all")) {
|
|
booldb = FALSE;
|
|
} else {
|
|
booldb = strcmp(info.name, dbname);
|
|
}
|
|
|
|
if (!(strcmp(creator, "Vpad") || strcmp(type, "strm") || booldb)) {
|
|
memset (buffer->data, 0, buffer->allocated);
|
|
if (!plu_quiet) {
|
|
printf("Fetching '%s' (Creator ID '%s')... ",
|
|
info.name, creator);
|
|
}
|
|
ret =
|
|
dlp_OpenDB(sd, 0, dlpOpenRead, info.name, &db);
|
|
if (ret < 0) {
|
|
fprintf(stderr, " WARNING: Unable to open %s\n",
|
|
info.name);
|
|
continue;
|
|
}
|
|
|
|
out = fopen(info.name, "w");
|
|
if (!out) {
|
|
fprintf(stderr,
|
|
" WARNING: Failed, unable to create file %s\n",
|
|
info.name);
|
|
dlp_CloseDB(sd,db);
|
|
continue;
|
|
}
|
|
|
|
formatChunkSize = write_header(out);
|
|
|
|
index = 0;
|
|
dataChunkSize = 0;
|
|
ret = 1;
|
|
while (ret > 0) {
|
|
ret =
|
|
dlp_ReadRecordByIndex
|
|
PI_ARGS((sd, db, index, buffer, &id_,
|
|
&attr, &category));
|
|
if (ret > 0) {
|
|
dataChunkSize = write_data(buffer->data, index, buffer->used, dataChunkSize, out);
|
|
}
|
|
index++;
|
|
}
|
|
wWaveLength = 4 + 4 + 4 + formatChunkSize + 4 + 4 + dataChunkSize;
|
|
fseek(out, 44, SEEK_SET);
|
|
fwrite(&dataChunkSize, 4, 1, out);
|
|
fseek(out, 4, SEEK_SET);
|
|
fwrite(&wWaveLength, 4, 1, out);
|
|
dlp_CloseDB(sd, db);
|
|
fclose(out);
|
|
if (!plu_quiet) {
|
|
printf("OK\n");
|
|
}
|
|
}
|
|
}
|
|
pi_buffer_free(buffer);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: do_fetch
|
|
*
|
|
* Summary: Connect and fetch the file
|
|
*
|
|
* Parameters: None
|
|
*
|
|
* Returns: 0
|
|
*
|
|
***********************************************************************/
|
|
int do_fetch(char *dbname)
|
|
{
|
|
int sd = -1,
|
|
ret;
|
|
|
|
sd = plu_connect();
|
|
|
|
ret = fetch_wavs(sd, dbname);
|
|
|
|
dlp_EndOfSync(sd, dlpEndCodeNormal);
|
|
pi_close(sd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: pdb_to_wav
|
|
*
|
|
* Summary: Do the bulk of the conversion here
|
|
*
|
|
* Parameters: None
|
|
*
|
|
* Returns: 0 - Success, -1 - Failure
|
|
*
|
|
***********************************************************************/
|
|
int pdb_to_wav(char *filename)
|
|
{
|
|
struct pi_file *pi_fp;
|
|
struct DBInfo info;
|
|
FILE *out;
|
|
int index,
|
|
ret,
|
|
attr,
|
|
cat;
|
|
void *buffer;
|
|
recordid_t uid;
|
|
|
|
size_t size;
|
|
|
|
long wWaveLength;
|
|
long formatChunkSize;
|
|
long dataChunkSize;
|
|
|
|
if (!plu_quiet) {
|
|
printf("Converting %s... ", filename);
|
|
}
|
|
pi_fp = pi_file_open(filename);
|
|
if (!pi_fp) {
|
|
fprintf(stderr," FAILED: could not open %s\n", filename);
|
|
return -1;
|
|
}
|
|
pi_file_get_info(pi_fp, &info);
|
|
|
|
out = fopen(info.name, "w");
|
|
if (!out) {
|
|
pi_file_close(pi_fp);
|
|
fprintf(stderr," FAILED: could not open %s to write\n", info.name);
|
|
return -1;
|
|
}
|
|
|
|
formatChunkSize = write_header(out);
|
|
|
|
index = 0;
|
|
dataChunkSize = 0;
|
|
ret = 1;
|
|
while (ret >= 0) {
|
|
ret =
|
|
pi_file_read_record(pi_fp, index, &buffer, &size, &attr,
|
|
&cat, &uid);
|
|
if (ret >= 0) {
|
|
dataChunkSize = write_data(buffer, index, size, dataChunkSize, out);
|
|
}
|
|
index++;
|
|
}
|
|
wWaveLength = 4 + 4 + 4 + formatChunkSize + 4 + 4 + dataChunkSize;
|
|
fseek(out, 44, SEEK_SET);
|
|
fwrite(&dataChunkSize, 4, 1, out);
|
|
fseek(out, 4, SEEK_SET);
|
|
fwrite(&wWaveLength, 4, 1, out);
|
|
fclose(out);
|
|
pi_file_close(pi_fp);
|
|
if (!plu_quiet) {
|
|
printf("OK, wrote %ld bytes to %s\n", dataChunkSize, info.name);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, const char *argv[])
|
|
{
|
|
int c;
|
|
|
|
char
|
|
*fetch = NULL,
|
|
*convert = NULL;
|
|
|
|
poptContext pc;
|
|
|
|
struct poptOption options[] = {
|
|
USERLAND_RESERVED_OPTIONS
|
|
{"fetch", 'f', POPT_ARG_STRING, &fetch, 0, "Fetch all wav files or specified wav file from the Palm", "[file|all]"},
|
|
{"convert", 'c', POPT_ARG_STRING, &convert, 0, "Convert <file>.wav.pdb file to wav", "file"},
|
|
POPT_TABLEEND
|
|
};
|
|
|
|
pc = poptGetContext("pilot-wav", argc, argv, options, 0);
|
|
poptSetOtherOptionHelp(pc,"\n\n"
|
|
" Decodes Palm Voice Memo files to wav files you can read\n\n"
|
|
" Example arguments: \n"
|
|
" pilot-wav -p /dev/pilot -f MyVoiceMemo.wav.pdb\n"
|
|
" pilot-wav -c MyVoiceMemo.wav.pdb\n\n");
|
|
|
|
if (argc < 2 ) {
|
|
poptPrintUsage(pc,stderr,0);
|
|
return 1;
|
|
}
|
|
|
|
|
|
while ((c = poptGetNextOpt(pc)) >= 0) {
|
|
fprintf(stderr," ERROR: Unhandled option %d.\n",c);
|
|
return 1;
|
|
}
|
|
|
|
if (c < -1) {
|
|
plu_badoption(pc,c);
|
|
}
|
|
|
|
if(convert != NULL)
|
|
pdb_to_wav(convert);
|
|
|
|
if(fetch != NULL)
|
|
do_fetch(fetch);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */
|
|
/* ex: set tabstop=4 expandtab: */
|
|
/* Local Variables: */
|
|
/* indent-tabs-mode: t */
|
|
/* c-basic-offset: 8 */
|
|
/* End: */
|