/* Now that we have succesfully written sam2wav.c, a program to read a .sample file and output a valid mono wav file, we have to write a program to go the other way, from mono .wav to .sample. Here it is ... */ #include "hacks.h" #define UWORD unsigned short #define buffer_size 16000 /* global vars */ int data_chunk_size; void usage(); int read_intel_long(FILE *, int *); void process_buffer(UWORD *, int); int read_chunk_name(FILE *, char *); int check_wav_header(FILE *); void process_buffer(UWORD *, int); void usage() { fprintf(stderr, "usage: wav2sam <.sample_file>\n\ .wav file must be 16-bit PCM(uncompressed) mono\n"); } void usage_exit() { usage(); exit(DOOPS); } int read_intel_word(f, W) /* returns word value in a longword int */ FILE *f; int *W; { unsigned char *temp; int c; temp = (unsigned char *) W; if ((c = fgetc(f)) eq EOF) return(c); temp[0] = c; if ((c = fgetc(f)) eq EOF) return(c); temp[1] = c; temp[2] = temp[3] = 0; return(OKDOKEY); } int read_intel_long(f, L) FILE *f; /* read from here */ int *L; /* return it here */ { int status; if ((status = fread(L, 4, 1, f)) neq 1) { fprintf(stderr, "read_intel_long: hit EOF\n"); return(EOF); } fprintf(stderr, "read_intel_long: returning %d\n", *L); return(OKDOKEY); } int read_chunk_name(f, cn) FILE *f; /* read from here */ char *cn; /* must have at least 4 bytes */ { int status; if ((status = fread(&cn[0], 4, 1, f)) neq 1) { return(EOF); } return(OKDOKEY); } int check_wav_header(f) /* read .wav header, have file point to first byte of data */ FILE *f; /* already opened and at first byte */ { int status, fmt_size, dummy; int fuck_temp; char cn[5]; cn[4] = '\0'; /* stick null on end of string */ status = read_chunk_name(f, &cn[0]); if (status neq OKDOKEY) { fprintf(stderr, "check_wav_header: early EOF\n"); return(DOOPS); } if (stricmp(cn, "RIFF") neq 0) { fprintf(stderr, "check_wav_header: not a RIFF wav file!\n"); return(DOOPS); } if ((status = read_intel_long(f, &dummy)) neq OKDOKEY) { fprintf(stderr, "check_wav_header: error getting wav file size\n"); return(DOOPS); } status = read_chunk_name(f, &cn[0]); if (status neq OKDOKEY) { fprintf(stderr, "check_wav_header: early EOF\n"); return(DOOPS); } if (stricmp(cn, "WAVE") neq 0) { fprintf(stderr, "check_wav_header: not a WAVE file!\n"); return(DOOPS); } /* from here on, wav is a series of chunks, just liek the IFF file format */ for (;;) { status = read_chunk_name(f, &cn[0]); fuck_temp = stricmp(cn, "fmt "); if (fuck_temp eq 0) { fprintf(stderr, "parsing \"fmt \" chunk\n"); if ((status = read_intel_long(f, &fmt_size)) neq OKDOKEY) { fprintf(stderr, "check_wav_header: error reading size of fmt chunk\n"); return(DOOPS); } if (fmt_size < 16) { fprintf(stderr, "check_wav_header: warning: fmt chunk size less than 16. aborting\n"); return(DOOPS); } if (fmt_size neq 16) { fprintf(stderr, "check_wav_header: warning: fmt chunk size is not 16. could be trouble\n"); } /* wav type - 16 bit value. we want it to be "1" */ if ((status = read_intel_word(f, &dummy)) neq OKDOKEY) { fprintf(stderr, "check_wav_header: error reading wave_type\n"); return(DOOPS); } if (dummy neq 1) { fprintf(stderr, "check_wav_header: wave_type is not one. Aborting\n"); return(DOOPS); } if ((status = read_intel_word(f, &dummy)) neq OKDOKEY) { fprintf(stderr, "check_wav_header: error reading number of channels\n"); return(DOOPS); } if (dummy neq 1) { fprintf(stderr, "check-wave_header: wav_file is not mono\n"); return(DOOPS); } /* at this point, we've read what we want to from the FMT header, so lets just skip to the end of the fmt header */ fmt_size += -4; while (fmt_size--) { if ((dummy = fgetc(f)) eq EOF) { fprintf(stderr, "check_wav_header: error reading through fmt header\n"); return(DOOPS); } } } else { /* not fmt chunk. see if it is data chunk */ if (stricmp(cn, "DATA") eq 0) { // at raw data chunk! At last! if ((status = read_intel_long(f, &data_chunk_size)) neq OKDOKEY) { fprintf(stderr, "check_wav_header: error reading size of DATA chunk\n"); return(DOOPS); } return(OKDOKEY); /* read to read data! Done with header! Yea! */ } else { /* unknown/ignorable chunk */ /* firstly, read size of unknown chunk */ if ((status = read_intel_long(f, &dummy)) neq OKDOKEY) { fprintf(stderr, "check_wav_header: error reading size of fmt chunk\n"); return(DOOPS); } while (dummy--) { if ((status = fgetc(f)) eq EOF) { fprintf(stderr, "check_wav_header: error reading past unknown chunk\n"); return(DOOPS); } } } } } } void process_buffer(b, len) /* convert signed intel 16bit to unsigned motorola 16bit*/ UWORD *b; int len; { unsigned char *p1, *p2; unsigned char hold; p1 = (unsigned char *) &b[0]; p2 = (unsigned char *) &b[0]; p2++; while (len--) { if (*p1 eq 0x00) { if (*p2 eq 0x80) { *p1 = 0x01; } } hold = *p1; *(p1++) = *p2 ^ 0x80; /* flip sign bit */ *(p2++) = hold; p1++; p2++; } } /* this is lame ... */ int min(m1, m2) int m1; int m2; { if (m1 > m2) return(m2); return(m1); } main(argc, argv) int argc; char *argv[]; { int status, length_error, read_this_much; FILE *f1, *f2; UWORD *buffer; if (argc eq 0) exit(DOOPS); if (argc neq 3) usage_exit(); if ((buffer = calloc(buffer_size, 2)) eq NULL) { /* size in samples */ fprintf(stderr, "memory failure\n"); exit(DOOPS); } if ((f1 = fopen(argv[1], "rb")) eq NULL) { free(buffer); fprintf(stderr, "error opening input file \"%s\"\n", argv[1]); exit(DOOPS); } if ((f2 = fopen(argv[2], "wb")) eq NULL) { free(buffer); fclose(f1); fprintf(stderr, "error creating output file \"%s\"\n", argv[2]); exit(DOOPS); } status = check_wav_header(f1); if (status eq DOOPS) { fprintf(stderr, "error checking wave header\n"); exit(DOOPS); } data_chunk_size /= 2; /* convert byte size to word or sample size */ fprintf(stderr, "data chunk size (in wav file) is: %d\n", data_chunk_size); /* OK. go to main loop now */ length_error = OKDOKEY; while (data_chunk_size) { read_this_much = min(buffer_size, data_chunk_size); if ((status = fread(buffer, 2, read_this_much, f1)) neq read_this_much) { /* file ended too soon. do an error message, then keep running, at least enough to write what *did* get written to the file */ fprintf(stderr, "premature EOF on input wav file\n"); if (status < 0) status = 0; data_chunk_size = read_this_much = status; length_error = DOOPS; } process_buffer(buffer, read_this_much); if (read_this_much > 0) { if ((status = fwrite(buffer, 2, read_this_much, f2)) neq read_this_much) { fprintf(stderr, "error writing to output file\n"); free(buffer); fclose(f2); fclose(f1); exit(DOOPS); } } data_chunk_size -= read_this_much; } fclose(f2); free(buffer); fclose(f1); exit(OKDOKEY); } /* actual end of this file */