int ALACDecoder_init(decoders_ALACDecoder *self, PyObject *args, PyObject *kwds) { char *filename; static char *kwlist[] = {"filename", NULL}; unsigned i; self->filename = NULL; self->file = NULL; self->bitstream = NULL; self->audiotools_pcm = NULL; self->frameset_channels = array_ia_new(); self->frame_channels = array_ia_new(); self->uncompressed_LSBs = array_i_new(); self->residuals = array_i_new(); for (i = 0; i < MAX_CHANNELS; i++) { self->subframe_headers[i].qlp_coeff = array_i_new(); } if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &filename)) return -1; /*open the alac file as a BitstreamReader*/ if ((self->file = fopen(filename, "rb")) == NULL) { PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename); return -1; } else { self->bitstream = br_open(self->file, BS_BIG_ENDIAN); } self->filename = strdup(filename); self->bitstream->mark(self->bitstream); if (parse_decoding_parameters(self)) { self->bitstream->unmark(self->bitstream); return -1; } else { self->bitstream->rewind(self->bitstream); } /*seek to the 'mdat' atom, which contains the ALAC stream*/ if (seek_mdat(self->bitstream) == ERROR) { self->bitstream->unmark(self->bitstream); PyErr_SetString(PyExc_ValueError, "Unable to locate 'mdat' atom in stream"); return -1; } else { self->bitstream->unmark(self->bitstream); } /*setup a framelist generator function*/ if ((self->audiotools_pcm = open_audiotools_pcm()) == NULL) return -1; return 0; }
int ReplayGainReader_init(replaygain_ReplayGainReader *self, PyObject *args, PyObject *kwds) { self->pcmreader = NULL; self->channels = array_ia_new(); self->white_noise = NULL; self->audiotools_pcm = NULL; double replaygain; double peak; if (!PyArg_ParseTuple(args, "O&dd", pcmreader_converter, &(self->pcmreader), &(replaygain), &(peak))) return -1; if ((self->white_noise = open_dither()) == NULL) return -1; if ((self->audiotools_pcm = open_audiotools_pcm()) == NULL) return -1; self->multiplier = powl(10.0l, replaygain / 20.0l); if (self->multiplier > 1.0l) self->multiplier = 1.0l / peak; return 0; }
void ReplayGainReader_dealloc(replaygain_ReplayGainReader* self) { if (self->pcmreader != NULL) self->pcmreader->del(self->pcmreader); self->channels = array_ia_new(); if (self->white_noise != NULL) self->white_noise->close(self->white_noise); Py_XDECREF(self->audiotools_pcm); self->ob_type->tp_free((PyObject*)self); }
int FlacDecoder_init(decoders_FlacDecoder *self, PyObject *args, PyObject *kwds) { char* filename; int stream_offset = 0; self->filename = NULL; self->file = NULL; self->bitstream = NULL; self->seektable = array_o_new((ARRAY_COPY_FUNC)seekpoint_copy, free, NULL); self->subframe_data = array_ia_new(); self->residuals = array_i_new(); self->qlp_coeffs = array_i_new(); self->framelist_data = array_i_new(); self->audiotools_pcm = NULL; self->remaining_samples = 0; if (!PyArg_ParseTuple(args, "si|i", &filename, &(self->channel_mask), &stream_offset)) return -1; if (self->channel_mask < 0) { PyErr_SetString(PyExc_ValueError, "channel_mask must be >= 0"); return -1; } if (stream_offset < 0) { PyErr_SetString(PyExc_ValueError, "stream offset must be >= 0"); return -1; } /*open the flac file*/ self->file = fopen(filename, "rb"); if (self->file == NULL) { PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename); return -1; } else { self->bitstream = br_open(self->file, BS_BIG_ENDIAN); } /*skip the given number of bytes, if any*/ if (stream_offset != 0) fseek(self->file, stream_offset, SEEK_SET); self->filename = strdup(filename); /*read the STREAMINFO block, SEEKTABLE block and setup the total number of samples to read*/ if (flacdec_read_metadata(self->bitstream, &(self->streaminfo), self->seektable)) { self->streaminfo.channels = 0; return -1; } self->remaining_samples = self->streaminfo.total_samples; /*initialize the output MD5 sum*/ audiotools__MD5Init(&(self->md5)); self->perform_validation = 1; self->stream_finalized = 0; /*setup a framelist generator function*/ if ((self->audiotools_pcm = open_audiotools_pcm()) == NULL) return -1; /*place mark at beginning of stream in case seeking is needed*/ self->bitstream->mark(self->bitstream); /*mark stream as not closed and ready for reading*/ self->closed = 0; return 0; }
static void alac_order_to_wave_order(array_ia* alac_ordered) { array_ia* wave_ordered = array_ia_new(); array_i* wave_ch; unsigned i; wave_ordered->resize(wave_ordered, alac_ordered->len); switch (alac_ordered->len) { case 2: wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[0]); /*left*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[1]); /*right*/ break; case 1: wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[0]); /*center*/ break; case 3: wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[1]); /*left*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[2]); /*right*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[0]); /*center*/ break; case 4: wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[1]); /*left*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[2]); /*right*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[0]); /*center*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[3]); /*back center*/ break; case 5: wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[1]); /*left*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[2]); /*right*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[0]); /*center*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[3]); /*back left*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[4]); /*back right*/ break; case 6: wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[1]); /*left*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[2]); /*right*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[0]); /*center*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[5]); /*LFE*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[3]); /*back left*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[4]); /*back right*/ break; case 7: wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[1]); /*left*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[2]); /*right*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[0]); /*center*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[6]); /*LFE*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[3]); /*back left*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[4]); /*back right*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[5]); /*back center*/ break; case 8: wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[3]); /*left*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[4]); /*right*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[0]); /*center*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[7]); /*LFE*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[5]); /*back left*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[6]); /*back right*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[1]); /*left of center*/ wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[2]); /*right of center*/ break; default: for (i = 0; i < alac_ordered->len; i++) { wave_ch = wave_ordered->append(wave_ordered); wave_ch->swap(wave_ch, alac_ordered->_[i]); } break; } wave_ordered->swap(wave_ordered, alac_ordered); wave_ordered->del(wave_ordered); }
PyObject* ReplayGain_title_gain(replaygain_ReplayGain *self, PyObject *args) { double title_gain; double title_peak = 0.0; pcmreader* pcmreader = NULL; /*read PCMReader-compatible object from args*/ if (!PyArg_ParseTuple(args, "O&", pcmreader_converter, &pcmreader)) { return NULL; } else { array_ia* channels = array_ia_new(); array_fa* channels_f = array_fa_new(); const int32_t peak_shift = 1 << (pcmreader->bits_per_sample - 1); if (pcmreader->sample_rate != self->sample_rate) { PyErr_SetString(PyExc_ValueError, "pcmreader's sample rate doesn't match"); pcmreader->del(pcmreader); channels->del(channels); channels_f->del(channels_f); return NULL; } /*read a FrameList object from PCMReader*/ if (pcmreader->read(pcmreader, 4096, channels)) { pcmreader->del(pcmreader); channels->del(channels); channels_f->del(channels_f); return NULL; } /*while FrameList contains more samples*/ while (channels->_[0]->len) { unsigned c; /*ensure FrameList only contains 1 or 2 channels*/ if ((channels->len != 1) && (channels->len != 2)) { PyErr_SetString(PyExc_ValueError, "FrameList must contain only 1 or 2 channels"); pcmreader->del(pcmreader); channels->del(channels); channels_f->del(channels_f); return NULL; } /*if only one channel, duplicate it to the other channel*/ channels->_[0]->copy(channels->_[0], channels->append(channels)); channels_f->reset(channels_f); /*convert left and right channels to doubles, (but *not* doubles between -1.0 and 1.0) and store peak values*/ for (c = 0; c < 2; c++) { array_i* channel_i = channels->_[c]; array_f* channel_f = channels_f->append(channels_f); int i; double peak; channel_f->resize(channel_f, channel_i->len); switch (pcmreader->bits_per_sample) { case 8: for (i = 0; i < channel_i->len; i++) { a_append(channel_f, (double)(channel_i->_[i] << 8)); peak = ((double)(abs(channel_i->_[i])) / peak_shift); title_peak = MAX(title_peak, peak); self->album_peak = MAX(self->album_peak, peak); } break; case 16: for (i = 0; i < channel_i->len; i++) { a_append(channel_f, (double)(channel_i->_[i])); peak = ((double)(abs(channel_i->_[i])) / peak_shift); title_peak = MAX(title_peak, peak); self->album_peak = MAX(self->album_peak, peak); } break; case 24: for (i = 0; i < channel_i->len; i++) { a_append(channel_f, (double)(channel_i->_[i] >> 8)); peak = ((double)(abs(channel_i->_[i])) / peak_shift); title_peak = MAX(title_peak, peak); self->album_peak = MAX(self->album_peak, peak); } break; default: PyErr_SetString(PyExc_ValueError, "unsupported bits per sample"); pcmreader->del(pcmreader); channels->del(channels); channels_f->del(channels_f); return NULL; } } /*perform actual gain analysis on channels*/ if (ReplayGain_analyze_samples(self, channels_f->_[0]->_, channels_f->_[1]->_, channels_f->_[0]->len, 2) == GAIN_ANALYSIS_ERROR) { PyErr_SetString(PyExc_ValueError, "ReplayGain calculation error"); pcmreader->del(pcmreader); channels->del(channels); channels_f->del(channels_f); return NULL; } /*read next FrameList object from PCMReader*/ if (pcmreader->read(pcmreader, 4096, channels)) { pcmreader->del(pcmreader); channels->del(channels); channels_f->del(channels_f); return NULL; } } /*deallocate temporary variables*/ pcmreader->del(pcmreader); channels->del(channels); channels_f->del(channels_f); /*return calculated title gain and title peak*/ /*if enough samples have been read*/ if ((title_gain = ReplayGain_get_title_gain(self)) != GAIN_NOT_ENOUGH_SAMPLES) { return Py_BuildValue("(d,d)", title_gain, title_peak); } else { PyErr_SetString(PyExc_ValueError, "Not enough samples to perform calculation"); return NULL; } } }
PyObject* encoders_encode_alac(PyObject *dummy, PyObject *args, PyObject *keywds) { static char *kwlist[] = {"file", "pcmreader", "block_size", "initial_history", "history_multiplier", "maximum_k", "minimum_interlacing_leftweight", "maximum_interlacing_leftweight", NULL}; PyObject *file_obj; FILE *output_file; BitstreamWriter *output = NULL; PyObject *pcmreader_obj; pcmreader* pcmreader; struct alac_context encoder; array_ia* channels = array_ia_new(); unsigned frame_file_offset; PyObject *log_output; alacenc_init_encoder(&encoder); encoder.options.minimum_interlacing_leftweight = 0; encoder.options.maximum_interlacing_leftweight = 4; /*extract a file object, PCMReader-compatible object and encoding options*/ if (!PyArg_ParseTupleAndKeywords( args, keywds, "OOiiii|ii", kwlist, &file_obj, &pcmreader_obj, &(encoder.options.block_size), &(encoder.options.initial_history), &(encoder.options.history_multiplier), &(encoder.options.maximum_k), &(encoder.options.minimum_interlacing_leftweight), &(encoder.options.maximum_interlacing_leftweight))) return NULL; /*transform the Python PCMReader-compatible object to a pcm_reader struct*/ if ((pcmreader = open_pcmreader(pcmreader_obj)) == NULL) { return NULL; } encoder.bits_per_sample = pcmreader->bits_per_sample; /*determine if the PCMReader is compatible with ALAC*/ if ((pcmreader->bits_per_sample != 16) && (pcmreader->bits_per_sample != 24)) { PyErr_SetString(PyExc_ValueError, "bits per sample must be 16 or 24"); goto error; } /*convert file object to bitstream writer*/ if ((output_file = PyFile_AsFile(file_obj)) == NULL) { PyErr_SetString(PyExc_TypeError, "file must by a concrete file object"); goto error; } else { output = bw_open(output_file, BS_BIG_ENDIAN); bw_add_callback(output, alac_byte_counter, &(encoder.mdat_byte_size)); } #else int ALACEncoder_encode_alac(char *filename, FILE *input, int block_size, int initial_history, int history_multiplier, int maximum_k) { FILE *output_file; BitstreamWriter *output = NULL; pcmreader *pcmreader; struct alac_context encoder; array_ia* channels = array_ia_new(); unsigned frame_file_offset; alacenc_init_encoder(&encoder); encoder.options.block_size = block_size; encoder.options.initial_history = initial_history; encoder.options.history_multiplier = history_multiplier; encoder.options.maximum_k = maximum_k; encoder.options.minimum_interlacing_leftweight = 0; encoder.options.maximum_interlacing_leftweight = 4; output_file = fopen(filename, "wb"); /*assume CD quality for now*/ pcmreader = open_pcmreader(input, 44100, 2, 0x3, 16, 0, 1); encoder.bits_per_sample = pcmreader->bits_per_sample; /*convert file object to bitstream writer*/ output = bw_open(output_file, BS_BIG_ENDIAN); bw_add_callback(output, alac_byte_counter, &(encoder.mdat_byte_size)); #endif /*write placeholder mdat header*/ output->write(output, 32, 0); output->write_bytes(output, (uint8_t*)"mdat", 4); /*write frames from pcm_reader until empty*/ if (pcmreader->read(pcmreader, encoder.options.block_size, channels)) goto error; while (channels->_[0]->size > 0) { #ifndef STANDALONE Py_BEGIN_ALLOW_THREADS #endif /*log the number of PCM frames in each ALAC frameset*/ encoder.frame_log->_[LOG_SAMPLE_SIZE]->append( encoder.frame_log->_[LOG_SAMPLE_SIZE], channels->_[0]->size); frame_file_offset = encoder.mdat_byte_size; /*log each frameset's starting offset in the mdat atom*/ encoder.frame_log->_[LOG_FILE_OFFSET]->append( encoder.frame_log->_[LOG_FILE_OFFSET], frame_file_offset); alac_write_frameset(output, &encoder, channels); /*log each frame's total size in bytes*/ encoder.frame_log->_[LOG_BYTE_SIZE]->append( encoder.frame_log->_[LOG_BYTE_SIZE], encoder.mdat_byte_size - frame_file_offset); #ifndef STANDALONE Py_END_ALLOW_THREADS #endif if (pcmreader->read(pcmreader, encoder.options.block_size, channels)) goto error; } /*return to header and rewrite it with the actual value*/ bw_pop_callback(output, NULL); fseek(output_file, 0, 0); output->write(output, 32, encoder.mdat_byte_size); /*close and free allocated files/buffers, which varies depending on whether we're running standlone or not*/ #ifndef STANDALONE log_output = alac_log_output(&encoder); pcmreader->del(pcmreader); output->free(output); alacenc_free_encoder(&encoder); channels->del(channels); return log_output; error: pcmreader->del(pcmreader); output->free(output); alacenc_free_encoder(&encoder); channels->del(channels); return NULL; }
static int encode_audio(BitstreamWriter* bs, pcmreader* pcmreader, int signed_samples, unsigned block_size) { unsigned left_shift = 0; int sign_adjustment; /*allocate some temporary buffers*/ array_ia* frame = array_ia_new(); array_ia* wrapped_samples = array_ia_new(); array_i* shifted = array_i_new(); array_ia* deltas = array_ia_new(); array_i* residuals = array_i_new(); unsigned c; unsigned i; for (i = 0; i < pcmreader->channels; i++) wrapped_samples->append(wrapped_samples); if (!signed_samples) { sign_adjustment = 1 << (pcmreader->bits_per_sample - 1); } else { sign_adjustment = 0; } if (pcmreader->read(pcmreader, block_size, frame)) goto error; while (frame->_[0]->len > 0) { #ifndef STANDALONE Py_BEGIN_ALLOW_THREADS #endif if (frame->_[0]->len != block_size) { /*PCM frame count has changed, so issue BLOCKSIZE command*/ block_size = frame->_[0]->len; write_unsigned(bs, COMMAND_SIZE, FN_BLOCKSIZE); write_long(bs, block_size); } for (c = 0; c < frame->len; c++) { array_i* channel = frame->_[c]; array_i* wrapped = wrapped_samples->_[c]; /*convert signed samples to unsigned, if necessary*/ if (sign_adjustment != 0) for (i = 0; i < channel->len; i++) channel->_[i] += sign_adjustment; if (all_zero(channel)) { /*write ZERO command and wrap channel for next set*/ write_unsigned(bs, COMMAND_SIZE, FN_ZERO); wrapped->extend(wrapped, channel); wrapped->tail(wrapped, SAMPLES_TO_WRAP, wrapped); } else { unsigned diff = 1; unsigned energy = 0; unsigned wasted_BPS = wasted_bits(channel); if (wasted_BPS != left_shift) { /*issue BITSHIFT comand*/ left_shift = wasted_BPS; write_unsigned(bs, COMMAND_SIZE, FN_BITSHIFT); write_unsigned(bs, BITSHIFT_SIZE, left_shift); } /*apply left shift to channel data*/ if (left_shift > 0) { shifted->reset_for(shifted, channel->len); for (i = 0; i < channel->len; i++) a_append(shifted, channel->_[i] >> left_shift); } else { channel->copy(channel, shifted); } /*calculate best DIFF, energy and residuals for shifted data*/ calculate_best_diff(shifted, wrapped, deltas, &diff, &energy, residuals); /*issue DIFF command*/ write_unsigned(bs, COMMAND_SIZE, diff); write_unsigned(bs, ENERGY_SIZE, energy); for (i = 0; i < residuals->len; i++) write_signed(bs, energy, residuals->_[i]); /*wrap shifted channel data for next set*/ wrapped->extend(wrapped, shifted); wrapped->tail(wrapped, SAMPLES_TO_WRAP, wrapped); } }
int OggFlacDecoder_init(decoders_OggFlacDecoder *self, PyObject *args, PyObject *kwds) { char* filename; ogg_status result; uint16_t header_packets; self->ogg_stream = NULL; self->ogg_file = NULL; self->subframe_data = array_ia_new(); self->residuals = array_i_new(); self->qlp_coeffs = array_i_new(); self->framelist_data = array_i_new(); self->audiotools_pcm = NULL; self->packet = br_substream_new(BS_BIG_ENDIAN); self->stream_finalized = 0; if (!PyArg_ParseTuple(args, "si", &filename, &(self->channel_mask))) return -1; if (self->channel_mask < 0) { PyErr_SetString(PyExc_ValueError, "channel_mask must be >= 0"); return -1; } self->ogg_file = fopen(filename, "rb"); if (self->ogg_file == NULL) { PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename); return -1; } else { self->ogg_stream = oggreader_open(self->ogg_file); } /*the first packet should be the FLAC's STREAMINFO*/ if ((result = oggreader_next_packet(self->ogg_stream, self->packet)) == OGG_OK) { if (!oggflac_read_streaminfo(self->packet, &(self->streaminfo), &header_packets)) return -1; } else { PyErr_SetString(ogg_exception(result), ogg_strerror(result)); return -1; } /*skip subsequent header packets*/ for (; header_packets > 0; header_packets--) { if ((result = oggreader_next_packet(self->ogg_stream, self->packet)) != OGG_OK) { PyErr_SetString(ogg_exception(result), ogg_strerror(result)); return -1; } } /*initialize the output MD5 sum*/ audiotools__MD5Init(&(self->md5)); /*add callback for CRC16 calculation*/ br_add_callback(self->packet, (bs_callback_func)flac_crc16, &(self->crc16)); /*setup a framelist generator function*/ if ((self->audiotools_pcm = open_audiotools_pcm()) == NULL) return -1; return 0; }