static gboolean xmms_mpc_init (xmms_xform_t *xform) { xmms_mpc_data_t *data; xmms_error_t error; data = g_new0 (xmms_mpc_data_t, 1); xmms_xform_private_data_set (xform, data); if (!xmms_apetag_read (xform)) { XMMS_DBG ("Failed to read APEv2 tag"); } /* Reset to start after reading the tags */ xmms_error_reset (&error); xmms_xform_seek (xform, 0, XMMS_XFORM_SEEK_SET, &error); data->buffer = g_string_new (NULL); data->reader.read = xmms_mpc_callback_read; data->reader.seek = xmms_mpc_callback_seek; data->reader.tell = xmms_mpc_callback_tell; data->reader.canseek = xmms_mpc_callback_canseek; data->reader.get_size = xmms_mpc_callback_get_size; data->reader.data = xform; #ifdef HAVE_MPCDEC_OLD mpc_streaminfo_init (&data->info); if (mpc_streaminfo_read (&data->info, &data->reader) != ERROR_CODE_OK) return FALSE; mpc_decoder_setup (&data->decoder, &data->reader); if (mpc_decoder_initialize (&data->decoder, &data->info) == FALSE) return FALSE; #else data->demux = mpc_demux_init (&data->reader); if (!data->demux) return FALSE; mpc_demux_get_info (data->demux, &data->info); #endif xmms_mpc_cache_streaminfo (xform); xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_FLOAT, XMMS_STREAM_TYPE_FMT_CHANNELS, data->info.channels, XMMS_STREAM_TYPE_FMT_SAMPLERATE, data->info.sample_freq, XMMS_STREAM_TYPE_END); return TRUE; }
static gboolean xmms_mpc_init (xmms_xform_t *xform) { xmms_mpc_data_t *data; data = g_new0 (xmms_mpc_data_t, 1); xmms_xform_private_data_set (xform, data); xmms_mpc_collect_metadata (xform); data->buffer = g_string_new (NULL); data->reader.read = xmms_mpc_callback_read; data->reader.seek = xmms_mpc_callback_seek; data->reader.tell = xmms_mpc_callback_tell; data->reader.canseek = xmms_mpc_callback_canseek; data->reader.get_size = xmms_mpc_callback_get_size; data->reader.data = xform; #ifdef HAVE_MPCDEC_OLD mpc_streaminfo_init (&data->info); if (mpc_streaminfo_read (&data->info, &data->reader) != ERROR_CODE_OK) return FALSE; mpc_decoder_setup (&data->decoder, &data->reader); if (mpc_decoder_initialize (&data->decoder, &data->info) == FALSE) return FALSE; #else data->demux = mpc_demux_init (&data->reader); if (!data->demux) return FALSE; mpc_demux_get_info (data->demux, &data->info); #endif xmms_mpc_cache_streaminfo (xform); xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_FLOAT, XMMS_STREAM_TYPE_FMT_CHANNELS, data->info.channels, XMMS_STREAM_TYPE_FMT_SAMPLERATE, data->info.sample_freq, XMMS_STREAM_TYPE_END); return TRUE; }
MPCReader(FILE *fp) { mpc_status err; fseek(fp, 0, SEEK_SET); demux = NULL; memset(&reader, 0, sizeof(reader)); memset(&si, 0, sizeof(si)); memset(MPCBuffer, 0, sizeof(MPCBuffer)); MPCBufferOffs = 0; MPCBufferIn = 0; if((err = mpc_reader_init_stdio_stream(&reader, fp)) < 0) { throw(MDFN_Error(0, _("Error initializing MusePack decoder!\n"))); } if(!(demux = mpc_demux_init(&reader))) { throw(0); } mpc_demux_get_info(demux, &si); if(si.channels != 2) { mpc_demux_exit(demux); demux = NULL; throw MDFN_Error(0, _("MusePack stream has wrong number of channels(%d); the correct number is 2."), si.channels); } if(si.sample_freq != 44100) { mpc_demux_exit(demux); demux = NULL; throw MDFN_Error(0, _("MusePack stream has wrong samplerate(%d Hz); the current samplerate is 44100 Hz."), si.sample_freq); } }
CDAFReader_MPC::CDAFReader_MPC(Stream *fp) : fw(fp) { demux = NULL; memset(&si, 0, sizeof(si)); memset(MPCBuffer, 0, sizeof(MPCBuffer)); MPCBufferOffs = 0; MPCBufferIn = 0; memset(&reader, 0, sizeof(reader)); reader.read = impc_read; reader.seek = impc_seek; reader.tell = impc_tell; reader.get_size = impc_get_size; reader.canseek = impc_canseek; reader.data = (void*)fp; if(!(demux = mpc_demux_init(&reader))) { throw(0); } mpc_demux_get_info(demux, &si); if(si.channels != 2) { mpc_demux_exit(demux); demux = NULL; throw MDFN_Error(0, _("MusePack stream has wrong number of channels(%u); the correct number is 2."), si.channels); } if(si.sample_freq != 44100) { mpc_demux_exit(demux); demux = NULL; throw MDFN_Error(0, _("MusePack stream has wrong samplerate(%u Hz); the correct samplerate is 44100 Hz."), si.sample_freq); } }
static gboolean gst_musepack_stream_init (GstMusepackDec * musepackdec) { mpc_streaminfo i; GstTagList *tags; GstCaps *caps; gchar *stream_id; /* set up reading */ gst_musepack_init_reader (musepackdec->r, musepackdec); musepackdec->d = mpc_demux_init (musepackdec->r); if (!musepackdec->d) { GST_ELEMENT_ERROR (musepackdec, STREAM, WRONG_TYPE, (NULL), (NULL)); return FALSE; } mpc_demux_get_info (musepackdec->d, &i); stream_id = gst_pad_create_stream_id (musepackdec->srcpad, GST_ELEMENT_CAST (musepackdec), NULL); gst_pad_push_event (musepackdec->srcpad, gst_event_new_stream_start (stream_id)); g_free (stream_id); /* capsnego */ caps = gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, GST_MPC_FORMAT, "layout", G_TYPE_STRING, "interleaved", "channels", G_TYPE_INT, i.channels, "rate", G_TYPE_INT, i.sample_freq, NULL); gst_pad_use_fixed_caps (musepackdec->srcpad); if (!gst_pad_set_caps (musepackdec->srcpad, caps)) { GST_ELEMENT_ERROR (musepackdec, CORE, NEGOTIATION, (NULL), (NULL)); return FALSE; } g_atomic_int_set (&musepackdec->bps, 4 * i.channels); g_atomic_int_set (&musepackdec->rate, i.sample_freq); musepackdec->segment.position = 0; musepackdec->segment.duration = mpc_streaminfo_get_length_samples (&i); /* send basic tags */ tags = gst_tag_list_new_empty (); gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_AUDIO_CODEC, "Musepack", NULL); if (i.encoder[0] != '\0' && i.encoder_version > 0) { gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, i.encoder, GST_TAG_ENCODER_VERSION, i.encoder_version, NULL); } if (i.bitrate > 0) { gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, i.bitrate, NULL); } else if (i.average_bitrate > 0.0) { gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, (guint) i.average_bitrate, NULL); } if (i.gain_title != 0 || i.gain_album != 0) { gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_TRACK_GAIN, (gdouble) i.gain_title / 100.0, GST_TAG_ALBUM_GAIN, (gdouble) i.gain_album / 100.0, NULL); } if (i.peak_title != 0 && i.peak_title != 32767 && i.peak_album != 0 && i.peak_album != 32767) { gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_TRACK_PEAK, (gdouble) i.peak_title / 32767.0, GST_TAG_ALBUM_PEAK, (gdouble) i.peak_album / 32767.0, NULL); } GST_LOG_OBJECT (musepackdec, "Posting tags: %" GST_PTR_FORMAT, tags); gst_pad_push_event (musepackdec->srcpad, gst_event_new_tag (tags)); return TRUE; }
bool SFB::Audio::MusepackDecoder::_Open(CFErrorRef *error) { UInt8 buf [PATH_MAX]; if(!CFURLGetFileSystemRepresentation(mInputSource->GetURL(), FALSE, buf, PATH_MAX)) return false; mReader.read = read_callback; mReader.seek = seek_callback; mReader.tell = tell_callback; mReader.get_size = get_size_callback; mReader.canseek = canseek_callback; mReader.data = this; mDemux = mpc_demux_init(&mReader); if(nullptr == mDemux) { if(error) { SFB::CFString description = CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Musepack file."), ""); SFB::CFString failureReason = CFCopyLocalizedString(CFSTR("Not a Musepack file"), ""); SFB::CFString recoverySuggestion = CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), ""); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } mpc_reader_exit_stdio(&mReader); return false; } // Get input file information mpc_streaminfo streaminfo; mpc_demux_get_info(mDemux, &streaminfo); mTotalFrames = mpc_streaminfo_get_length_samples(&streaminfo); // Canonical Core Audio format mFormat.mFormatID = kAudioFormatLinearPCM; mFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved; mFormat.mSampleRate = streaminfo.sample_freq; mFormat.mChannelsPerFrame = streaminfo.channels; mFormat.mBitsPerChannel = 8 * sizeof(float); mFormat.mBytesPerPacket = (mFormat.mBitsPerChannel / 8); mFormat.mFramesPerPacket = 1; mFormat.mBytesPerFrame = mFormat.mBytesPerPacket * mFormat.mFramesPerPacket; mFormat.mReserved = 0; // Set up the source format mSourceFormat.mFormatID = 'MUSE'; mSourceFormat.mSampleRate = streaminfo.sample_freq; mSourceFormat.mChannelsPerFrame = streaminfo.channels; mSourceFormat.mFramesPerPacket = (1 << streaminfo.block_pwr); // Setup the channel layout switch(streaminfo.channels) { case 1: mChannelLayout = ChannelLayout::ChannelLayoutWithTag(kAudioChannelLayoutTag_Mono); break; case 2: mChannelLayout = ChannelLayout::ChannelLayoutWithTag(kAudioChannelLayoutTag_Stereo); break; case 4: mChannelLayout = ChannelLayout::ChannelLayoutWithTag(kAudioChannelLayoutTag_Quadraphonic); break; } // Allocate the buffer list if(!mBufferList.Allocate(mFormat, MPC_FRAME_LENGTH)) { if(error) *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX, ENOMEM, nullptr); mpc_demux_exit(mDemux), mDemux = nullptr; mpc_reader_exit_stdio(&mReader); return false; } for(UInt32 i = 0; i < mBufferList->mNumberBuffers; ++i) mBufferList->mBuffers[i].mDataByteSize = 0; return true; }
/* This is the codec entry point. */ enum codec_status codec_main(void) { mpc_int64_t samplesdone; uint32_t frequency; /* 0.1 kHz accuracy */ uint32_t elapsed_time; /* milliseconds */ uint32_t byterate; /* bytes per second */ mpc_status status; mpc_reader reader; mpc_streaminfo info; mpc_frame_info frame; mpc_demux *demux = NULL; int retval = CODEC_OK; frame.buffer = sample_buffer; /* musepack's sample representation is 18.14 * DSP_SET_SAMPLE_DEPTH = 14 (FRACT) + 16 (NATIVE) - 1 (SIGN) = 29 */ ci->configure(DSP_SET_SAMPLE_DEPTH, 29); /* Create a decoder instance */ reader.read = read_impl; reader.seek = seek_impl; reader.tell = tell_impl; reader.get_size = get_size_impl; next_track: if (codec_init()) { retval = CODEC_ERROR; goto exit; } while (!*ci->taginfo_ready && !ci->stop_codec) ci->sleep(1); /* Initialize demux/decoder. */ demux = mpc_demux_init(&reader); if (NULL == demux) { retval = CODEC_ERROR; goto done; } /* Read file's streaminfo data. */ mpc_demux_get_info(demux, &info); byterate = (mpc_uint32_t)(info.average_bitrate) / 8; frequency = info.sample_freq / 100; /* 0.1 kHz accuracy */ ci->configure(DSP_SWITCH_FREQUENCY, info.sample_freq); /* Remark: rockbox offset is the file offset in bytes. So, estimate the * sample seek position from the file offset, the sampling frequency and * the bitrate. As the saved position is exactly calculated the reverse way * there is no loss of information except rounding. */ samplesdone = 100 * ((mpc_uint64_t)(ci->id3->offset * frequency) / byterate); /* Set up digital signal processing for correct number of channels */ /* NOTE: current musepack format only allows for stereo files but code is here to handle other configurations anyway */ if (info.channels == 2) ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); else if (info.channels == 1) ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); else { retval = CODEC_ERROR; goto done; } codec_set_replaygain(ci->id3); /* Resume to saved sample offset. */ if (samplesdone > 0) { if (mpc_demux_seek_sample(demux, samplesdone) == MPC_STATUS_OK) { elapsed_time = (samplesdone*10)/frequency; ci->set_elapsed(elapsed_time); } else { samplesdone = 0; } } /* This is the decoding loop. */ do { /* Complete seek handler. */ if (ci->seek_time) { mpc_int64_t new_offset = ((ci->seek_time - 1)/10)*frequency; if (mpc_demux_seek_sample(demux, new_offset) == MPC_STATUS_OK) { samplesdone = new_offset; ci->set_elapsed(ci->seek_time); } ci->seek_complete(); } /* Stop or skip occured, exit decoding loop. */ if (ci->stop_codec || ci->new_track) break; /* Decode one frame. */ status = mpc_demux_decode(demux, &frame); ci->yield(); if (frame.bits == -1) { /* Decoding error, exit decoding loop. */ retval = (status == MPC_STATUS_OK) ? CODEC_OK : CODEC_ERROR; goto done; } else { /* Decoding passed, insert samples to PCM buffer. */ ci->pcmbuf_insert(frame.buffer, frame.buffer + MPC_FRAME_LENGTH, frame.samples); samplesdone += frame.samples; elapsed_time = (samplesdone*10)/frequency; ci->set_elapsed(elapsed_time); /* Remark: rockbox offset is the file offset in bytes. So estimate * this offset from the samples, sampling frequency and bitrate */ ci->set_offset( (samplesdone * byterate)/(frequency*100) ); } } while (true); done: if (ci->request_next_track()) goto next_track; exit: return retval; }
static gboolean gst_musepack_stream_init (GstMusepackDec * musepackdec) { mpc_streaminfo i; GstTagList *tags; GstCaps *caps; /* set up reading */ gst_musepack_init_reader (musepackdec->r, musepackdec); #ifdef MPC_IS_OLD_API /* streaminfo */ mpc_streaminfo_init (&i); if (mpc_streaminfo_read (&i, musepackdec->r) < 0) { GST_ELEMENT_ERROR (musepackdec, STREAM, WRONG_TYPE, (NULL), (NULL)); return FALSE; } /* decoding */ mpc_decoder_setup (musepackdec->d, musepackdec->r); mpc_decoder_scale_output (musepackdec->d, 1.0); if (!mpc_decoder_initialize (musepackdec->d, &i)) { GST_ELEMENT_ERROR (musepackdec, STREAM, WRONG_TYPE, (NULL), (NULL)); return FALSE; } #else musepackdec->d = mpc_demux_init (musepackdec->r); if (!musepackdec->d) { GST_ELEMENT_ERROR (musepackdec, STREAM, WRONG_TYPE, (NULL), (NULL)); return FALSE; } mpc_demux_get_info (musepackdec->d, &i); #endif /* capsnego */ caps = gst_caps_from_string (BASE_CAPS); gst_caps_set_simple (caps, "endianness", G_TYPE_INT, G_BYTE_ORDER, "channels", G_TYPE_INT, i.channels, "rate", G_TYPE_INT, i.sample_freq, NULL); gst_pad_use_fixed_caps (musepackdec->srcpad); if (!gst_pad_set_caps (musepackdec->srcpad, caps)) { GST_ELEMENT_ERROR (musepackdec, CORE, NEGOTIATION, (NULL), (NULL)); return FALSE; } g_atomic_int_set (&musepackdec->bps, 4 * i.channels); g_atomic_int_set (&musepackdec->rate, i.sample_freq); gst_segment_set_last_stop (&musepackdec->segment, GST_FORMAT_DEFAULT, 0); gst_segment_set_duration (&musepackdec->segment, GST_FORMAT_DEFAULT, mpc_streaminfo_get_length_samples (&i)); /* send basic tags */ tags = gst_tag_list_new (); gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_AUDIO_CODEC, "Musepack", NULL); if (i.encoder[0] != '\0' && i.encoder_version > 0) { gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, i.encoder, GST_TAG_ENCODER_VERSION, i.encoder_version, NULL); } if (i.bitrate > 0) { gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, i.bitrate, NULL); } else if (i.average_bitrate > 0.0) { gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, (guint) i.average_bitrate, NULL); } if (i.gain_title != 0 || i.gain_album != 0) { gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_TRACK_GAIN, (gdouble) i.gain_title / 100.0, GST_TAG_ALBUM_GAIN, (gdouble) i.gain_album / 100.0, NULL); } if (i.peak_title != 0 && i.peak_title != 32767 && i.peak_album != 0 && i.peak_album != 32767) { gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_TRACK_PEAK, (gdouble) i.peak_title / 32767.0, GST_TAG_ALBUM_PEAK, (gdouble) i.peak_album / 32767.0, NULL); } GST_LOG_OBJECT (musepackdec, "Posting tags: %" GST_PTR_FORMAT, tags); gst_element_found_tags (GST_ELEMENT (musepackdec), tags); return TRUE; }
int main(int argc, char **argv) { MPC_SAMPLE_FORMAT album_max = 0; mpc_uint16_t album_gain; mpc_uint16_t album_peak; mpc_uint16_t * title_gain; mpc_uint16_t * title_peak; mpc_uint32_t * header_pos; int j; printf(About); if (argc < 2) { usage(argv[0]); return 0; } title_gain = malloc((sizeof(mpc_uint16_t) * 2 + sizeof(mpc_uint32_t)) * (argc - 1)); title_peak = title_gain + (argc - 1); header_pos = (mpc_uint32_t *) (title_peak + (argc - 1)); for (j = 1; j < argc; j++) { MPC_SAMPLE_FORMAT sample_buffer[MPC_DECODER_BUFFER_LENGTH]; MPC_SAMPLE_FORMAT title_max = 0, chap_max; mpc_uint16_t * chap_gain, * chap_peak; mpc_reader reader; mpc_demux* demux; mpc_streaminfo si; mpc_status err; int chap_nb, chap = 0; mpc_uint64_t cur_sample = 1, next_chap_sample = mpc_int64_max; err = mpc_reader_init_stdio(&reader, argv[j]); if (err < 0) return !MPC_STATUS_OK; demux = mpc_demux_init(&reader); if (!demux) return !MPC_STATUS_OK; mpc_demux_get_info(demux, &si); chap_nb = mpc_demux_chap_nb(demux); mpc_demux_seek_sample(demux, 0); if (chap_nb > 0) { mpc_chap_info * chap_info = mpc_demux_chap(demux, chap); next_chap_sample = chap_info->sample; chap_gain = malloc(sizeof(mpc_uint16_t) * 2 * chap_nb); chap_peak = chap_gain + chap_nb; } if (j == 1) gain_init_analysis ( si.sample_freq ); while (1) { mpc_frame_info frame; int i = 0; frame.buffer = sample_buffer; mpc_demux_decode(demux, &frame); if (frame.bits == -1) break; while (next_chap_sample < cur_sample + frame.samples) { int sample_nb = (int)(next_chap_sample - cur_sample); chap_max = _max(chap_max, analyze_get_max(sample_buffer + 2 * i, sample_nb)); if (chap == 0) // first samples are not in a chapter gain_get_chapter(); else { chap_gain[chap - 1] = (mpc_uint16_t) (gain_get_chapter() * 256); chap_peak[chap - 1] = (mpc_uint16_t) (log10(chap_max * (1 << 15)) * 20 * 256); } chap++; title_max = _max(title_max, chap_max); chap_max = 0; i += sample_nb; cur_sample = next_chap_sample; if (chap < chap_nb) { mpc_chap_info * chap_info = mpc_demux_chap(demux, chap); next_chap_sample = chap_info->sample; } else next_chap_sample = mpc_int64_max; } chap_max = _max(chap_max, analyze_get_max(sample_buffer + 2 * i, frame.samples - i)); cur_sample += frame.samples - i; } if (chap_nb > 0) { chap_gain[chap - 1] = (mpc_uint16_t) (gain_get_chapter() * 256); chap_peak[chap - 1] = (mpc_uint16_t) (log10(chap_max * (1 << 15)) * 20 * 256); write_chaps_gain(demux, argv[j], chap_gain, chap_peak); } title_max = _max(title_max, chap_max); album_max = _max(album_max, title_max); title_gain[j-1] = (mpc_uint16_t) (gain_get_title() * 256); title_peak[j-1] = (mpc_uint16_t) (log10(title_max * (1 << 15)) * 20 * 256); header_pos[j-1] = si.header_position + 4; mpc_demux_exit(demux); mpc_reader_exit_stdio(&reader); if (chap_nb > 0) free(chap_gain); } album_gain = (mpc_uint16_t) (gain_get_album() * 256); album_peak = (mpc_uint16_t) (log10(album_max * (1 << 15)) * 20 * 256); for (j = 0; j < argc - 1; j++) { unsigned char buffer[64]; mpc_bits_reader r; mpc_block b; mpc_uint64_t size; FILE * file; file = fopen( argv[j + 1], "r+b"); if (file == 0) { fprintf(stderr, "Can't open file \"%s\" for writing\n", argv[j + 1]); continue; } fseek(file, header_pos[j] - 4, SEEK_SET); fread(buffer, 1, 16, file); if (memcmp(buffer, "MPCK", 4) != 0) { fprintf(stderr, "Unsupported file format, not a sv8 file : %s\n", argv[j + 1]); fclose(file); continue; } r.buff = buffer + 4; r.count = 8; for(;;) { size = mpc_bits_get_block(&r, &b); if (mpc_check_key(b.key) != MPC_STATUS_OK) break; if (memcmp(b.key, "RG", 2) == 0) break; header_pos[j] += b.size + size; fseek(file, header_pos[j], SEEK_SET); fread(buffer, 1, 16, file); r.buff = buffer; r.count = 8; } if (memcmp(b.key, "RG", 2) != 0 || b.size < 9) { //check for the loop above having aborted without finding the packet we want to update fprintf(stderr, "Unsupported file format or corrupted file : %s\n", argv[j + 1]); fclose(file); continue; } header_pos[j] += size; buffer[size] = 1; // replaygain version buffer[size + 1] = title_gain[j] >> 8; buffer[size + 2] = title_gain[j] & 0xFF; buffer[size + 3] = title_peak[j] >> 8; buffer[size + 4] = title_peak[j] & 0xFF; buffer[size + 5] = album_gain >> 8; buffer[size + 6] = album_gain & 0xFF; buffer[size + 7] = album_peak >> 8; buffer[size + 8] = album_peak & 0xFF; fseek(file, header_pos[j], SEEK_SET); fwrite(buffer + size, 1, b.size, file); fclose(file); } free(title_gain); return 0; }
int main(int argc, char **argv) { mpc_reader reader; mpc_demux* demux; mpc_streaminfo si; mpc_encoder_t e; unsigned char buffer[16]; mpc_bits_reader r; mpc_block b; mpc_uint64_t size; mpc_status err; mpc_int64_t start_sample = 0, end_sample = 0; mpc_uint32_t beg_silence, start_block, block_num, i; int c; FILE * in_file; printf(About); while ((c = getopt(argc , argv, "s:e:")) != -1) { switch (c) { case 's': start_sample = atoll(optarg); break; case 'e': end_sample = atoll(optarg); break; } } if(argc - optind != 2) { usage(argv[0]); return 0; } err = mpc_reader_init_stdio(&reader, argv[optind]); if(err < 0) return !MPC_STATUS_OK; demux = mpc_demux_init(&reader); if(!demux) return !MPC_STATUS_OK; mpc_demux_get_info(demux, &si); if (si.stream_version < 8) { fprintf(stderr, "this file cannot be edited, please convert it first to sv8 using mpc2sv8\n"); exit(!MPC_STATUS_OK); } if (end_sample == 0) end_sample = si.samples; else end_sample += si.beg_silence; start_sample += si.beg_silence; if (start_sample < 0 || end_sample > si.samples || end_sample <= start_sample) { fprintf(stderr, "specified samples bounds out of stream bounds\n"); exit(!MPC_STATUS_OK); } beg_silence = start_sample % (MPC_FRAME_LENGTH << si.block_pwr); start_block = start_sample / (MPC_FRAME_LENGTH << si.block_pwr); block_num = (end_sample + (MPC_FRAME_LENGTH << si.block_pwr) - 1) / (MPC_FRAME_LENGTH << si.block_pwr) - start_block; end_sample -= start_block * (MPC_FRAME_LENGTH << si.block_pwr); mpc_encoder_init(&e, end_sample, si.block_pwr, 1); e.outputFile = fopen( argv[optind + 1], "rb" ); if ( e.outputFile != 0 ) { fprintf(stderr, "Error : output file \"%s\" already exists\n", argv[optind + 1]); exit(MPC_STATUS_FAIL); } e.outputFile = fopen( argv[optind + 1], "w+b" ); e.seek_ref = 0; writeMagic(&e); writeStreamInfo( &e, si.max_band, si.ms > 0, end_sample, beg_silence, si.sample_freq, si.channels); writeBlock(&e, "SH", MPC_TRUE, 0); writeGainInfo(&e, 0, 0, 0, 0); writeBlock(&e, "RG", MPC_FALSE, 0); in_file = fopen(argv[optind], "rb"); i = si.header_position + 4; fseek(in_file, i, SEEK_SET); fread(buffer, 1, 16, in_file); r.buff = buffer; r.count = 8; size = mpc_bits_get_block(&r, &b); while( memcmp(b.key, "AP", 2) != 0 ) { if ((err = mpc_check_key(b.key)) != MPC_STATUS_OK) { fprintf(stderr, "Error : invalid input stream\n"); goto error; } if (memcmp(b.key, "EI", 2) == 0) copy_data(in_file, i, e.outputFile, b.size + size); i += b.size + size; fseek(in_file, i, SEEK_SET); fread(buffer, 1, 16, in_file); r.buff = buffer; r.count = 8; size = mpc_bits_get_block(&r, &b); } e.seek_ptr = ftell(e.outputFile); writeBits (&e, 0, 16); writeBits (&e, 0, 24); // jump 40 bits for seek table pointer writeBlock(&e, "SO", MPC_FALSE, 0); // reserve space for seek offset while( start_block != 0 ) { if ((err = mpc_check_key(b.key)) != MPC_STATUS_OK) { fprintf(stderr, "Error : invalid input stream\n"); goto error; } if (memcmp(b.key, "AP", 2) == 0) start_block--; i += b.size + size; fseek(in_file, i, SEEK_SET); fread(buffer, 1, 16, in_file); r.buff = buffer; r.count = 8; size = mpc_bits_get_block(&r, &b); } while( block_num != 0 ) { if ((err = mpc_check_key(b.key)) != MPC_STATUS_OK) { fprintf(stderr, "Error : invalid input stream\n"); goto error; } if (memcmp(b.key, "AP", 2) == 0) { if ((e.block_cnt & ((1 << e.seek_pwr) - 1)) == 0) { e.seek_table[e.seek_pos] = ftell(e.outputFile); e.seek_pos++; } e.block_cnt++; copy_data(in_file, i, e.outputFile, b.size + size); block_num--; } i += b.size + size; fseek(in_file, i, SEEK_SET); fread(buffer, 1, 16, in_file); r.buff = buffer; r.count = 8; size = mpc_bits_get_block(&r, &b); } writeSeekTable(&e); writeBlock(&e, "ST", MPC_FALSE, 0); // write seek table block writeBlock(&e, "SE", MPC_FALSE, 0); // write end of stream block error: fclose ( e.outputFile ); fclose ( in_file ); mpc_demux_exit(demux); mpc_reader_exit_stdio(&reader); mpc_encoder_exit(&e); if (err != MPC_STATUS_OK) remove(argv[optind + 1]); return err; }