#! /usr/bin/perl # Read a pdb file from a Kyocera 7135 and extract the audio from it. # # Handles both MP3 and sample format, and can fetch alrm, tone, flip, and # ring types. # # This depended on information from kyocera_6035_pdb.txt, found at # http://merwin.bespin.org/t4a/specs/kyocera_6035_pdb.txt # # The PDB files apparently could be used in different places. To make # that work right, they apparently sometimes contained another PDB file, # listing the other place it could be used. The code here notes this, and # automatically extracts those, too. # # File names are pulled from the PDB. # Good habits, make perl noisy. use strict; use warnings; # Modules to read PDB files. use Palm::PDB; use Palm::Raw; # Create temp files. use File::Temp qw/ tempfile tempdir /; my $filename = $ARGV[0]; die "Need filename on command line" unless ($filename and -e $filename); process($filename); sub process { my $filename = shift; print "Processing $filename...\n"; my $pdb = Palm::PDB->new(); $pdb->Load($filename); print "File $filename has type ", $pdb->{type}, " from creator ", $pdb->{creator}, "\n"; if($pdb->{creator} eq "QCBA") { print "Processing PCM data...\n"; process_wav($pdb); } elsif($pdb->{creator} eq "MP3P") { print "Processing MP3 file...\n"; process_mp3($pdb); } else { print "Unknown creator", $pdb->{creator}, "\n"; } } sub process_wav { my $pdb = shift; my $contained_creator = substr($pdb->{records}->[0]->{data}, 64, 4); if($contained_creator eq "QCBA") { print "Contains PDB data, processing again.\n"; my $tmpfile = records_to_tmpfile($pdb); print "Stored in $tmpfile\n"; my $newpdb = Palm::PDB->new(); $newpdb->Load($tmpfile); $newpdb->{name} = $pdb->{name}; process_wav($newpdb); } else { my $outfile = $pdb->{name}; $outfile .= ".wav" unless $outfile =~ /\.wav$/; print "Got regular data, saving to $outfile.\n"; my $rawspeed = substr($pdb->{records}->[0]->{data}, 10, 2); my $speed = unpack("n", $rawspeed); print "wave at $speed\n"; open(my $fh, "| sox -t raw -c 1 -r $speed -b -u - -t wav '$outfile'") or die "can't run sox: $!"; binmode($fh); syswrite($fh, $pdb->{records}->[0]->{data}, length $pdb->{records}->[0]->{data}, 12); shift @{$pdb->{records}}; foreach my $r (@{$pdb->{records}}) { syswrite($fh, $r->{data}); } close($fh); } } sub process_mp3 { my $pdb = shift; my $contained_creator = substr($pdb->{records}->[0]->{data}, 64, 4); if($contained_creator eq "MP3P") { print "Contains PDB data, processing again.\n"; my $tmpfile = records_to_tmpfile($pdb); print "Stored in $tmpfile\n"; my $newpdb = Palm::PDB->new(); $newpdb->Load($tmpfile); $newpdb->{name} = $pdb->{name}; process_mp3($newpdb); } else { my $outfile = $pdb->{name}; $outfile .= ".mp3" unless $outfile =~ /\.mp3$/; print "Got regular data, saving to $outfile.\n"; records_to_file($outfile, $pdb); } } sub records_to_file { my $filename = shift; my $pdb = shift; open(my $fh, "> $filename") or die "can't write $filename: $!"; binmode($fh); foreach my $r (@{$pdb->{records}}) { syswrite ($fh, $r->{data}); } close($fh); } sub records_to_tmpfile { my $pdb = shift; my $tmpdir = tempdir( CLEANUP => 0 ); my ($fh, $name) = tempfile( DIR => $tmpdir ); close($fh); records_to_file($name, $pdb); return $name; }