int pcmreader_converter(PyObject* obj, void** pcm_reader) { pcmreader* pcmreader_s = open_pcmreader(obj); if (pcmreader_s != NULL) { *pcm_reader = pcmreader_s; return 1; } else { return 0; } }
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; }
int main(int argc, char *argv[]) { char* output_file = NULL; unsigned channels = 2; unsigned original_sample_rate = 48000; const unsigned sample_rate = 48000; const unsigned bits_per_sample = 16; pcmreader *pcmreader = NULL; result_t result; char c; const static struct option long_opts[] = { {"help", no_argument, NULL, 'h'}, {"channels", required_argument, NULL, 'c'}, {"original-sample-rate", required_argument, NULL, 'r'}, {NULL, no_argument, NULL, 0} }; const static char* short_opts = "-hc:"; while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { switch (c) { case 1: if (output_file == NULL) { output_file = optarg; } else { printf("only one output file allowed\n"); return 1; } break; case 'c': if (((channels = strtoul(optarg, NULL, 10)) == 0) && errno) { printf("invalid --channel \"%s\"\n", optarg); return 1; } break; case 'r': if (((original_sample_rate = strtoul(optarg, NULL, 10)) == 0) && errno) { printf("invalid --original-sample-rate \"%s\"\n", optarg); return 1; } break; case 'h': /*fallthrough*/ case ':': case '?': printf("*** Usage: vorbisenc [options] <output.ogg>\n"); printf("-c, --channels=# number of input channels\n"); return 0; default: break; } } if (output_file == NULL) { printf("exactly 1 output file required\n"); return 1; } assert((channels > 0) && (channels <= 255)); printf("Encoding from stdin using parameters:\n"); printf("channels %u\n", channels); printf("sample rate %u\n", sample_rate); printf("bits per sample %u\n", bits_per_sample); printf("little-endian, signed samples\n"); pcmreader = open_pcmreader(stdin, sample_rate, channels, 0, bits_per_sample, 0, 1); switch (result = encode_opus_file(output_file, pcmreader, 10, original_sample_rate)) { case ENCODE_OK: break; default: fprintf(stderr, "*** Error: %d", result); break; } pcmreader->close(pcmreader); pcmreader->del(pcmreader); return 0; }