Megtaláltam a forrást, ami azért "veszett el", mert egy progiba kezdtem összerakni az összes WAV-ba konvertálós emulátor formátumot (ez az "emuwav", fent van a honlapomon is asszem).
Nos ahogy nézem a Homelab-es HTP2WAV-ot még ráadásul Linuxon írhattam, mert getopt-ot használok.
Ide bemásolom a kódot, elfér... ennyi az egész. Ahogy nézem nem valami jó a frekvenciakonverzió benne, de úgy emlékszem jól működött.
üdv
Attila
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
/* WAV file header structure */
/* should be 1-byte aligned */
#pragma pack(1)
struct wav_header {
char riff[4];
unsigned int rLen;
char WAVEfmt[8];
unsigned int fLen; /* 0x1020 */
unsigned short wFormatTag; /* 0x0001 */
unsigned short nChannels; /* 0x0001 */
unsigned int nSamplesPerSec;
unsigned int nAvgBytesPerSec; // nSamplesPerSec*nChannels*(nBitsPerSample%8)
unsigned short nBlockAlign; /* 0x0001 */
unsigned short nBitsPerSample; /* 0x0008 */
char datastr[4];
unsigned int data_size;
} wave = {
'R','I','F','F',
0,
'W','A','V','E','f','m','t',' ',
16,
1,
1,
44100,
44100,
1,
8,
'd','a','t','a',
0
};
#pragma pack()
static unsigned char p_gain = 60;
const unsigned char p_silence = 0;
static unsigned int wav_sample_count = 0;
static unsigned int cycles_to_samples(unsigned int cycles)
{
return ( cycles * wave.nSamplesPerSec + 0*1500000) / 3000000;
}
static void filter_output( unsigned char level, FILE *wavfile)
{
static double hp_accu = 0, lp_accu = 0;
double in = level * 1.0;
double clipped = lp_accu - hp_accu;
unsigned char out;
if ( clipped >=127.0 )
clipped = 127.0;
else if ( clipped<-127.0 )
clipped = -127;
out = ((unsigned char)(clipped)) ^ 0x80;
lp_accu += ((double)in - lp_accu) * 0.5577;
hp_accu += (lp_accu - hp_accu) * 0.0070984;
fputc( out, wavfile);
}
static void dump_bit(FILE *fp, unsigned int bit)
{
unsigned int i, j;
unsigned int period = 1 << bit;
for (j=0; j<period; j++) {
for( i=0; i<cycles_to_samples(546/period); i++) /* 546 ? */
filter_output( p_gain, fp);
for( i=0; i<cycles_to_samples(3878/period); i++)
filter_output( p_silence, fp);
}
}
static void dump_last_bit(FILE *fp, unsigned int bit)
{
unsigned int i, j;
unsigned int period = 1 << bit;
for (j=0; j<period; j++) {
for( i=0; i<cycles_to_samples(680/period); i++)
filter_output( p_gain, fp);
for( i=0; i<cycles_to_samples(3878/period); i++)
filter_output( p_silence, fp);
}
}
static void close_wav(FILE *outfile)
{
int foo = ftell(outfile) - 8;
fseek(outfile, 4, SEEK_SET);
fwrite(&foo,sizeof(foo),1,outfile);
foo = foo-sizeof(wave) + 8;
fseek(outfile,sizeof(wave)-sizeof(unsigned long),SEEK_SET);
fwrite(&foo,sizeof(foo),1,outfile);
fclose(outfile);
}
static void output_wav_byte(FILE *wavfile, unsigned char byte)
{
unsigned int bc = 7;
while ( --bc ) {
dump_bit( wavfile, (byte>>(7-bc))&1);
}
dump_last_bit( wavfile, byte&1);
}
static void init_wav(FILE *wavfile)
{
unsigned int i, j;
fwrite( &wave, sizeof(wave), 1, wavfile);
/* Lead in silence */
for( j=0; j<cycles_to_samples(55300); j++)
filter_output( p_silence, wavfile);
for (i=0; i<12; i++) {
for( j=0; j<cycles_to_samples(2656); j++)
filter_output( p_silence, wavfile);
for( j=0; j<cycles_to_samples(2656); j++)
filter_output( p_gain, wavfile);
}
for( i=0; j<cycles_to_samples(25238); j++)
filter_output( p_silence, wavfile);
}
static void process_htp(FILE *input, FILE* output)
{
unsigned char in;
while (!feof( input ) ) {
fread( &in, 1, 1, input);
output_wav_byte( output, in);
}
fclose( input );
}
static void print_usage()
{
printf( "HTP2WAV v1.0\n");
printf( "Copyright 2004 by Attila Grosz\n");
printf( "Usage:\n");
printf( "htp2wav -i <input_filename> -o <output_filename>\n");
printf( "Command line option:\n");
printf( "-g <gain> : gain, must be between 1 and 7 (default: 4)\n");
printf( "-h : prints this text\n");
exit(1);
}
int main(int argc, char *argv[])
{
int finished = 0;
int arg1, arg2;
FILE *htp = 0, *wav = 0;
while (!finished) {
switch (getopt (argc, argv, "?hf:i:o:g:")) {
case -1:
case ':':
finished = 1;
break;
case '?':
case 'h':
print_usage();
break;
case 'f':
if ( !sscanf( optarg, "%i", &arg1 ) ) {
fprintf( stderr, "Error parsing argument for '-f'.\n");
exit(2);
} else {
if ( arg1!=48000 && arg1!=44100 && arg1!=22050 &&
arg1!=11025 && arg1!=8000 ) {
fprintf( stderr, "Unsupported sample rate: %i.\n", arg1);
fprintf( stderr, "Supported sample rates are: 48000, 44100, 22050, 11025 and 8000.\n");
exit(3);
}
wave.nSamplesPerSec = arg1;
wave.nAvgBytesPerSec = wave.nSamplesPerSec*wave.nChannels
*(wave.nBitsPerSample%8);
}
break;
case 'g':
if ( !sscanf( optarg, "%i", &arg1 ) ) {
fprintf( stderr, "Error parsing argument for '-g'.\n");
exit(2);
} else {
if ( arg1<0 || arg1>7 ) {
fprintf( stderr, "Illegal gain value: %i.\n", arg1);
fprintf( stderr, "Gain must be between 1 and 7.\n");
}
p_gain = arg1*0x0f;
}
break;
case 'i':
if ( !(htp = fopen( optarg, "rb")) ) {
fprintf( stderr, "Error opening %s.\n", optarg);
exit(4);
}
break;
case 'o':
if ( !(wav = fopen( optarg, "wb")) ) {
fprintf( stderr, "Error opening %s.\n", optarg);
exit(4);
}
break;
default:
break;
}
}
if ( !htp ) {
print_usage();
} else if ( !wav ) {
print_usage();
} else {
init_wav(wav);
process_htp(htp, wav);
close_wav( wav );
}
return 0;
}