#include #include #include #include #include #include #include #include #include #define CARRIER_FREQ (carrier_freq ?: data_freq*4) #define MARK_FREQ (CARRIER_FREQ*2) #define SPACE_FREQ (CARRIER_FREQ/2) #define BIT_SIZE (sample_freq/data_freq) #define D2W_PCM_SIZE(x) ((x)*8*BIT_SIZE) #define D2W_PACK_SIZE(x) (D2W_PCM_SIZE(x)/2) #define W2D_UNPACK_SIZE(x) ((x)*2/(8*BIT_SIZE)) #define W2D_PCM_SIZE(x) (D2W_PCM_SIZE(W2D_UNPACK_SIZE(x))) #define wave_func(f, t) cos(2.0f*M_PI*(double)f*(double)t) #define pcm_encode(v) ((int)floor(((double)v+1.0f)/0.133333f)) #define pcm_decode(v) (((double)v*0.133334f)-1.0f) #define bit_freq(b) (b ? MARK_FREQ : SPACE_FREQ) int sample_freq = 44000; int carrier_freq = 0; int data_freq = 10; struct wav_header { char filetype_blockid[4]; int filesize; char fileformat_id[4]; char format_blockid[4]; int blocksize; short audioformat; short channels; int freq; int bytepersec; short byteperblock; short bitspersample; char data_blockid[4]; int datasize; }; struct wav_header *get_wav_header() { struct wav_header *wh; if ((wh = malloc(sizeof(*wh))) == NULL) return NULL; strcpy(wh->filetype_blockid, "RIFF"); strcpy(wh->fileformat_id, "WAVE"); strcpy(wh->format_blockid, "fmt "); wh->blocksize = 0x10; strcpy(wh->data_blockid, "data"); return wh; } void gen_wbit(int bit, int *res) { double t; int i; for (i = 0, t = 0; i < BIT_SIZE; i++, t += (1.0f/(double)sample_freq)) res[i] = pcm_encode(wave_func(bit_freq(bit), t)); } void gen_wbyte(char b, int *res) { int i; for (i = 0; i < 8; i++) { gen_wbit(b & 0x80 ? 1 : 0, res+(i*BIT_SIZE)); b = b << 1; } } void gen_wdata(char *data, int len, int *res) { int i; for (i = 0; i < len; i++) gen_wbyte(data[i], res+(i*8*BIT_SIZE)); } int get_bit(int *wbit) { int i; int found = 0; /* for (i = 0; i < BIT_SIZE; i++) fprintf(stderr, "%d ", wbit[i]); fprintf(stderr, "\n");*/ for (i = 1; i < BIT_SIZE; i++) { if (wbit[i] == wbit[0]) { found = 1; break; } } if (!found) return -1; #ifdef DEBUG fprintf(stderr, "get_bit(): i: %d\n", i); #endif if (sample_freq/i == MARK_FREQ) return 1; else if (sample_freq/i == SPACE_FREQ) return 0; return -2; } int get_byte(int *wbyte) { int i; char b = 0; int tmp; for (i = 0; i < 8; i++) { b = b << 1; tmp = get_bit(wbyte+(i*BIT_SIZE)); assert(tmp == 0 || tmp == 1); b |= tmp; } return b; } void wave_to_bytes(int *wbytes, int len, char *data) { int i; for (i = 0; i < len; i++) data[i] = get_byte(wbytes+(i*8*BIT_SIZE)); } void pack_wave(int *wbytes, int size, char *packdata) { int i; for (i = 0; i < size; i+=2) packdata[i/2] = (wbytes[i] << 4) | wbytes[i+1]; } void unpack_wave(char *packdata, int size, int *res) { int i; for (i = 0; i < size; i+=2) { res[i] = (packdata[i/2] & 0xf0) >> 4; res[i+1] = packdata[i/2] & 0xf; #ifdef DEBUG fprintf(stderr, "Unpacking wave %d to %d and %d\n", packdata[i/2], res[i], res[i+1]); #endif } } int read_wav(const char *path, char **res) { int fd; struct wav_header wh; int size, hdrsz, rdsz; char *data; fd = open(path, O_RDONLY); if (fd == -1) { perror("open"); return -1; } if ((hdrsz = read(fd, &wh, sizeof(wh))) == -1) { perror("read"); close(fd); return -1; } if (hdrsz != sizeof(wh)) { fprintf(stderr, "Invalid header size.\n"); close(fd); return -1; } size = wh.datasize; if (size != wh.filesize - 36) { fprintf(stderr, "Invalid sizes (file: %d, data: %d).\n", wh.filesize, size); close(fd); return -1; } data = malloc(size); bzero(data, size); if ((rdsz = read(fd, data, size)) == -1) { perror("read"); free(data); close(fd); return -1; } data[rdsz] = 0; close(fd); *res = data; return rdsz; } int read_raw(const char *path, char **res) { int fd; char *data; int rdsz; struct stat st; fd = open(path, O_RDONLY); if (fd == -1) { perror("open"); return -1; } if (fstat(fd, &st) == -1) { perror("fstat"); close(fd); return -1; } data = malloc(st.st_size); bzero(data, st.st_size); if ((rdsz = read(fd, data, st.st_size)) == -1) { perror("read"); free(data); close(fd); return -1; } data[rdsz] = 0; close(fd); *res = data; return rdsz; } void write_wav(const char *path, int size, char *packdata) { int fd; struct wav_header *wh; fd = open(path, O_WRONLY|O_TRUNC|O_CREAT, 00644); if (fd == -1) { perror("open"); return; } wh = get_wav_header(); wh->filesize = size + 44 - 8; wh->audioformat = 1; /* PCM */ wh->channels = 1; wh->freq = sample_freq; wh->bytepersec = data_freq*8; wh->byteperblock = 1; wh->bitspersample = 4; wh->datasize = size; write(fd, wh, sizeof(*wh)); write(fd, packdata, size); close(fd); #ifdef DEBUG fprintf(stderr, "Wrote %d bytes\n", sizeof(*wh)+size); #endif } void write_raw(const char *path, int size, char *data) { int fd; fd = open(path, O_WRONLY|O_TRUNC|O_CREAT, 00644); if (fd == -1) { perror("open"); return; } write(fd, data, size); close(fd); #ifdef DEBUG fprintf(stderr, "Wrote %d bytes\n", size); #endif } void usage(char *name) { fprintf(stderr, "Usage: %s [-h] [-s sample_freq] [-c carrier_freq] [-d data_freq] -i infile -o outfile -m mode\n" "\t\t-s sample_freq\tSample frequency (default: %d Hz\n" "\t\t-d data_freq\tData frequency, aka bit rate (default: %d)\n" "\t\t-c carrier_freq\tCarrier frequency. (default: data_freq*4)\n" "\t\t-i infile\tInput file or - for stdin\n" "\t\t-o outfile\tOutput file or - for stdout\n" "\t\t-m mode\t\tMode is either d2w for data-to-wave or w2d for wave-to-data\n", name, sample_freq, data_freq); exit(1); } int main(int ac, char **av) { int op, mode = 0; char infile[128]; char outfile[128]; bzero(infile, 128); bzero(outfile, 128); while ((op = getopt(ac, av, "s:c:d:i:o:m:h")) != EOF) { switch(op) { case 's': sample_freq = atoi(optarg); break; case 'd': data_freq = atoi(optarg); break; case 'i': strncpy(infile, optarg, 128); break; case 'o': strncpy(outfile, optarg, 128); break; case 'c': carrier_freq = atoi(optarg); break; case 'm': if (!strcmp(optarg, "d2w")) mode = 1; else if (!strcmp(optarg, "w2d")) mode = 2; break; case 'h': usage(av[0]); break; default: usage(av[0]); } } if (!*infile || !*outfile) { fprintf(stderr, "Missing infile or outfile.\n"); return 1; } if (!mode) { fprintf(stderr, "Mode not specified.\n"); return 1; } int dsize; char *indata, *outdata; if (mode == 1) { if ((dsize = read_raw(infile, &indata)) == -1) { fprintf(stderr, "Error while reading input file.\n"); return 1; } #ifdef DEBUG fprintf(stderr, "Data read (%d bytes): %s\n", dsize, indata); #endif int *pcm_tmp = malloc(D2W_PCM_SIZE(dsize)*sizeof(int)); outdata = malloc(D2W_PACK_SIZE(dsize)); gen_wdata(indata, dsize, pcm_tmp); pack_wave(pcm_tmp, D2W_PCM_SIZE(dsize), outdata); write_wav(outfile, D2W_PACK_SIZE(dsize), outdata); free(pcm_tmp); } else { if ((dsize = read_wav(infile, &indata)) == -1) { fprintf(stderr, "Error while reading input file.\n"); return 1; } #ifdef DEBUG fprintf(stderr, "Data read (%d bytes). Translate into %d bytes.\n", dsize, W2D_UNPACK_SIZE(dsize)); #endif int *pcm_tmp = malloc(W2D_PCM_SIZE(dsize)*sizeof(int)); outdata = malloc(W2D_UNPACK_SIZE(dsize)); unpack_wave(indata, W2D_PCM_SIZE(dsize), pcm_tmp); wave_to_bytes(pcm_tmp, W2D_UNPACK_SIZE(dsize), outdata); write_raw(outfile, W2D_UNPACK_SIZE(dsize), outdata); free(pcm_tmp); } free(indata); free(outdata); return 0; }