static gint xmms_mpc_read (xmms_xform_t *xform, xmms_sample_t *buffer, gint len, xmms_error_t *err) { MPC_SAMPLE_FORMAT internal[MPC_DECODER_BUFFER_LENGTH]; xmms_mpc_data_t *data; mpc_uint32_t ret; guint size; data = xmms_xform_private_data_get (xform); size = MIN (data->buffer->len, len); #ifdef HAVE_MPCDEC_OLD if (size <= 0) { ret = mpc_decoder_decode (&data->decoder, internal, NULL, NULL); if (ret == -1) { xmms_error_set (err, XMMS_ERROR_GENERIC, "Musepack decoder failed"); return -1; } ret *= xmms_sample_size_get (XMMS_SAMPLE_FORMAT_FLOAT); ret *= data->info.channels; g_string_append_len (data->buffer, (gchar *) internal, ret); } #else if (size <= 0) { mpc_frame_info frame; frame.buffer = internal; do { ret = mpc_demux_decode (data->demux, &frame); } while (frame.bits != -1 && frame.samples == 0); if (frame.bits == -1 && ret != MPC_STATUS_OK) { xmms_error_set (err, XMMS_ERROR_GENERIC, "Musepack decoder failed"); return -1; } ret = frame.samples; ret *= xmms_sample_size_get (XMMS_SAMPLE_FORMAT_FLOAT); ret *= data->info.channels; g_string_append_len (data->buffer, (gchar *) internal, ret); } #endif /* Update the current size of available data */ size = MIN (data->buffer->len, len); memcpy (buffer, data->buffer->str, size); g_string_erase (data->buffer, 0, size); return size; }
int64 Read_(int16 *buffer, int64 frames) { mpc_status err; int16 *cowbuf = (int16 *)buffer; int32 toread = frames * 2; while(toread > 0) { int32 tmplen; if(!MPCBufferIn) { mpc_frame_info fi; memset(&fi, 0, sizeof(fi)); fi.buffer = MPCBuffer; if((err = mpc_demux_decode(demux, &fi)) < 0 || fi.bits == -1) return(frames - toread / 2); MPCBufferIn = fi.samples * 2; MPCBufferOffs = 0; } tmplen = MPCBufferIn; if(tmplen >= toread) tmplen = toread; for(int x = 0; x < tmplen; x++) { #ifdef MPC_FIXED_POINT int32 samp = MPCBuffer[MPCBufferOffs + x] >> MPC_FIXED_POINT_FRACTPART; #else #warning Floating-point MPC decoding path not tested. int32 samp = (int32)(MPCBuffer[MPCBufferOffs + x] * 32767); #endif if(samp < -32768) samp = -32768; if(samp > 32767) samp = 32767; *cowbuf = (int16)samp; cowbuf++; } MPCBufferOffs += tmplen; toread -= tmplen; MPCBufferIn -= tmplen; } return(frames - toread / 2); }
void AudioStreamMPC::update() { if (!active || paused) return; int todo=get_todo(); while(todo>MPC_DECODER_BUFFER_LENGTH/si.channels) { mpc_frame_info frame; frame.buffer=sample_buffer; mpc_status err = mpc_demux_decode(demux, &frame); if (frame.bits!=-1) { int16_t *dst_buff = get_write_buffer(); #ifdef MPC_FIXED_POINT for( int i = 0; i < frame.samples * si.channels; i++) { int tmp = sample_buffer[i] >> MPC_FIXED_POINT_FRACTPART; if (tmp > ((1 << 15) - 1)) tmp = ((1 << 15) - 1); if (tmp < -(1 << 15)) tmp = -(1 << 15); dst_buff[i] = tmp; } #else for( int i = 0; i < frame.samples * si.channels; i++) { int tmp = Math::fast_ftoi(sample_buffer[i]*32767.0); if (tmp > ((1 << 15) - 1)) tmp = ((1 << 15) - 1); if (tmp < -(1 << 15)) tmp = -(1 << 15); dst_buff[i] = tmp; } #endif int frames = frame.samples; write(frames); todo-=frames; } else { if (err != MPC_STATUS_OK) {
static void gst_musepackdec_loop (GstPad * sinkpad) { GstMusepackDec *musepackdec; GstFlowReturn flow; GstBuffer *out; GstMapInfo info; mpc_frame_info frame; mpc_status err; gint num_samples, samplerate, bitspersample; musepackdec = GST_MUSEPACK_DEC (GST_PAD_PARENT (sinkpad)); samplerate = g_atomic_int_get (&musepackdec->rate); if (samplerate == 0) { if (!gst_musepack_stream_init (musepackdec)) goto pause_task; gst_musepackdec_send_newsegment (musepackdec); samplerate = g_atomic_int_get (&musepackdec->rate); } bitspersample = g_atomic_int_get (&musepackdec->bps); out = gst_buffer_new_allocate (NULL, MPC_DECODER_BUFFER_LENGTH * 4, NULL); gst_buffer_map (out, &info, GST_MAP_READWRITE); frame.buffer = (MPC_SAMPLE_FORMAT *) info.data; err = mpc_demux_decode (musepackdec->d, &frame); gst_buffer_unmap (out, &info); if (err != MPC_STATUS_OK) { GST_ERROR_OBJECT (musepackdec, "Failed to decode sample"); GST_ELEMENT_ERROR (musepackdec, STREAM, DECODE, (NULL), (NULL)); goto pause_task; } else if (frame.bits == -1) { goto eos_and_pause; } num_samples = frame.samples; gst_buffer_set_size (out, num_samples * bitspersample); GST_BUFFER_OFFSET (out) = musepackdec->segment.position; GST_BUFFER_PTS (out) = gst_util_uint64_scale_int (musepackdec->segment.position, GST_SECOND, samplerate); GST_BUFFER_DURATION (out) = gst_util_uint64_scale_int (num_samples, GST_SECOND, samplerate); musepackdec->segment.position += num_samples; GST_LOG_OBJECT (musepackdec, "Pushing buffer, timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out))); flow = gst_pad_push (musepackdec->srcpad, out); if (flow != GST_FLOW_OK) { GST_DEBUG_OBJECT (musepackdec, "Flow: %s", gst_flow_get_name (flow)); goto pause_task; } /* check if we're at the end of a configured segment */ if (musepackdec->segment.stop != -1 && musepackdec->segment.position >= musepackdec->segment.stop) { gint64 stop_time; GST_DEBUG_OBJECT (musepackdec, "Reached end of configured segment"); if ((musepackdec->segment.flags & GST_SEEK_FLAG_SEGMENT) == 0) goto eos_and_pause; GST_DEBUG_OBJECT (musepackdec, "Posting SEGMENT_DONE message"); stop_time = gst_util_uint64_scale_int (musepackdec->segment.stop, GST_SECOND, samplerate); gst_element_post_message (GST_ELEMENT (musepackdec), gst_message_new_segment_done (GST_OBJECT (musepackdec), GST_FORMAT_TIME, stop_time)); gst_pad_push_event (musepackdec->srcpad, gst_event_new_segment_done (GST_FORMAT_TIME, stop_time)); goto pause_task; } return; eos_and_pause: { GST_DEBUG_OBJECT (musepackdec, "sending EOS event"); gst_pad_push_event (musepackdec->srcpad, gst_event_new_eos ()); /* fall through to pause */ } pause_task: { GST_DEBUG_OBJECT (musepackdec, "Pausing task"); gst_pad_pause_task (sinkpad); return; } }
UInt32 SFB::Audio::MusepackDecoder::_ReadAudio(AudioBufferList *bufferList, UInt32 frameCount) { if(bufferList->mNumberBuffers != mFormat.mChannelsPerFrame) { LOGGER_WARNING("org.sbooth.AudioEngine.Decoder.Musepack", "_ReadAudio() called with invalid parameters"); return 0; } MPC_SAMPLE_FORMAT buffer [MPC_DECODER_BUFFER_LENGTH]; UInt32 framesRead = 0; // Reset output buffer data size for(UInt32 i = 0; i < bufferList->mNumberBuffers; ++i) bufferList->mBuffers[i].mDataByteSize = 0; for(;;) { UInt32 framesRemaining = frameCount - framesRead; UInt32 framesToSkip = (UInt32)(bufferList->mBuffers[0].mDataByteSize / sizeof(float)); UInt32 framesInBuffer = (UInt32)(mBufferList->mBuffers[0].mDataByteSize / sizeof(float)); UInt32 framesToCopy = std::min(framesInBuffer, framesRemaining); // Copy data from the buffer to output for(UInt32 i = 0; i < mBufferList->mNumberBuffers; ++i) { float *floatBuffer = (float *)bufferList->mBuffers[i].mData; memcpy(floatBuffer + framesToSkip, mBufferList->mBuffers[i].mData, framesToCopy * sizeof(float)); bufferList->mBuffers[i].mDataByteSize += framesToCopy * sizeof(float); // Move remaining data in buffer to beginning if(framesToCopy != framesInBuffer) { floatBuffer = (float *)mBufferList->mBuffers[i].mData; memmove(floatBuffer, floatBuffer + framesToCopy, (framesInBuffer - framesToCopy) * sizeof(float)); } mBufferList->mBuffers[i].mDataByteSize -= framesToCopy * sizeof(float); } framesRead += framesToCopy; // All requested frames were read if(framesRead == frameCount) break; // Decode one frame of MPC data mpc_frame_info frame; frame.buffer = buffer; mpc_status result = mpc_demux_decode(mDemux, &frame); if(MPC_STATUS_OK != result) { LOGGER_ERR("org.sbooth.AudioEngine.Decoder.Musepack", "Musepack decoding error"); break; } // End of input if(-1 == frame.bits) break; #ifdef MPC_FIXED_POINT #error "Fixed point not yet supported" #else float *inputBuffer = (float *)buffer; // Clip the samples to [-1, 1) float minValue = -1.f; float maxValue = 8388607.f / 8388608.f; vDSP_vclip(inputBuffer, 1, &minValue, &maxValue, inputBuffer, 1, frame.samples * mFormat.mChannelsPerFrame); // Deinterleave the normalized samples for(UInt32 channel = 0; channel < mFormat.mChannelsPerFrame; ++channel) { float *floatBuffer = (float *)mBufferList->mBuffers[channel].mData; for(UInt32 sample = channel; sample < frame.samples * mFormat.mChannelsPerFrame; sample += mFormat.mChannelsPerFrame) *floatBuffer++ = inputBuffer[sample]; mBufferList->mBuffers[channel].mNumberChannels = 1; mBufferList->mBuffers[channel].mDataByteSize = frame.samples * sizeof(float); } #endif /* MPC_FIXED_POINT */ } mCurrentFrame += framesRead; return framesRead; }
/* 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 void gst_musepackdec_loop (GstPad * sinkpad) { GstMusepackDec *musepackdec; GstFlowReturn flow; GstBuffer *out; #ifdef MPC_IS_OLD_API guint32 update_acc, update_bits; #else mpc_frame_info frame; mpc_status err; #endif gint num_samples, samplerate, bitspersample; musepackdec = GST_MUSEPACK_DEC (GST_PAD_PARENT (sinkpad)); samplerate = g_atomic_int_get (&musepackdec->rate); if (samplerate == 0) { if (!gst_musepack_stream_init (musepackdec)) goto pause_task; gst_musepackdec_send_newsegment (musepackdec); samplerate = g_atomic_int_get (&musepackdec->rate); } bitspersample = g_atomic_int_get (&musepackdec->bps); flow = gst_pad_alloc_buffer_and_set_caps (musepackdec->srcpad, -1, MPC_DECODER_BUFFER_LENGTH * 4, GST_PAD_CAPS (musepackdec->srcpad), &out); if (flow != GST_FLOW_OK) { GST_DEBUG_OBJECT (musepackdec, "Flow: %s", gst_flow_get_name (flow)); goto pause_task; } #ifdef MPC_IS_OLD_API num_samples = mpc_decoder_decode (musepackdec->d, (MPC_SAMPLE_FORMAT *) GST_BUFFER_DATA (out), &update_acc, &update_bits); if (num_samples < 0) { GST_ERROR_OBJECT (musepackdec, "Failed to decode sample"); GST_ELEMENT_ERROR (musepackdec, STREAM, DECODE, (NULL), (NULL)); goto pause_task; } else if (num_samples == 0) { goto eos_and_pause; } #else frame.buffer = (MPC_SAMPLE_FORMAT *) GST_BUFFER_DATA (out); err = mpc_demux_decode (musepackdec->d, &frame); if (err != MPC_STATUS_OK) { GST_ERROR_OBJECT (musepackdec, "Failed to decode sample"); GST_ELEMENT_ERROR (musepackdec, STREAM, DECODE, (NULL), (NULL)); goto pause_task; } else if (frame.bits == -1) { goto eos_and_pause; } num_samples = frame.samples; #endif GST_BUFFER_SIZE (out) = num_samples * bitspersample; GST_BUFFER_OFFSET (out) = musepackdec->segment.last_stop; GST_BUFFER_TIMESTAMP (out) = gst_util_uint64_scale_int (musepackdec->segment.last_stop, GST_SECOND, samplerate); GST_BUFFER_DURATION (out) = gst_util_uint64_scale_int (num_samples, GST_SECOND, samplerate); musepackdec->segment.last_stop += num_samples; GST_LOG_OBJECT (musepackdec, "Pushing buffer, timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out))); flow = gst_pad_push (musepackdec->srcpad, out); if (flow != GST_FLOW_OK) { GST_DEBUG_OBJECT (musepackdec, "Flow: %s", gst_flow_get_name (flow)); goto pause_task; } /* check if we're at the end of a configured segment */ if (musepackdec->segment.stop != -1 && musepackdec->segment.last_stop >= musepackdec->segment.stop) { gint64 stop_time; GST_DEBUG_OBJECT (musepackdec, "Reached end of configured segment"); if ((musepackdec->segment.flags & GST_SEEK_FLAG_SEGMENT) == 0) goto eos_and_pause; GST_DEBUG_OBJECT (musepackdec, "Posting SEGMENT_DONE message"); stop_time = gst_util_uint64_scale_int (musepackdec->segment.stop, GST_SECOND, samplerate); gst_element_post_message (GST_ELEMENT (musepackdec), gst_message_new_segment_done (GST_OBJECT (musepackdec), GST_FORMAT_TIME, stop_time)); goto pause_task; } return; eos_and_pause: { GST_DEBUG_OBJECT (musepackdec, "sending EOS event"); gst_pad_push_event (musepackdec->srcpad, gst_event_new_eos ()); /* fall through to pause */ } pause_task: { GST_DEBUG_OBJECT (musepackdec, "Pausing task"); gst_pad_pause_task (sinkpad); return; } }
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; }