SINT SoundSourceWV::readSampleFrames( SINT numberOfFrames, CSAMPLE* sampleBuffer) { if (sampleBuffer == nullptr) { // NOTE(uklotzde): The WavPack API does not provide any // functions for skipping samples in the audio stream. Calling // API functions with a nullptr buffer does not return. Since // we don't want to read samples into a temporary buffer that // has to be allocated we are seeking to the position after // the skipped samples. SINT curFrameIndexBefore = m_curFrameIndex; SINT curFrameIndexAfter = seekSampleFrame(m_curFrameIndex + numberOfFrames); DEBUG_ASSERT(curFrameIndexBefore <= curFrameIndexAfter); DEBUG_ASSERT(m_curFrameIndex == curFrameIndexAfter); return curFrameIndexAfter - curFrameIndexBefore; } // static assert: sizeof(CSAMPLE) == sizeof(int32_t) SINT unpackCount = WavpackUnpackSamples(m_wpc, reinterpret_cast<int32_t*>(sampleBuffer), numberOfFrames); DEBUG_ASSERT(unpackCount >= 0); if (!(WavpackGetMode(m_wpc) & MODE_FLOAT)) { // signed integer -> float const SINT sampleCount = frames2samples(unpackCount); for (SINT i = 0; i < sampleCount; ++i) { const int32_t sampleValue = reinterpret_cast<int32_t*>(sampleBuffer)[i]; sampleBuffer[i] = CSAMPLE(sampleValue) * m_sampleScaleFactor; } } m_curFrameIndex += unpackCount; return unpackCount; }
index_t soundfile_read_double(soundfile_t *sf, double *buffer, index_t n_frames) { if (sf->t == sft_libsndfile) { return sf_read_double(sf->p, buffer, n_frames); } else { int buffer_size = 65536; int32_t b[buffer_size*sf->channels]; index_t frames_read = 0; double divisor = 1L << (sf->bits_per_sample - 1); while (1) { int to_read = MIN(buffer_size, n_frames - frames_read); if (to_read <= 0) return frames_read; int n = WavpackUnpackSamples(sf->p, b, to_read); if (n < 0 || (n == 0 && frames_read == 0)) die("WavpackUnpackSamples returned %d", n); if (n == 0) return frames_read; for (index_t f = 0; f < n; f++) { for (int c = 0; c < sf->channels; c++) buffer[frames_read*sf->channels+c] = b[f*sf->channels+c]/divisor; frames_read++; } } } }
static int wav_decode (void *prv_data, char *buf, int buf_len, struct sound_params *sound_params) { struct wavpack_data *data = (struct wavpack_data *)prv_data; int ret, i, s_num, iBps, oBps; int8_t * buf8 = (int8_t *)buf; int16_t * buf16 = (int16_t *)buf; int32_t * buf32 = (int32_t *)buf; iBps = data->channels * WavpackGetBytesPerSample (data->wpc); oBps = (iBps == 6) ? 8 : iBps; s_num = buf_len / oBps; decoder_error_clear (&data->error); int32_t *dbuf = (int32_t *)xcalloc ( s_num, data->channels * 4); ret = WavpackUnpackSamples (data->wpc, dbuf, s_num ); if (ret == 0) { free (dbuf); return 0; } if (data->mode & MODE_FLOAT) { sound_params->fmt = SFMT_FLOAT; memcpy (buf, dbuf, ret * oBps); } else { debug ("iBps %d", iBps); switch (iBps / data->channels){ case 4: for (i = 0; i < ret * data->channels; i++) buf32[i] = dbuf[i]; sound_params->fmt = SFMT_S32 | SFMT_NE; break; case 3: for (i = 0; i < ret * data->channels; i++) buf32[i] = dbuf[i] * 256; sound_params->fmt = SFMT_S32 | SFMT_NE; break; case 2: for (i = 0; i < ret * data->channels; i++) buf16[i] = dbuf[i]; sound_params->fmt = SFMT_S16 | SFMT_NE; break; case 1: for (i = 0; i < ret * data->channels; i++) buf8[i] = dbuf[i]; sound_params->fmt = SFMT_S8 | SFMT_NE; } } sound_params->channels = data->channels; sound_params->rate = data->sample_rate; free (dbuf); return ret * oBps ; }
decoded_samples WavPackDecoder::decode(const char* data, std::size_t bytes) { _data = data; _dataSize = bytes; _pos = 0; if (! _context) { _context = WavpackOpenFileInputEx(&_streamReader, this, 0, _errMsgStorage.get(), OPEN_STREAMING, 0); if (! _context) { std::string errmsg("Could not set up input stream: "); errmsg += std::string(_errMsgStorage.get()); throw std::runtime_error(errmsg); } } uint32_t sampleCount = WavpackUnpackSamples(_context, _decodeBuffer.get(), DECODE_BUFFER_SZ); uint32_t sampleCountFinal = sampleCount; int32_t* p = _decodeBuffer.get(); char* outBytes = _decodedPcm.get(); //unpack the samples back to original bit depth switch (BIT_DEPTH) { case 16: while (sampleCount > 0) { *((int16_t *)outBytes) = (int16_t)(*p); outBytes += sizeof (int16_t); p++; sampleCount--; } break; case 8: while (sampleCount > 0) { *outBytes++ = (char)(*p); p++; sampleCount--; } break; } decoded_samples ret; ret.NumSamples = sampleCountFinal; ret.SampleData = _decodedPcm.get(); return ret; }
static int WAVPACK_infile_decode(struct mpxplay_filehand_buffered_func_s *fbfs,void *fbds,struct mpxplay_infile_info_s *miis) { mpxplay_audio_decoder_info_s *adi=miis->audio_decoder_infos; struct wavpack_decoder_data *wpdi=miis->private_data; WavpackUpdateStreamhand(wpdi->wpc,fbds); adi->pcm_samplenum=WavpackUnpackSamples(wpdi->wpc,(long *)adi->pcm_bufptr,adi->pcm_framelen)*adi->outchannels; if(!adi->pcm_samplenum) return MPXPLAY_ERROR_INFILE_NODATA; if(wpdi->bytes_per_sample<4) format_samples(wpdi->bytes_per_sample,(unsigned char *)adi->pcm_bufptr,(long *)adi->pcm_bufptr,adi->pcm_samplenum); return MPXPLAY_ERROR_INFILE_OK; }
SINT SoundSourceWV::readSampleFrames( SINT numberOfFrames, CSAMPLE* sampleBuffer) { // static assert: sizeof(CSAMPLE) == sizeof(int32_t) SINT unpackCount = WavpackUnpackSamples(m_wpc, reinterpret_cast<int32_t*>(sampleBuffer), numberOfFrames); if (!(WavpackGetMode(m_wpc) & MODE_FLOAT)) { // signed integer -> float const SINT sampleCount = frames2samples(unpackCount); for (SINT i = 0; i < sampleCount; ++i) { const int32_t sampleValue = reinterpret_cast<int32_t*>(sampleBuffer)[i]; sampleBuffer[i] = CSAMPLE(sampleValue) * m_sampleScaleFactor; } } return unpackCount; }
static int decode_data(char *target, int max_size) { int bps, channels; uint32_t samples_unpacked = 0; channels = get_channels(); bps = WavpackGetBytesPerSample(wpc); if (max_size >= 1024) { samples_unpacked = WavpackUnpackSamples(wpc, temp_buffer, 256 / channels); total_unpacked_samples += samples_unpacked; if (samples_unpacked) format_samples(bps, (uchar *)target, temp_buffer, samples_unpacked * channels); } else { printf("vorbis: Target buffer too small: %d < 1024\n", max_size); } return samples_unpacked * (WavpackGetBitsPerSample(wpc) / 4); }
ReadableSampleFrames SoundSourceWV::readSampleFramesClamped( WritableSampleFrames writableSampleFrames) { const SINT firstFrameIndex = writableSampleFrames.frameIndexRange().start(); if (m_curFrameIndex != firstFrameIndex) { if (WavpackSeekSample(m_wpc, firstFrameIndex)) { m_curFrameIndex = firstFrameIndex; } else { kLogger.warning() << "Could not seek to first frame index" << firstFrameIndex; m_curFrameIndex = WavpackGetSampleIndex(m_wpc); return ReadableSampleFrames(IndexRange::between(m_curFrameIndex, m_curFrameIndex)); } } DEBUG_ASSERT(m_curFrameIndex == firstFrameIndex); const SINT numberOfFramesTotal = writableSampleFrames.frameLength(); static_assert(sizeof(CSAMPLE) == sizeof(int32_t), "CSAMPLE and int32_t must have the same size"); CSAMPLE* pOutputBuffer = writableSampleFrames.writableData(); SINT unpackCount = WavpackUnpackSamples(m_wpc, reinterpret_cast<int32_t*>(pOutputBuffer), numberOfFramesTotal); DEBUG_ASSERT(unpackCount >= 0); DEBUG_ASSERT(unpackCount <= numberOfFramesTotal); if (!(WavpackGetMode(m_wpc) & MODE_FLOAT)) { // signed integer -> float const SINT sampleCount = frames2samples(unpackCount); for (SINT i = 0; i < sampleCount; ++i) { const int32_t sampleValue = *reinterpret_cast<int32_t*>(pOutputBuffer); *pOutputBuffer++ = CSAMPLE(sampleValue) * m_sampleScaleFactor; } } const auto resultRange = IndexRange::forward(m_curFrameIndex, unpackCount); m_curFrameIndex += unpackCount; return ReadableSampleFrames( resultRange, SampleBuffer::ReadableSlice( writableSampleFrames.writableData(), frames2samples(unpackCount))); }
bool AKSampler_Plugin::loadCompressedSampleFile(AKSampleFileDescriptor& sfd, float volBoostDb) { char errMsg[100]; WavpackContext* wpc = WavpackOpenFileInput(sfd.path, errMsg, OPEN_2CH_MAX, 0); if (wpc == 0) { printf("Wavpack error loading %s: %s\n", sfd.path, errMsg); return false; } AKSampleDataDescriptor sdd; sdd.sampleDescriptor = sfd.sampleDescriptor; sdd.sampleRate = (float)WavpackGetSampleRate(wpc); sdd.channelCount = WavpackGetReducedChannels(wpc); sdd.sampleCount = WavpackGetNumSamples(wpc); sdd.isInterleaved = sdd.channelCount > 1; sdd.data = new float[sdd.channelCount * sdd.sampleCount]; int mode = WavpackGetMode(wpc); WavpackUnpackSamples(wpc, (int32_t*)sdd.data, sdd.sampleCount); if ((mode & MODE_FLOAT) == 0) { // convert samples to floating-point int bps = WavpackGetBitsPerSample(wpc); float scale = 1.0f / (1 << (bps - 1)); float* pf = sdd.data; int32_t* pi = (int32_t*)pf; for (int i = 0; i < (sdd.sampleCount * sdd.channelCount); i++) *pf++ = scale * *pi++; } if (volBoostDb != 0.0f) { float scale = exp(volBoostDb / 20.0f); float* pf = sdd.data; for (int i = 0; i < (sdd.sampleCount * sdd.channelCount); i++) *pf++ *= scale; } loadSampleData(sdd); delete[] sdd.data; return true; }
EmErrorCode WvDecoder::DecodeUnit(char* data, uint32_t& used, uint32_t& unitCount) { if (m_UnitIndex < m_UnitCount) { unitCount = 1; // according to wavpack's source code cli/wvunpack.c uint32_t nsamples = WavpackUnpackSamples(m_Ctx, (int32_t*)&m_Buf[0], unitCount*m_Channels); format_samples(m_BytesPerSample, (unsigned char*)data, &m_Buf[0], nsamples*m_Channels); used = nsamples * m_BytesPerSample * m_Channels; m_UnitIndex += unitCount; m_BitRate = WavpackGetInstantBitrate(m_Ctx)/1000; return ErrorCode::Ok; } used = 0; unitCount = m_UnitCount; m_BitRate = 0; return ErrorCode::DecoderOutOfRange; }
/* this is called for each file to process */ enum codec_status codec_run(void) { WavpackContext *wpc; char error [80]; /* rockbox: comment 'set but unused' variables int bps; */ int nchans, sr_100; intptr_t param; if (codec_init()) return CODEC_ERROR; ci->seek_buffer (ci->id3->offset); /* Create a decoder instance */ wpc = WavpackOpenFileInput (read_callback, error); if (!wpc) return CODEC_ERROR; ci->configure(DSP_SWITCH_FREQUENCY, WavpackGetSampleRate (wpc)); codec_set_replaygain(ci->id3); /* bps = WavpackGetBytesPerSample (wpc); */ nchans = WavpackGetReducedChannels (wpc); ci->configure(DSP_SET_STEREO_MODE, nchans == 2 ? STEREO_INTERLEAVED : STEREO_MONO); sr_100 = ci->id3->frequency / 100; ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10); /* The main decoder loop */ while (1) { int32_t nsamples; enum codec_command_action action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) break; if (action == CODEC_ACTION_SEEK_TIME) { int curpos_ms = WavpackGetSampleIndex (wpc) / sr_100 * 10; int n, d, skip; if (param > curpos_ms) { n = param - curpos_ms; d = ci->id3->length - curpos_ms; skip = (int)((int64_t)(ci->filesize - ci->curpos) * n / d); ci->seek_buffer (ci->curpos + skip); } else if (curpos_ms != 0) { n = curpos_ms - param; d = curpos_ms; skip = (int)((int64_t) ci->curpos * n / d); ci->seek_buffer (ci->curpos - skip); } wpc = WavpackOpenFileInput (read_callback, error); if (!wpc) { ci->seek_complete(); break; } ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10); ci->seek_complete(); } nsamples = WavpackUnpackSamples (wpc, temp_buffer, BUFFER_SIZE / nchans); if (!nsamples) break; ci->pcmbuf_insert (temp_buffer, NULL, nsamples); ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10); } return CODEC_OK; }
static bool_t wv_play (InputPlayback * playback, const char * filename, VFSFile * file, int start_time, int stop_time, bool_t pause) { if (file == NULL) return FALSE; int32_t *input = NULL; void *output = NULL; int sample_rate, num_channels, bits_per_sample; unsigned num_samples; WavpackContext *ctx = NULL; VFSFile *wvc_input = NULL; bool_t error = FALSE; if (! wv_attach (filename, file, & wvc_input, & ctx, NULL, OPEN_TAGS | OPEN_WVC)) { fprintf (stderr, "Error opening Wavpack file '%s'.", filename); error = TRUE; goto error_exit; } sample_rate = WavpackGetSampleRate(ctx); num_channels = WavpackGetNumChannels(ctx); bits_per_sample = WavpackGetBitsPerSample(ctx); num_samples = WavpackGetNumSamples(ctx); if (!playback->output->open_audio(SAMPLE_FMT(bits_per_sample), sample_rate, num_channels)) { fprintf (stderr, "Error opening audio output."); error = TRUE; goto error_exit; } if (pause) playback->output->pause(TRUE); input = malloc(BUFFER_SIZE * num_channels * sizeof(uint32_t)); output = malloc(BUFFER_SIZE * num_channels * SAMPLE_SIZE(bits_per_sample)); if (input == NULL || output == NULL) goto error_exit; playback->set_gain_from_playlist(playback); pthread_mutex_lock (& mutex); playback->set_params(playback, (int) WavpackGetAverageBitrate(ctx, num_channels), sample_rate, num_channels); seek_value = (start_time > 0) ? start_time : -1; stop_flag = FALSE; playback->set_pb_ready(playback); pthread_mutex_unlock (& mutex); while (!stop_flag && (stop_time < 0 || playback->output->written_time () < stop_time)) { int ret; unsigned samples_left; /* Handle seek and pause requests */ pthread_mutex_lock (& mutex); if (seek_value >= 0) { playback->output->flush (seek_value); WavpackSeekSample (ctx, (int64_t) seek_value * sample_rate / 1000); seek_value = -1; } pthread_mutex_unlock (& mutex); /* Decode audio data */ samples_left = num_samples - WavpackGetSampleIndex(ctx); ret = WavpackUnpackSamples(ctx, input, BUFFER_SIZE); if (samples_left == 0) stop_flag = TRUE; else if (ret < 0) { fprintf (stderr, "Error decoding file.\n"); break; } else { /* Perform audio data conversion and output */ unsigned i; int32_t *rp = input; int8_t *wp = output; int16_t *wp2 = output; int32_t *wp4 = output; if (bits_per_sample == 8) { for (i = 0; i < ret * num_channels; i++, wp++, rp++) *wp = *rp & 0xff; } else if (bits_per_sample == 16) { for (i = 0; i < ret * num_channels; i++, wp2++, rp++) *wp2 = *rp & 0xffff; } else if (bits_per_sample == 24 || bits_per_sample == 32) { for (i = 0; i < ret * num_channels; i++, wp4++, rp++) *wp4 = *rp; } playback->output->write_audio(output, ret * num_channels * SAMPLE_SIZE(bits_per_sample)); } } error_exit: free(input); free(output); wv_deattach (wvc_input, ctx); stop_flag = TRUE; return ! error; }
int CSound::DecodeWV(int SampleID, const void *pData, unsigned DataSize) { if(SampleID == -1 || SampleID >= NUM_SAMPLES) return -1; CSample *pSample = &m_aSamples[SampleID]; char aError[100]; WavpackContext *pContext; ms_pWVBuffer = pData; ms_WVBufferSize = DataSize; ms_WVBufferPosition = 0; pContext = WavpackOpenFileInput(ReadData, aError); if (pContext) { int NumSamples = WavpackGetNumSamples(pContext); int BitsPerSample = WavpackGetBitsPerSample(pContext); unsigned int SampleRate = WavpackGetSampleRate(pContext); int NumChannels = WavpackGetNumChannels(pContext); int *pSrc; short *pDst; int i; pSample->m_Channels = NumChannels; pSample->m_Rate = SampleRate; if(pSample->m_Channels > 2) { dbg_msg("sound/wv", "file is not mono or stereo."); return -1; } if(BitsPerSample != 16) { dbg_msg("sound/wv", "bps is %d, not 16", BitsPerSample); return -1; } int *pBuffer = (int *)mem_alloc(4*NumSamples*NumChannels, 1); WavpackUnpackSamples(pContext, pBuffer, NumSamples); // TODO: check return value pSrc = pBuffer; pSample->m_pData = (short *)mem_alloc(2*NumSamples*NumChannels, 1); pDst = pSample->m_pData; for (i = 0; i < NumSamples*NumChannels; i++) *pDst++ = (short)*pSrc++; mem_free(pBuffer); pSample->m_NumFrames = NumSamples; pSample->m_LoopStart = -1; pSample->m_LoopEnd = -1; pSample->m_PausedAt = 0; } else { dbg_msg("sound/wv", "failed to decode sample (%s)", aError); return -1; } return SampleID; }
static void * DecodeThread(void *a) { ape_tag tag; char *filename = (char *) a; int bps_updateCounter = 0; int bps; int i; WavpackDecoder d(&mod); if (!d.attach(filename)) { printf("wavpack: Error opening file: \"%s\"\n", filename); killDecodeThread = true; return end_thread(); } bps = WavpackGetBytesPerSample(d.ctx) * d.num_channels; DBG("reading %s at %d rate with %d channels\n", filename, d.sample_rate, d.num_channels); if (!d.open_audio()) { DBG("error opening xmms audio channel\n"); killDecodeThread = true; AudioError = true; openedAudio = false; } else { DBG("opened xmms audio channel\n"); openedAudio = true; } unsigned status; char *display = generate_title(filename, d.ctx); int length = (int) (1000 * WavpackGetNumSamples(d.ctx)); while (!killDecodeThread) { if (isSeek != -1) { DBG("seeking to position %d\n", isSeek); WavpackSeekSample(d.ctx, isSeek * d.sample_rate); isSeek = -1; } if (paused == 0 && (mod.output->buffer_free() >= (1152 * 2 * (16 / 8)) << (mod.output->buffer_playing()? 1 : 0))) { status = WavpackUnpackSamples(d.ctx, d.input, BUFFER_SIZE); if (status == (unsigned) (-1)) { printf("wavpack: Error decoding file.\n"); break; } else if (status == 0) { killDecodeThread = true; break; } else { d.process_buffer(status); } } else { xmms_usleep(10000); } } return end_thread(); }
int snd_load_wv(const char *filename) { SAMPLE *snd; int sid = -1; char error[100]; WavpackContext *context; /* don't waste memory on sound when we are stress testing */ if(config.dbg_stress) return -1; /* no need to load sound when we are running with no sound */ if(!sound_enabled) return 1; file = engine_openfile(filename, IOFLAG_READ); /* TODO: use system.h stuff for this */ if(!file) { dbg_msg("sound/wv", "failed to open %s", filename); return -1; } sid = snd_alloc_id(); if(sid < 0) return -1; snd = &samples[sid]; context = WavpackOpenFileInput(read_data, error); if (context) { int samples = WavpackGetNumSamples(context); int bitspersample = WavpackGetBitsPerSample(context); unsigned int samplerate = WavpackGetSampleRate(context); int channels = WavpackGetNumChannels(context); int *data; int *src; short *dst; int i; snd->channels = channels; snd->rate = samplerate; if(snd->channels > 2) { dbg_msg("sound/wv", "file is not mono or stereo. filename='%s'", filename); return -1; } /* if(snd->rate != 44100) { dbg_msg("sound/wv", "file is %d Hz, not 44100 Hz. filename='%s'", snd->rate, filename); return -1; }*/ if(bitspersample != 16) { dbg_msg("sound/wv", "bps is %d, not 16, filname='%s'", bitspersample, filename); return -1; } data = (int *)mem_alloc(4*samples*channels, 1); WavpackUnpackSamples(context, data, samples); /* TODO: check return value */ src = data; snd->data = (short *)mem_alloc(2*samples*channels, 1); dst = snd->data; for (i = 0; i < samples*channels; i++) *dst++ = (short)*src++; mem_free(data); snd->num_frames = samples; snd->loop_start = -1; snd->loop_end = -1; } else { dbg_msg("sound/wv", "failed to open %s: %s", filename, error); } io_close(file); file = NULL; if(config.debug) dbg_msg("sound/wv", "loaded %s", filename); rate_convert(sid); return sid; }
/* * This does the main decoding thing. * Requires an already opened WavpackContext. */ static void wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek) { GError *error = NULL; bool is_float; enum sample_format sample_format; struct audio_format audio_format; format_samples_t format_samples; float total_time; int bytes_per_sample, output_sample_size; is_float = (WavpackGetMode(wpc) & MODE_FLOAT) != 0; sample_format = wavpack_bits_to_sample_format(is_float, WavpackGetBytesPerSample(wpc)); if (!audio_format_init_checked(&audio_format, WavpackGetSampleRate(wpc), sample_format, WavpackGetNumChannels(wpc), &error)) { g_warning("%s", error->message); g_error_free(error); return; } if (is_float) { format_samples = format_samples_float; } else { format_samples = format_samples_int; } total_time = WavpackGetNumSamples(wpc); total_time /= audio_format.sample_rate; bytes_per_sample = WavpackGetBytesPerSample(wpc); output_sample_size = audio_format_frame_size(&audio_format); /* wavpack gives us all kind of samples in a 32-bit space */ int32_t chunk[1024]; const uint32_t samples_requested = G_N_ELEMENTS(chunk) / audio_format.channels; decoder_initialized(decoder, &audio_format, can_seek, total_time); enum decoder_command cmd = decoder_get_command(decoder); while (cmd != DECODE_COMMAND_STOP) { if (cmd == DECODE_COMMAND_SEEK) { if (can_seek) { unsigned where = decoder_seek_where(decoder) * audio_format.sample_rate; if (WavpackSeekSample(wpc, where)) { decoder_command_finished(decoder); } else { decoder_seek_error(decoder); } } else { decoder_seek_error(decoder); } } uint32_t samples_got = WavpackUnpackSamples(wpc, chunk, samples_requested); if (samples_got == 0) break; int bitrate = (int)(WavpackGetInstantBitrate(wpc) / 1000 + 0.5); format_samples(bytes_per_sample, chunk, samples_got * audio_format.channels); cmd = decoder_data(decoder, NULL, chunk, samples_got * output_sample_size, bitrate); } }
static int wv_read (DB_fileinfo_t *_info, char *bytes, int size) { wvctx_t *info = (wvctx_t *)_info; int currentsample = WavpackGetSampleIndex (info->ctx); int samplesize = _info->fmt.channels * _info->fmt.bps / 8; if (size / samplesize + currentsample > info->endsample) { size = (info->endsample - currentsample + 1) * samplesize; trace ("wv: size truncated to %d bytes (%d samples), cursample=%d, endsample=%d\n", size, info->endsample - currentsample + 1, currentsample, info->endsample); if (size <= 0) { return 0; } } int initsize = size; int n; if (WavpackGetMode (info->ctx) & MODE_FLOAT) { _info->fmt.is_float = 1; } if (_info->fmt.is_float || _info->fmt.bps == 32) { n = WavpackUnpackSamples (info->ctx, (int32_t *)bytes, size / samplesize); size -= n * samplesize; } else { int32_t buffer[size/(_info->fmt.bps / 8)]; n = WavpackUnpackSamples (info->ctx, (int32_t *)buffer, size / samplesize); size -= n * samplesize; n *= _info->fmt.channels; // convert from int32 to input (what???) int32_t *p = buffer; if (_info->fmt.bps == 16) { while (n > 0) { *((int16_t *)bytes) = (int16_t)(*p); bytes += sizeof (int16_t); p++; n--; } } else if (_info->fmt.bps == 8) { while (n > 0) { *bytes++ = (char)(*p); p++; n--; } } else if (_info->fmt.bps == 24) { while (n > 0) { *bytes++ = (*p)&0xff; *bytes++ = ((*p)&0xff00)>>8; *bytes++ = ((*p)&0xff0000)>>16; p++; n--; } } } _info->readpos = (float)(WavpackGetSampleIndex (info->ctx)-info->startsample)/WavpackGetSampleRate (info->ctx); #ifndef TINYWV deadbeef->streamer_set_bitrate (WavpackGetInstantBitrate (info->ctx) / 1000); #endif return initsize-size; }
static gint xmms_wavpack_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, xmms_error_t *error) { xmms_wavpack_data_t *data; gint mono_samples, samples; xmms_samples32_t *buf32; gint i; g_return_val_if_fail (xform, -1); data = xmms_xform_private_data_get (xform); g_return_val_if_fail (data, -1); switch (data->bits_per_sample) { case 8: mono_samples = len; xmms_wavpack_ensure_buf (data, mono_samples); buf32 = data->buf; break; case 12: case 16: mono_samples = len / 2; xmms_wavpack_ensure_buf (data, mono_samples); buf32 = data->buf; break; case 24: mono_samples = len / 4; buf32 = buf; break; case 32: mono_samples = len / 4; buf32 = buf; break; } samples = mono_samples / data->channels; samples = WavpackUnpackSamples (data->ctx, buf32, samples); mono_samples = samples * data->channels; switch (data->bits_per_sample) { case 8: len = mono_samples; for (i=0; i<mono_samples; ++i) { ((xmms_samples8_t *) buf)[i] = data->buf[i]; } break; case 12: len = mono_samples * 2; for (i=0; i<mono_samples; ++i) { ((xmms_samples16_t *) buf)[i] = data->buf[i] << 4; } break; case 16: len = mono_samples * 2; for (i=0; i<mono_samples; ++i) { ((xmms_samples16_t *) buf)[i] = data->buf[i]; } break; case 24: len = mono_samples * 4; for (i=0; i<mono_samples; ++i) { ((xmms_samples32_t *) buf)[i] <<= 8; } break; case 32: len = mono_samples * 4; break; } return len; }
UInt32 WavPackDecoder::ReadAudio(AudioBufferList *bufferList, UInt32 frameCount) { if(!IsOpen() || nullptr == bufferList || bufferList->mNumberBuffers != mFormat.mChannelsPerFrame || 0 == frameCount) return 0; // Reset output buffer data size for(UInt32 i = 0; i < bufferList->mNumberBuffers; ++i) bufferList->mBuffers[i].mDataByteSize = 0; UInt32 framesRemaining = frameCount; UInt32 totalFramesRead = 0; while(0 < framesRemaining) { UInt32 framesToRead = std::min(framesRemaining, static_cast<UInt32>(BUFFER_SIZE_FRAMES)); // Wavpack uses "complete" samples (one sample across all channels), i.e. a Core Audio frame uint32_t samplesRead = WavpackUnpackSamples(mWPC, mBuffer, framesToRead); if(0 == samplesRead) break; // The samples returned are handled differently based on the file's mode int mode = WavpackGetMode(mWPC); // Floating point files require no special handling other than deinterleaving if(MODE_FLOAT & mode) { float *inputBuffer = reinterpret_cast<float *>(mBuffer); // Deinterleave the samples for(UInt32 channel = 0; channel < mFormat.mChannelsPerFrame; ++channel) { float *floatBuffer = static_cast<float *>(bufferList->mBuffers[channel].mData); for(UInt32 sample = channel; sample < samplesRead * mFormat.mChannelsPerFrame; sample += mFormat.mChannelsPerFrame) *floatBuffer++ = inputBuffer[sample]; bufferList->mBuffers[channel].mNumberChannels = 1; bufferList->mBuffers[channel].mDataByteSize = static_cast<UInt32>(samplesRead * sizeof(float)); } } // Lossless files will be handed off as integers else if(MODE_LOSSLESS & mode) { // WavPack hands us 32-bit signed ints with the samples low-aligned; shift them to high alignment UInt32 shift = static_cast<UInt32>(8 * (sizeof(int32_t) - WavpackGetBytesPerSample(mWPC))); // Deinterleave the 32-bit samples and shift to high-alignment for(UInt32 channel = 0; channel < mFormat.mChannelsPerFrame; ++channel) { int32_t *shiftedBuffer = static_cast<int32_t *>(bufferList->mBuffers[channel].mData); for(UInt32 sample = channel; sample < samplesRead * mFormat.mChannelsPerFrame; sample += mFormat.mChannelsPerFrame) *shiftedBuffer++ = mBuffer[sample] << shift; bufferList->mBuffers[channel].mNumberChannels = 1; bufferList->mBuffers[channel].mDataByteSize = static_cast<UInt32>(samplesRead * sizeof(int32_t)); } } // Convert lossy files to float else { float scaleFactor = (1 << ((WavpackGetBytesPerSample(mWPC) * 8) - 1)); // Deinterleave the 32-bit samples and convert to float for(UInt32 channel = 0; channel < mFormat.mChannelsPerFrame; ++channel) { float *floatBuffer = static_cast<float *>(bufferList->mBuffers[channel].mData); for(UInt32 sample = channel; sample < samplesRead * mFormat.mChannelsPerFrame; sample += mFormat.mChannelsPerFrame) *floatBuffer++ = mBuffer[sample] / scaleFactor; bufferList->mBuffers[channel].mNumberChannels = 1; bufferList->mBuffers[channel].mDataByteSize = static_cast<UInt32>(samplesRead * sizeof(float)); } } totalFramesRead += samplesRead; framesRemaining -= samplesRead; } mCurrentFrame += totalFramesRead; return totalFramesRead; }
uint32_t wavpack_buffer_decoder_unpack(wavpack_buffer_decoder* wbd, int32_t* buffer, uint32_t samples) { return WavpackUnpackSamples (wbd->wpc, buffer, samples); }
int CSound::LoadWV(const char *pFilename) { CSample *pSample; int SampleID = -1; char aError[100]; WavpackContext *pContext; // don't waste memory on sound when we are stress testing if(g_Config.m_DbgStress) return -1; // no need to load sound when we are running with no sound if(!m_SoundEnabled) return 1; if(!m_pStorage) return -1; ms_File = m_pStorage->OpenFile(pFilename, IOFLAG_READ, IStorage::TYPE_ALL); if(!ms_File) { dbg_msg("sound/wv", "failed to open file. filename='%s'", pFilename); return -1; } SampleID = AllocID(); if(SampleID < 0) return -1; pSample = &m_aSamples[SampleID]; pContext = WavpackOpenFileInput(ReadData, aError); if (pContext) { int m_aSamples = WavpackGetNumSamples(pContext); int BitsPerSample = WavpackGetBitsPerSample(pContext); unsigned int SampleRate = WavpackGetSampleRate(pContext); int m_aChannels = WavpackGetNumChannels(pContext); int *pData; int *pSrc; short *pDst; int i; pSample->m_Channels = m_aChannels; pSample->m_Rate = SampleRate; if(pSample->m_Channels > 2) { dbg_msg("sound/wv", "file is not mono or stereo. filename='%s'", pFilename); return -1; } /* if(snd->rate != 44100) { dbg_msg("sound/wv", "file is %d Hz, not 44100 Hz. filename='%s'", snd->rate, filename); return -1; }*/ if(BitsPerSample != 16) { dbg_msg("sound/wv", "bps is %d, not 16, filname='%s'", BitsPerSample, pFilename); return -1; } pData = (int *)mem_alloc(4*m_aSamples*m_aChannels, 1); WavpackUnpackSamples(pContext, pData, m_aSamples); // TODO: check return value pSrc = pData; pSample->m_pData = (short *)mem_alloc(2*m_aSamples*m_aChannels, 1); pDst = pSample->m_pData; for (i = 0; i < m_aSamples*m_aChannels; i++) *pDst++ = (short)*pSrc++; mem_free(pData); pSample->m_NumFrames = m_aSamples; pSample->m_LoopStart = -1; pSample->m_LoopEnd = -1; pSample->m_PausedAt = 0; } else { dbg_msg("sound/wv", "failed to open %s: %s", pFilename, aError); } io_close(ms_File); ms_File = NULL; if(g_Config.m_Debug) dbg_msg("sound/wv", "loaded %s", pFilename); RateConvert(SampleID); return SampleID; }
/* this is the codec entry point */ enum codec_status codec_main(void) { WavpackContext *wpc; char error [80]; int bps, nchans, sr_100; int retval; /* Generic codec initialisation */ ci->configure(DSP_SET_SAMPLE_DEPTH, 28); next_track: if (codec_init()) { retval = CODEC_ERROR; goto exit; } while (!*ci->taginfo_ready && !ci->stop_codec) ci->sleep(1); /* Create a decoder instance */ wpc = WavpackOpenFileInput (read_callback, error); if (!wpc) { retval = CODEC_ERROR; goto done; } ci->configure(DSP_SWITCH_FREQUENCY, WavpackGetSampleRate (wpc)); codec_set_replaygain(ci->id3); bps = WavpackGetBytesPerSample (wpc); nchans = WavpackGetReducedChannels (wpc); ci->configure(DSP_SET_STEREO_MODE, nchans == 2 ? STEREO_INTERLEAVED : STEREO_MONO); sr_100 = ci->id3->frequency / 100; ci->set_elapsed (0); /* The main decoder loop */ while (1) { int32_t nsamples; if (ci->seek_time && ci->taginfo_ready && ci->id3->length) { ci->seek_time--; int curpos_ms = WavpackGetSampleIndex (wpc) / sr_100 * 10; int n, d, skip; if (ci->seek_time > curpos_ms) { n = ci->seek_time - curpos_ms; d = ci->id3->length - curpos_ms; skip = (int)((int64_t)(ci->filesize - ci->curpos) * n / d); ci->seek_buffer (ci->curpos + skip); } else { n = curpos_ms - ci->seek_time; d = curpos_ms; skip = (int)((int64_t) ci->curpos * n / d); ci->seek_buffer (ci->curpos - skip); } wpc = WavpackOpenFileInput (read_callback, error); ci->seek_complete(); if (!wpc) break; ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10); ci->yield (); } nsamples = WavpackUnpackSamples (wpc, temp_buffer, BUFFER_SIZE / nchans); if (!nsamples || ci->stop_codec || ci->new_track) break; ci->yield (); if (ci->stop_codec || ci->new_track) break; ci->pcmbuf_insert (temp_buffer, NULL, nsamples); ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10); ci->yield (); } retval = CODEC_OK; done: if (ci->request_next_track()) goto next_track; exit: return retval; }
static GstFlowReturn gst_wavpack_dec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buf) { GstWavpackDec *dec; GstBuffer *outbuf = NULL; GstFlowReturn ret = GST_FLOW_OK; WavpackHeader wph; int32_t decoded, unpacked_size; gboolean format_changed; gint width, depth, i, j, max; gint32 *dec_data = NULL; guint8 *out_data; GstMapInfo map, omap; dec = GST_WAVPACK_DEC (bdec); g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR); gst_buffer_map (buf, &map, GST_MAP_READ); /* check input, we only accept framed input with complete chunks */ if (map.size < sizeof (WavpackHeader)) goto input_not_framed; if (!gst_wavpack_read_header (&wph, map.data)) goto invalid_header; if (map.size < wph.ckSize + 4 * 1 + 4) goto input_not_framed; if (!(wph.flags & INITIAL_BLOCK)) goto input_not_framed; dec->wv_id.buffer = map.data; dec->wv_id.length = map.size; dec->wv_id.position = 0; /* create a new wavpack context if there is none yet but if there * was already one (i.e. caps were set on the srcpad) check whether * the new one has the same caps */ if (!dec->context) { gchar error_msg[80]; dec->context = WavpackOpenFileInputEx (dec->stream_reader, &dec->wv_id, NULL, error_msg, OPEN_STREAMING, 0); /* expect this to work */ if (!dec->context) { GST_WARNING_OBJECT (dec, "Couldn't decode buffer: %s", error_msg); goto context_failed; } } g_assert (dec->context != NULL); format_changed = (dec->sample_rate != WavpackGetSampleRate (dec->context)) || (dec->channels != WavpackGetNumChannels (dec->context)) || (dec->depth != WavpackGetBytesPerSample (dec->context) * 8) || (dec->channel_mask != WavpackGetChannelMask (dec->context)); if (!gst_pad_has_current_caps (GST_AUDIO_DECODER_SRC_PAD (dec)) || format_changed) { gint channel_mask; dec->sample_rate = WavpackGetSampleRate (dec->context); dec->channels = WavpackGetNumChannels (dec->context); dec->depth = WavpackGetBytesPerSample (dec->context) * 8; channel_mask = WavpackGetChannelMask (dec->context); if (channel_mask == 0) channel_mask = gst_wavpack_get_default_channel_mask (dec->channels); dec->channel_mask = channel_mask; gst_wavpack_dec_negotiate (dec); /* send GST_TAG_AUDIO_CODEC and GST_TAG_BITRATE tags before something * is decoded or after the format has changed */ gst_wavpack_dec_post_tags (dec); } /* alloc output buffer */ dec_data = g_malloc (4 * wph.block_samples * dec->channels); /* decode */ decoded = WavpackUnpackSamples (dec->context, dec_data, wph.block_samples); if (decoded != wph.block_samples) goto decode_error; unpacked_size = (dec->width / 8) * wph.block_samples * dec->channels; outbuf = gst_buffer_new_and_alloc (unpacked_size); /* legacy; pass along offset, whatever that might entail */ GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buf); gst_buffer_map (outbuf, &omap, GST_MAP_WRITE); out_data = omap.data; width = dec->width; depth = dec->depth; max = dec->channels * wph.block_samples; if (width == 8) { gint8 *outbuffer = (gint8 *) out_data; gint *reorder_map = dec->channel_reorder_map; for (i = 0; i < max; i += dec->channels) { for (j = 0; j < dec->channels; j++) *outbuffer++ = (gint8) (dec_data[i + reorder_map[j]]); } } else if (width == 16) { gint16 *outbuffer = (gint16 *) out_data; gint *reorder_map = dec->channel_reorder_map; for (i = 0; i < max; i += dec->channels) { for (j = 0; j < dec->channels; j++) *outbuffer++ = (gint16) (dec_data[i + reorder_map[j]]); } } else if (dec->width == 32) { gint32 *outbuffer = (gint32 *) out_data; gint *reorder_map = dec->channel_reorder_map; if (width != depth) { for (i = 0; i < max; i += dec->channels) { for (j = 0; j < dec->channels; j++) *outbuffer++ = (gint32) (dec_data[i + reorder_map[j]] << (width - depth)); } } else { for (i = 0; i < max; i += dec->channels) { for (j = 0; j < dec->channels; j++) *outbuffer++ = (gint32) (dec_data[i + reorder_map[j]]); } } } else { g_assert_not_reached (); } gst_buffer_unmap (outbuf, &omap); gst_buffer_unmap (buf, &map); buf = NULL; g_free (dec_data); ret = gst_audio_decoder_finish_frame (bdec, outbuf, 1); out: if (buf) gst_buffer_unmap (buf, &map); if (G_UNLIKELY (ret != GST_FLOW_OK)) { GST_DEBUG_OBJECT (dec, "flow: %s", gst_flow_get_name (ret)); } return ret; /* ERRORS */ input_not_framed: { GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("Expected framed input")); ret = GST_FLOW_ERROR; goto out; } invalid_header: { GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("Invalid wavpack header")); ret = GST_FLOW_ERROR; goto out; } context_failed: { GST_AUDIO_DECODER_ERROR (bdec, 1, LIBRARY, INIT, (NULL), ("error creating Wavpack context"), ret); goto out; } decode_error: { const gchar *reason = "unknown"; if (dec->context) { reason = WavpackGetErrorMessage (dec->context); } else { reason = "couldn't create decoder context"; } GST_AUDIO_DECODER_ERROR (bdec, 1, STREAM, DECODE, (NULL), ("decoding error: %s", reason), ret); g_free (dec_data); if (ret == GST_FLOW_OK) gst_audio_decoder_finish_frame (bdec, NULL, 1); goto out; } }
/* * This does the main decoding thing. * Requires an already opened WavpackContext. */ static void wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek, struct replay_gain_info *replay_gain_info) { struct audio_format audio_format; format_samples_t format_samples; char chunk[CHUNK_SIZE]; int samples_requested, samples_got; float total_time, current_time; int bytes_per_sample, output_sample_size; int position; audio_format.sample_rate = WavpackGetSampleRate(wpc); audio_format.channels = WavpackGetReducedChannels(wpc); audio_format.bits = WavpackGetBitsPerSample(wpc); /* round bitwidth to 8-bit units */ audio_format.bits = (audio_format.bits + 7) & (~7); /* mpd handles max 24-bit samples */ if (audio_format.bits > 24) { audio_format.bits = 24; } if (!audio_format_valid(&audio_format)) { g_warning("Invalid audio format: %u:%u:%u\n", audio_format.sample_rate, audio_format.bits, audio_format.channels); return; } if ((WavpackGetMode(wpc) & MODE_FLOAT) == MODE_FLOAT) { format_samples = format_samples_float; } else { format_samples = format_samples_int; } total_time = WavpackGetNumSamples(wpc); total_time /= audio_format.sample_rate; bytes_per_sample = WavpackGetBytesPerSample(wpc); output_sample_size = audio_format_frame_size(&audio_format); /* wavpack gives us all kind of samples in a 32-bit space */ samples_requested = sizeof(chunk) / (4 * audio_format.channels); decoder_initialized(decoder, &audio_format, can_seek, total_time); position = 0; do { if (decoder_get_command(decoder) == DECODE_COMMAND_SEEK) { if (can_seek) { int where; where = decoder_seek_where(decoder); where *= audio_format.sample_rate; if (WavpackSeekSample(wpc, where)) { position = where; decoder_command_finished(decoder); } else { decoder_seek_error(decoder); } } else { decoder_seek_error(decoder); } } if (decoder_get_command(decoder) == DECODE_COMMAND_STOP) { break; } samples_got = WavpackUnpackSamples( wpc, (int32_t *)chunk, samples_requested ); if (samples_got > 0) { int bitrate = (int)(WavpackGetInstantBitrate(wpc) / 1000 + 0.5); position += samples_got; current_time = position; current_time /= audio_format.sample_rate; format_samples( bytes_per_sample, chunk, samples_got * audio_format.channels ); decoder_data( decoder, NULL, chunk, samples_got * output_sample_size, current_time, bitrate, replay_gain_info ); } } while (samples_got > 0); }
static gboolean wv_play (InputPlayback * playback, const gchar * filename, VFSFile * file, gint start_time, gint stop_time, gboolean pause) { if (file == NULL) return FALSE; gint32 *input = NULL; void *output = NULL; gint sample_rate, num_channels, bits_per_sample; guint num_samples; WavpackContext *ctx = NULL; VFSFile *wvc_input = NULL; gboolean error = FALSE; if (! wv_attach (filename, file, & wvc_input, & ctx, NULL, OPEN_TAGS | OPEN_WVC)) { g_warning("Error opening Wavpack file '%s'.", filename); error = TRUE; goto error_exit; } sample_rate = WavpackGetSampleRate(ctx); num_channels = WavpackGetNumChannels(ctx); bits_per_sample = WavpackGetBitsPerSample(ctx); num_samples = WavpackGetNumSamples(ctx); if (!playback->output->open_audio(SAMPLE_FMT(bits_per_sample), sample_rate, num_channels)) { g_warning("Error opening audio output."); error = TRUE; goto error_exit; } if (pause) playback->output->pause(TRUE); input = g_malloc(BUFFER_SIZE * num_channels * sizeof(guint32)); output = g_malloc(BUFFER_SIZE * num_channels * SAMPLE_SIZE(bits_per_sample)); if (input == NULL || output == NULL) goto error_exit; playback->set_gain_from_playlist(playback); g_mutex_lock(ctrl_mutex); playback->set_params(playback, (gint) WavpackGetAverageBitrate(ctx, num_channels), sample_rate, num_channels); seek_value = (start_time > 0) ? start_time : -1; stop_flag = FALSE; playback->set_pb_ready(playback); g_mutex_unlock(ctrl_mutex); while (!stop_flag && (stop_time < 0 || playback->output->written_time () < stop_time)) { gint ret; guint samples_left; /* Handle seek and pause requests */ g_mutex_lock(ctrl_mutex); if (seek_value >= 0) { playback->output->flush (seek_value); WavpackSeekSample (ctx, (gint64) seek_value * sample_rate / 1000); seek_value = -1; g_cond_signal(ctrl_cond); } g_mutex_unlock(ctrl_mutex); /* Decode audio data */ samples_left = num_samples - WavpackGetSampleIndex(ctx); ret = WavpackUnpackSamples(ctx, input, BUFFER_SIZE); if (samples_left == 0) stop_flag = TRUE; else if (ret < 0) { g_warning("Error decoding file.\n"); break; } else { /* Perform audio data conversion and output */ guint i; gint32 *rp = input; gint8 *wp = output; gint16 *wp2 = output; gint32 *wp4 = output; if (bits_per_sample == 8) { for (i = 0; i < ret * num_channels; i++, wp++, rp++) *wp = *rp & 0xff; } else if (bits_per_sample == 16) { for (i = 0; i < ret * num_channels; i++, wp2++, rp++) *wp2 = *rp & 0xffff; } else if (bits_per_sample == 24 || bits_per_sample == 32) { for (i = 0; i < ret * num_channels; i++, wp4++, rp++) *wp4 = *rp; } playback->output->write_audio(output, ret * num_channels * SAMPLE_SIZE(bits_per_sample)); } } /* Flush buffer */ g_mutex_lock(ctrl_mutex); while (!stop_flag && playback->output->buffer_playing()) g_usleep(20000); g_cond_signal(ctrl_cond); g_mutex_unlock(ctrl_mutex); error_exit: g_free(input); g_free(output); wv_deattach (wvc_input, ctx); stop_flag = TRUE; playback->output->close_audio(); return ! error; }
static GstFlowReturn gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buf) { GstWavpackDec *dec; GstBuffer *outbuf; GstFlowReturn ret = GST_FLOW_OK; WavpackHeader wph; int32_t decoded, unpacked_size; gboolean format_changed; dec = GST_WAVPACK_DEC (GST_PAD_PARENT (pad)); /* check input, we only accept framed input with complete chunks */ if (GST_BUFFER_SIZE (buf) < sizeof (WavpackHeader)) goto input_not_framed; if (!gst_wavpack_read_header (&wph, GST_BUFFER_DATA (buf))) goto invalid_header; if (GST_BUFFER_SIZE (buf) < wph.ckSize + 4 * 1 + 4) goto input_not_framed; if (!(wph.flags & INITIAL_BLOCK)) goto input_not_framed; dec->wv_id.buffer = GST_BUFFER_DATA (buf); dec->wv_id.length = GST_BUFFER_SIZE (buf); dec->wv_id.position = 0; /* create a new wavpack context if there is none yet but if there * was already one (i.e. caps were set on the srcpad) check whether * the new one has the same caps */ if (!dec->context) { gchar error_msg[80]; dec->context = WavpackOpenFileInputEx (dec->stream_reader, &dec->wv_id, NULL, error_msg, OPEN_STREAMING, 0); if (!dec->context) { GST_WARNING ("Couldn't decode buffer: %s", error_msg); dec->error_count++; if (dec->error_count <= WAVPACK_DEC_MAX_ERRORS) { goto out; /* just return OK for now */ } else { goto decode_error; } } } g_assert (dec->context != NULL); dec->error_count = 0; format_changed = (dec->sample_rate != WavpackGetSampleRate (dec->context)) || (dec->channels != WavpackGetNumChannels (dec->context)) || (dec->depth != WavpackGetBitsPerSample (dec->context)) || #ifdef WAVPACK_OLD_API (dec->channel_mask != dec->context->config.channel_mask); #else (dec->channel_mask != WavpackGetChannelMask (dec->context)); #endif if (!GST_PAD_CAPS (dec->srcpad) || format_changed) { GstCaps *caps; gint channel_mask; dec->sample_rate = WavpackGetSampleRate (dec->context); dec->channels = WavpackGetNumChannels (dec->context); dec->depth = WavpackGetBitsPerSample (dec->context); caps = gst_caps_new_simple ("audio/x-raw-int", "rate", G_TYPE_INT, dec->sample_rate, "channels", G_TYPE_INT, dec->channels, "depth", G_TYPE_INT, dec->depth, "width", G_TYPE_INT, 32, "endianness", G_TYPE_INT, G_BYTE_ORDER, "signed", G_TYPE_BOOLEAN, TRUE, NULL); #ifdef WAVPACK_OLD_API channel_mask = dec->context->config.channel_mask; #else channel_mask = WavpackGetChannelMask (dec->context); #endif if (channel_mask == 0) channel_mask = gst_wavpack_get_default_channel_mask (dec->channels); dec->channel_mask = channel_mask; /* Only set the channel layout for more than two channels * otherwise things break unfortunately */ if (channel_mask != 0 && dec->channels > 2) if (!gst_wavpack_set_channel_layout (caps, channel_mask)) GST_WARNING_OBJECT (dec, "Failed to set channel layout"); GST_DEBUG_OBJECT (dec, "setting caps %" GST_PTR_FORMAT, caps); /* should always succeed */ gst_pad_set_caps (dec->srcpad, caps); gst_caps_unref (caps); /* send GST_TAG_AUDIO_CODEC and GST_TAG_BITRATE tags before something * is decoded or after the format has changed */ gst_wavpack_dec_post_tags (dec); } /* alloc output buffer */ unpacked_size = 4 * wph.block_samples * dec->channels; ret = gst_pad_alloc_buffer (dec->srcpad, GST_BUFFER_OFFSET (buf), unpacked_size, GST_PAD_CAPS (dec->srcpad), &outbuf); if (ret != GST_FLOW_OK) goto out; gst_buffer_copy_metadata (outbuf, buf, GST_BUFFER_COPY_TIMESTAMPS); /* If we got a DISCONT buffer forward the flag. Nothing else * has to be done as libwavpack doesn't store state between * Wavpack blocks */ if (GST_BUFFER_IS_DISCONT (buf) || dec->next_block_index != wph.block_index) GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); dec->next_block_index = wph.block_index + wph.block_samples; /* decode */ decoded = WavpackUnpackSamples (dec->context, (int32_t *) GST_BUFFER_DATA (outbuf), wph.block_samples); if (decoded != wph.block_samples) goto decode_error; if ((outbuf = gst_audio_buffer_clip (outbuf, &dec->segment, dec->sample_rate, 4 * dec->channels))) { GST_LOG_OBJECT (dec, "pushing buffer with time %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf))); ret = gst_pad_push (dec->srcpad, outbuf); } out: if (G_UNLIKELY (ret != GST_FLOW_OK)) { GST_DEBUG_OBJECT (dec, "flow: %s", gst_flow_get_name (ret)); } gst_buffer_unref (buf); return ret; /* ERRORS */ input_not_framed: { GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("Expected framed input")); gst_buffer_unref (buf); return GST_FLOW_ERROR; } invalid_header: { GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("Invalid wavpack header")); gst_buffer_unref (buf); return GST_FLOW_ERROR; } decode_error: { const gchar *reason = "unknown"; if (dec->context) { #ifdef WAVPACK_OLD_API reason = dec->context->error_message; #else reason = WavpackGetErrorMessage (dec->context); #endif } else { reason = "couldn't create decoder context"; } GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("Failed to decode wavpack stream: %s", reason)); gst_buffer_unref (outbuf); gst_buffer_unref (buf); return GST_FLOW_ERROR; } }