/* ******************************************************************************* * Sonia Nagala ******************************************************************************* * 12/16/06 * Music220A Final Project * quantize.c ******************************************************************************* * Starter code provided by hw1 assignment of Music422. * * Added code to store only the num_bits most significant bits in each sample. ******************************************************************************* */ #include #include #include // provides getopt #include #include "codec.h" #include "file.h" #include "audiofile.h" #define BLOCKSIZE 256 typedef struct { bool encode; } params_t; params_t params; void quantize(codec_file_p in_fp, codec_file_p out_fp, int num_bits); codec_err_t vector_encode(codec_vector_p v1, int8_t* encoded, uint16_t frames, int num_bits); codec_err_t vector_decode(codec_vector_p v1, int8_t* encoded, uint16_t frames, int num_bits); void scale(codec_file_p in_fp, codec_file_p out_fp, float gain); void set_default_params(params_t *params); void usage(); int main(int argc, char **argv) { int ch; extern char *optarg; extern int optind; char *in_filename, *out_filename; int num_bits; codec_err_t err; codec_file_t input_fp, output_fp; codec_fileinfo_p in_info = &input_fp.info; codec_fileinfo_p out_info = &output_fp.info; set_default_params(¶ms); // type 'man getopt' at the console for more info while ((ch = getopt(argc, argv, "e")) != -1) switch(ch) { /*case 'e': if(optarg == '1') params.encode = true; else params.encode = false; break;*/ default: usage(); exit(0); } argc -= optind; argv += optind; // read the filenames from the command line if (argc >= 3) { in_filename = *argv++; out_filename = *argv++; num_bits = atoi(*argv++); } else { usage(); exit(0); } // open the audio files err = audiofile_open(in_filename, AUDIOFILE_READ, &input_fp); if (err) exit(1); // copy the parameters we read in for the input file to the info structure for // the output file so that we open it with the identical settings to the input file. file_copy_fileinfo(&input_fp, &output_fp); err = audiofile_open(out_filename, AUDIOFILE_WRITE, &output_fp); if (err) exit(1); printf("\tinput file: %s (%d chans, %dkHz, %u bits, %d frames)\n", in_filename,in_info->channels, in_info->srate, in_info->bits_per_sample, in_info->frames); // call our processing function as defined below. Change this line to call your // own processing functions. //scale(&input_fp, &output_fp, params.gain); quantize(&input_fp, &output_fp, num_bits); printf("\toutput file: %s (%d chans, %dkHz, %u bits, %d frames)\n\t\tcompressed to %d bit sample size\n", out_filename,out_info->channels, out_info->srate, out_info->bits_per_sample, out_info->frames, num_bits); // close the audio files audiofile_close(&input_fp); audiofile_close(&output_fp); exit(0); } // QUANTIZE IS BASED ON SCALE BUT CALLS VECTOR_ENCODE AND VECTOR_DECODE void quantize(codec_file_p in_fp, codec_file_p out_fp, int num_bits) { uint8_t c, channels; int8_t encoded[256]; FILE * enc_fp; codec_err_t err; codec_vector_set_p data_vectors; // pointer to an array of data vectors codec_vector_set_p data_vectors_enc; codec_vector_set_p data_vectors_dec; // if the num channels was know this would equate to: // codec_vector_p data_vectors[num_channels]; // one frame is one sample x number of channels in the file // ie. for a 16-bit stereo file one frame = 4 bytes or 2 16-bit words uint32_t frames_in_file, frame_count = 0; int32_t frames_read; // must to be signed because the audiofile functions return // negative values for errors. // read some commonly used values in from the input file's info // structure for convenience. channels = in_fp->info.channels; frames_in_file = in_fp->info.frames; // Allocate the storage we'll use to read the data from the sound file into. // The result will be an array of 'channels' vectors, each BLOCKSIZE in length. // Which is equivalent to // codec_float_t my_vector[channels][BLOCKSIZE]; // had we known both quantities at compile time. // Note we pass a point to data_vectors because it will have a value assigned // to it inside vector_set_alloc. err = vector_set_alloc(BLOCKSIZE, channels, &data_vectors); if (err != ERR_NONE) { printf("Error allocating data vector\n"); return; } enc_fp = fopen("encodedfile.enc","w"); do { // read in a block of frames // Returns the number of frames actually read (may be less than BLOCKSIZE) // if we're near the end of the file. Returns < 0 if an error occurs. Should // never return 0 in this case unless the frame_count logic is incorrect. frames_read = audiofile_read(in_fp, BLOCKSIZE, data_vectors); if (frames_read < 0) { printf("Error reading from audio file at line %d\n",__LINE__); frame_count = frames_in_file; // bail out } else { // do the actual scaling on each channel vector of samples // (in place - see vector.h) for (c=0; c < channels; c++) { vector_encode(data_vectors[c], encoded, frames_read, num_bits); // HERE IT WRITES THE 8-BIT ENCODED VALUES INTO ENCODED.ENC fwrite(&encoded, 1, frames_read, enc_fp); // write the result to the output file // NOTE: we use frames_read rather than blocksize to accomodate for // the final block of the file which will likely not be BLOCKSIZE in length //printf("%d \n", frames_read); vector_decode(data_vectors[c], encoded, frames_read, num_bits); } audiofile_write(out_fp, frames_read, data_vectors); // Keep track of the number of frames processed to know when to stop. frame_count += frames_read; } } while (frame_count < frames_in_file); fclose(enc_fp); // free the memory used by the data vectors. vector_set_dealloc(data_vectors, channels); return; } ////////////////////////////////////////////////////// // VECTOR_ENCODE CONVERTS THE FLOAT VALUES OF EACH SAMPLE INTO SIGNED 8-BIT INTEGERS // BY FIRST CONVERTING TO 16-BIT INTEGERS AND DIVIDING BY 256, THUS CUTTING OFF THE // LOWEST 8 BITS OF INFORMATION. (IT ALSO SCALES BY 2^15 FROM FLOAT TO INT) codec_err_t vector_encode(codec_vector_p v1, int8_t* encoded, uint16_t frames, int num_bits) { int i; int16_t temp; for (i = 0; i < frames; i++) { temp = (int16_t)(v1[i] * 32768); // Scale number ranged -1 to 1 to -32768 to 32768 encoded[i] = temp >> (16 - num_bits);// Shift bits to only contain num_bits most // significant bits. } } /////////////////////////////////////////////////////// // VECTOR_DECODE CONVERTS THE 8-BIT INTEGERS TO 16-BIT, MULTIPLIES BY 256, AND // RE-SCALES BY 2^15 TO CONVERT BACK TO FLOAT VALUES, WHICH IT REINSERTS INTO // THE SAMPLES. codec_err_t vector_decode(codec_vector_p v1, int8_t* encoded, uint16_t frames, int num_bits) { int i; int16_t temp; for(i = 0; i < frames; i++){ temp = encoded[i]; v1[i] = (temp << (16 - num_bits)) / 32768.0; // Shift most significant bits back // to their original position // Then scale number ranged from -32768 -> // 32768 back to -1 -> 1. } } void set_default_params(params_t *params) { params->encode=true; } void usage() { printf("quantize: usage\n\tquantize inputfile outputfile num_bits\n"); printf("\tinputfile: \t16-bit audio file name\n"); printf("\toutputfile: \toutput audio file name (will be overwritten!)\n"); printf("\tnum_bits: \tnumber of bits to store per sample (8 or less)\n"); }