void wavpack_buffer_format_samples(wavpack_buffer_decoder* wbd, uchar *dst, long *src, uint32_t samples) { long temp; int bps = WavpackGetBytesPerSample(wbd->wpc); uint32_t samcnt = samples * WavpackGetNumChannels (wbd->wpc); switch (bps) { case 1: while (samcnt--) *dst++ = (uchar)(*src++ + 128); break; case 2: while (samcnt--) { *dst++ = (uchar)(temp = *src++); *dst++ = (uchar)(temp >> 8); } break; case 3: while (samcnt--) { *dst++ = (uchar)(temp = *src++); *dst++ = (uchar)(temp >> 8); *dst++ = (uchar)(temp >> 16); } break; } }
soundfile_t * soundfile_open_read(const char *path) { dp(30, "path=%s \n", path); soundfile_t *s = salloc(sizeof *s); s->m = sft_read; if (g_regex_match_simple ("\\.wv$", path, 0, 0)) { char error[80] = {0}; int flags = 0; int norm_offset = 0; s->t = sft_wavpack; s->p = WavpackOpenFileInput(path, error, flags, norm_offset); if (!s->p) die("can not open input file '%s'", path); s->bits_per_sample = WavpackGetBitsPerSample(s->p); s->channels = WavpackGetNumChannels(s->p); s->samplerate = WavpackGetSampleRate(s->p); s->frames = WavpackGetNumSamples(s->p); } else { SF_INFO infile_info = {0}; if (strcmp(path, "-")) s->p = sf_open(path, SFM_READ, &infile_info); else s->p = sf_open_fd(0, SFM_READ, &infile_info, 0); if (!s->p) die("can not open input file '%s'", path); s->t = sft_libsndfile; s->channels = infile_info.channels; s->samplerate = infile_info.samplerate; s->frames = infile_info.frames; } return s; }
static void wv_get_song_info(char *filename, char **title, int *length) { assert(filename != NULL); char error_buff[80]; WavpackContext *ctx = WavpackOpenFileInput(filename, error_buff, OPEN_TAGS | OPEN_WVC, 0); if (ctx == NULL) { printf("wavpack: Error opening file: \"%s: %s\"\n", filename, error_buff); return; } int sample_rate = WavpackGetSampleRate(ctx); int num_channels = WavpackGetNumChannels(ctx); DBG("reading %s at %d rate with %d channels\n", filename, sample_rate, num_channels); *length = (int)(WavpackGetNumSamples(ctx) / sample_rate) * 1000, *title = generate_title(filename, ctx); DBG("title for %s = %s\n", filename, *title); WavpackCloseFile(ctx); }
void wavpack_buffer_format_samples(wavpack_buffer_decoder* wbd, uchar *dst, long *src, uint32_t samples, int float32_output) { long temp; int bps = WavpackGetBytesPerSample(wbd->wpc); uint32_t samcnt = samples * WavpackGetNumChannels (wbd->wpc); switch (bps) { case 1: while (samcnt--) *dst++ = (uchar)(*src++ + 128); break; case 2: while (samcnt--) { *dst++ = (uchar)(temp = *src++); *dst++ = (uchar)(temp >> 8); } break; case 3: while (samcnt--) { *dst++ = (uchar)(temp = *src++); *dst++ = (uchar)(temp >> 8); *dst++ = (uchar)(temp >> 16); } break; case 4: if (float32_output && !(WavpackGetMode (wbd->wpc) & MODE_FLOAT)) { float *fdst = (float *) dst; while (samcnt--) *fdst++ = *src++ * 4.656612873077393e-10F; } break; } }
bool attach(const char *filename) { ctx = WavpackOpenFileInput(filename, error_buff, OPEN_TAGS | OPEN_WVC | OPEN_NORMALIZE, 0); if (ctx == NULL) { return false; } sample_rate = WavpackGetSampleRate(ctx); num_channels = WavpackGetNumChannels(ctx); bytes_per_sample = WavpackGetBytesPerSample(ctx); input = (int32_t *)calloc(BUFFER_SIZE, num_channels * sizeof(int32_t)); output = (int16_t *)calloc(BUFFER_SIZE, num_channels * sizeof(int16_t)); memset (shaping_error, 0, sizeof (shaping_error)); mod->set_info(generate_title(filename, ctx), (int) (WavpackGetNumSamples(ctx) / sample_rate) * 1000, (int) WavpackGetAverageBitrate(ctx, true), (int) sample_rate, num_channels); play_gain = calculate_gain (ctx); DBG("gain value = %g\n", play_gain); return true; }
gboolean Wavpack_Header_Read_File_Info(gchar *filename, ET_File_Info *ETFileInfo) { WavpackContext *wpc; wpc = WavpackOpenFileInput(filename, NULL, 0, 0); if ( wpc == NULL ) { return FALSE; } ETFileInfo->version = WavpackGetVersion(wpc); /* .wvc correction file not counted */ ETFileInfo->bitrate = WavpackGetAverageBitrate(wpc, 0)/1000; ETFileInfo->samplerate = WavpackGetSampleRate(wpc); ETFileInfo->mode = WavpackGetNumChannels(wpc); ETFileInfo->size = WavpackGetFileSize(wpc); ETFileInfo->duration = WavpackGetNumSamples(wpc)/ETFileInfo->samplerate; WavpackCloseFile(wpc); return TRUE; }
EmErrorCode WvDecoder::Open(const std::string& url) { m_Ctx = WavpackOpenFileInput(url.c_str(), nullptr, 0, 0); if (m_Ctx == nullptr) return ErrorCode::DecoderFailedToOpen; if (WavpackGetNumSamples(m_Ctx) == (uint32_t) -1) return ErrorCode::DecoderFailedToInit; m_Duration = (double)WavpackGetNumSamples(m_Ctx) / WavpackGetSampleRate(m_Ctx) * 1000; m_Channels = WavpackGetNumChannels(m_Ctx); m_SampleRate = WavpackGetSampleRate(m_Ctx); m_BitsPerSample = WavpackGetBitsPerSample(m_Ctx); m_BytesPerSample = WavpackGetBytesPerSample(m_Ctx); // one sample may not be enough to build a full channel m_UnitCount = WavpackGetNumSamples(m_Ctx)/m_Channels; m_UnitIndex = 0; m_Buf.resize(10 * m_Channels * sizeof(int32_t)); // 1~10 full-samples return ErrorCode::Ok; }
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; }
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; } }
static DB_playItem_t * wv_insert (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname) { DB_FILE *fp = deadbeef->fopen (fname); if (!fp) { return NULL; } char error[80]; #ifdef TINYWV WavpackContext *ctx = WavpackOpenFileInput (wv_read_stream, fp, error); #else WavpackContext *ctx = WavpackOpenFileInputEx (&wsr, fp, NULL, error, 0, 0); #endif if (!ctx) { fprintf (stderr, "wavpack error: %s\n", error); deadbeef->fclose (fp); return NULL; } int totalsamples = WavpackGetNumSamples (ctx); int samplerate = WavpackGetSampleRate (ctx); float duration = (float)totalsamples / samplerate; DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id); deadbeef->pl_add_meta (it, ":FILETYPE", "wv"); deadbeef->plt_set_item_duration (plt, it, duration); trace ("wv: totalsamples=%d, samplerate=%d, duration=%f\n", totalsamples, samplerate, duration); #if 0 int num = WavpackGetNumTagItems (ctx); trace ("num tag items: %d\n", num); for (int i = 0; i < num; i++) { char str[1024]; WavpackGetTagItemIndexed (ctx, i, str, sizeof (str)); trace ("tag item: %s\n", str); } #endif int apeerr = deadbeef->junk_apev2_read (it, fp); if (!apeerr) { trace ("wv: ape tag found\n"); } int v1err = deadbeef->junk_id3v1_read (it, fp); if (!v1err) { trace ("wv: id3v1 tag found\n"); } deadbeef->pl_add_meta (it, "title", NULL); char s[100]; snprintf (s, sizeof (s), "%lld", deadbeef->fgetlength (fp)); deadbeef->pl_add_meta (it, ":FILE_SIZE", s); snprintf (s, sizeof (s), "%d", WavpackGetBytesPerSample (ctx) * 8); deadbeef->pl_add_meta (it, ":BPS", s); snprintf (s, sizeof (s), "%d", WavpackGetNumChannels (ctx)); deadbeef->pl_add_meta (it, ":CHANNELS", s); snprintf (s, sizeof (s), "%d", WavpackGetSampleRate (ctx)); deadbeef->pl_add_meta (it, ":SAMPLERATE", s); snprintf (s, sizeof (s), "%d", (int)(WavpackGetAverageBitrate (ctx, 1) / 1000)); deadbeef->pl_add_meta (it, ":BITRATE", s); snprintf (s, sizeof (s), "%s", (WavpackGetMode (ctx) & MODE_FLOAT) ? "FLOAT" : "INTEGER"); deadbeef->pl_add_meta (it, ":WAVPACK_MODE", s); // embedded cue deadbeef->pl_lock (); const char *cuesheet = deadbeef->pl_find_meta (it, "cuesheet"); if (cuesheet) { trace ("found cuesheet: %s\n", cuesheet); DB_playItem_t *last = deadbeef->plt_insert_cue_from_buffer (plt, after, it, cuesheet, strlen (cuesheet), totalsamples, samplerate); if (last) { deadbeef->pl_unlock (); deadbeef->fclose (fp); WavpackCloseFile (ctx); deadbeef->pl_item_unref (it); deadbeef->pl_item_unref (last); return last; } } deadbeef->pl_unlock (); // cue file on disc DB_playItem_t *cue_after = deadbeef->plt_insert_cue (plt, after, it, totalsamples, samplerate); if (cue_after) { deadbeef->fclose (fp); WavpackCloseFile (ctx); deadbeef->pl_item_unref (it); deadbeef->pl_item_unref (cue_after); return cue_after; } after = deadbeef->plt_insert_item (plt, after, it); deadbeef->pl_item_unref (it); deadbeef->fclose (fp); WavpackCloseFile (ctx); return after; }
static int wv_init (DB_fileinfo_t *_info, DB_playItem_t *it) { wvctx_t *info = (wvctx_t *)_info; deadbeef->pl_lock (); info->file = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI")); deadbeef->pl_unlock (); if (!info->file) { return -1; } #ifndef TINYWV deadbeef->pl_lock (); const char *uri = deadbeef->pl_find_meta (it, ":URI"); char *c_fname = alloca (strlen (uri) + 2); if (c_fname) { strcpy (c_fname, uri); strcat (c_fname, "c"); info->c_file = deadbeef->fopen (c_fname); } else { fprintf (stderr, "wavpack warning: failed to alloc memory for correction file name\n"); } deadbeef->pl_unlock (); #endif char error[80]; #ifdef TINYWV info->ctx = WavpackOpenFileInput (wv_read_stream, info->file, error); #else info->ctx = WavpackOpenFileInputEx (&wsr, info->file, info->c_file, error, OPEN_NORMALIZE, 0); #endif if (!info->ctx) { fprintf (stderr, "wavpack error: %s\n", error); return -1; } _info->plugin = &plugin; _info->fmt.bps = WavpackGetBytesPerSample (info->ctx) * 8; _info->fmt.channels = WavpackGetNumChannels (info->ctx); _info->fmt.samplerate = WavpackGetSampleRate (info->ctx); _info->fmt.is_float = (WavpackGetMode (info->ctx) & MODE_FLOAT) ? 1 : 0; // FIXME: streamer and maybe output plugins need to be fixed to support // arbitrary channelmask // _info->fmt.channelmask = WavpackGetChannelMask (info->ctx); for (int i = 0; i < _info->fmt.channels; i++) { _info->fmt.channelmask |= 1 << i; } _info->readpos = 0; if (it->endsample > 0) { info->startsample = it->startsample; info->endsample = it->endsample; if (plugin.seek_sample (_info, 0) < 0) { return -1; } } else { info->startsample = 0; info->endsample = WavpackGetNumSamples (info->ctx)-1; } return 0; }
static gboolean xmms_wavpack_init (xmms_xform_t *xform) { xmms_wavpack_data_t *data; xmms_sample_format_t sample_format; gint samplerate; /* the maximum length of error really isn't defined... stupid */ gchar error[1024]; g_return_val_if_fail (xform, FALSE); if (!xmms_apetag_read (xform)) { XMMS_DBG ("Failed to read APEv2 tag"); } data = g_new0 (xmms_wavpack_data_t, 1); g_return_val_if_fail (data, FALSE); xmms_xform_private_data_set (xform, data); data->reader.read_bytes = wavpack_read_bytes; data->reader.get_pos = wavpack_get_pos; data->reader.set_pos_abs = wavpack_set_pos_abs; data->reader.set_pos_rel = wavpack_set_pos_rel; data->reader.push_back_byte = wavpack_push_back_byte; data->reader.get_length = wavpack_get_length; data->reader.can_seek = wavpack_can_seek; data->ctx = WavpackOpenFileInputEx (&data->reader, xform, xform, error, OPEN_TAGS, 0); if (!data->ctx) { xmms_log_error ("Unable to open wavpack file: %s", error); xmms_xform_private_data_set (xform, NULL); xmms_wavpack_free_data (data); return FALSE; } data->channels = WavpackGetNumChannels (data->ctx); data->bits_per_sample = WavpackGetBitsPerSample (data->ctx); data->num_samples = WavpackGetNumSamples (data->ctx); samplerate = WavpackGetSampleRate (data->ctx); xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION, (int) (1000.0 * data->num_samples / samplerate)); xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_SAMPLERATE, samplerate); xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE, (int) WavpackGetAverageBitrate (data->ctx, FALSE)); switch (data->bits_per_sample) { case 8: sample_format = XMMS_SAMPLE_FORMAT_S8; break; case 12: case 16: sample_format = XMMS_SAMPLE_FORMAT_S16; break; case 24: case 32: sample_format = XMMS_SAMPLE_FORMAT_S32; break; default: xmms_log_error ("Unsupported bits-per-sample in wavpack file: %d", data->bits_per_sample); xmms_xform_private_data_set (xform, NULL); xmms_wavpack_free_data (data); return FALSE; } xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, sample_format, XMMS_STREAM_TYPE_FMT_CHANNELS, data->channels, XMMS_STREAM_TYPE_FMT_SAMPLERATE, samplerate, XMMS_STREAM_TYPE_END); return TRUE; }
bool WavPackDecoder::Open(CFErrorRef *error) { if(IsOpen()) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger("org.sbooth.AudioEngine.AudioDecoder.WavPack"); LOG4CXX_WARN(logger, "Open() called on an AudioDecoder that is already open"); return true; } // Ensure the input source is open if(!mInputSource->IsOpen() && !mInputSource->Open(error)) return false; mStreamReader.read_bytes = read_bytes_callback; mStreamReader.get_pos = get_pos_callback; mStreamReader.set_pos_abs = set_pos_abs_callback; mStreamReader.set_pos_rel = set_pos_rel_callback; mStreamReader.push_back_byte = push_back_byte_callback; mStreamReader.get_length = get_length_callback; mStreamReader.can_seek = can_seek_callback; char errorBuf [80]; // Setup converter mWPC = WavpackOpenFileInputEx(&mStreamReader, this, NULL, errorBuf, OPEN_WVC | OPEN_NORMALIZE, 0); if(NULL == mWPC) { if(error) { CFMutableDictionaryRef errorDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 32, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFStringRef displayName = CreateDisplayNameForURL(mInputSource->GetURL()); CFStringRef errorString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFCopyLocalizedString(CFSTR("The file “%@” is not a valid WavPack file."), ""), displayName); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedDescriptionKey, errorString); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedFailureReasonKey, CFCopyLocalizedString(CFSTR("Not a WavPack file"), "")); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedRecoverySuggestionKey, CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); CFRelease(errorString), errorString = NULL; CFRelease(displayName), displayName = NULL; *error = CFErrorCreate(kCFAllocatorDefault, AudioDecoderErrorDomain, AudioDecoderInputOutputError, errorDictionary); CFRelease(errorDictionary), errorDictionary = NULL; } return false; } // Floating-point and lossy files will be handed off in the canonical Core Audio format int mode = WavpackGetMode(mWPC); if(MODE_FLOAT & mode || !(MODE_LOSSLESS & mode)) { // Canonical Core Audio format mFormat.mFormatID = kAudioFormatLinearPCM; mFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved; mFormat.mSampleRate = WavpackGetSampleRate(mWPC); mFormat.mChannelsPerFrame = WavpackGetNumChannels(mWPC); mFormat.mBitsPerChannel = 8 * sizeof(float); mFormat.mBytesPerPacket = (mFormat.mBitsPerChannel / 8); mFormat.mFramesPerPacket = 1; mFormat.mBytesPerFrame = mFormat.mBytesPerPacket * mFormat.mFramesPerPacket; mFormat.mReserved = 0; } else { mFormat.mFormatID = kAudioFormatLinearPCM; mFormat.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsAlignedHigh | kAudioFormatFlagIsNonInterleaved; mFormat.mSampleRate = WavpackGetSampleRate(mWPC); mFormat.mChannelsPerFrame = WavpackGetNumChannels(mWPC); mFormat.mBitsPerChannel = WavpackGetBitsPerSample(mWPC); mFormat.mBytesPerPacket = sizeof(int32_t); mFormat.mFramesPerPacket = 1; mFormat.mBytesPerFrame = mFormat.mBytesPerPacket * mFormat.mFramesPerPacket; mFormat.mReserved = 0; } mTotalFrames = WavpackGetNumSamples(mWPC); // Set up the source format mSourceFormat.mFormatID = 'WVPK'; mSourceFormat.mSampleRate = WavpackGetSampleRate(mWPC); mSourceFormat.mChannelsPerFrame = WavpackGetNumChannels(mWPC); mSourceFormat.mBitsPerChannel = WavpackGetBitsPerSample(mWPC); // Setup the channel layout switch(mFormat.mChannelsPerFrame) { case 1: mChannelLayout = CreateChannelLayoutWithTag(kAudioChannelLayoutTag_Mono); break; case 2: mChannelLayout = CreateChannelLayoutWithTag(kAudioChannelLayoutTag_Stereo); break; case 4: mChannelLayout = CreateChannelLayoutWithTag(kAudioChannelLayoutTag_Quadraphonic); break; } mBuffer = static_cast<int32_t *>(calloc(BUFFER_SIZE_FRAMES * mFormat.mChannelsPerFrame, sizeof(int32_t))); if(NULL == mBuffer) { if(error) *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX, ENOMEM, NULL); return false; } mIsOpen = true; return true; }
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; } }
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; }
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; }
HRESULT CWavPackDSDecoder::Receive(IMediaSample *pSample) { // Check for other streams and pass them on AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); if ((pProps->dwStreamId != AM_STREAM_MEDIA) && (pProps->dwStreamId != AM_STREAM_BLOCK_ADDITIONNAL)) { return m_pOutput->Deliver(pSample); } ASSERT(pSample); // If no output to deliver to then no point sending us data ASSERT(m_pOutput != NULL); HRESULT hr = S_OK; BYTE *pSrc, *pDst; DWORD SrcLength = pSample->GetActualDataLength(); hr = pSample->GetPointer(&pSrc); if(FAILED(hr)) return hr; // Check for minimal block size if(SrcLength < (3 * sizeof(uint32_t))) { return S_OK; } WAVEFORMATEX* pwfx = (WAVEFORMATEX*)m_pInput->CurrentMediaType().Format(); BOOL bSeveralBlocks = (pwfx->nChannels > 2); if(pProps->dwStreamId == AM_STREAM_MEDIA) { REFERENCE_TIME rtStop; if(pSample->IsSyncPoint() == S_OK) { pSample->GetTime(&m_rtFrameStart, &rtStop); m_TotalSamples = 0; } m_MainBlockDiscontinuity = (pSample->IsDiscontinuity() == S_OK); reconstruct_wavpack_frame( m_MainFrame, &m_CommonFrameData, (char*)pSrc, SrcLength, TRUE, bSeveralBlocks, m_PrivateData.version); if(m_HybridMode == TRUE) { // Stop here and wait for correction data return S_OK; } } if((m_HybridMode == TRUE) && (pProps->dwStreamId == AM_STREAM_BLOCK_ADDITIONNAL)) { // rebuild correction data block reconstruct_wavpack_frame( m_CorrectionFrame, &m_CommonFrameData, (char*)pSrc, SrcLength, FALSE, bSeveralBlocks, m_PrivateData.version); } if(wavpack_buffer_decoder_load_frame(m_Codec, m_MainFrame->data, m_MainFrame->len, m_HybridMode ? m_CorrectionFrame->data : NULL, m_CorrectionFrame->len) == 0) { // Something is wrong return S_FALSE; } // We can precise the decoding mode now if(m_HybridMode == FALSE) { if(m_CommonFrameData.array_flags[0] & WV_HYBRID_FLAG) { m_DecodingMode = DECODING_MODE_LOSSY; } else { m_DecodingMode = DECODING_MODE_LOSSLESS; } } uint32_t samplesLeft = m_CommonFrameData.block_samples; while(samplesLeft > 0) { // Set up the output sample IMediaSample *pOutSample; hr = InitializeOutputSample(pSample, &pOutSample); if(FAILED(hr)) { break; } DWORD DstLength = pOutSample->GetSize(); hr = pOutSample->GetPointer(&pDst); if(FAILED(hr)) { pOutSample->Release(); break; } DstLength &= 0xFFFFFFF8; long samples = wavpack_buffer_decoder_unpack(m_Codec,(int32_t *)pDst, m_SamplesPerBuffer); if(samples) { wavpack_buffer_format_samples(m_Codec, (uchar *) pDst, (long*) pDst, samples); DstLength = samples * WavpackGetBytesPerSample(m_Codec->wpc) * WavpackGetNumChannels (m_Codec->wpc); pOutSample->SetActualDataLength(DstLength); REFERENCE_TIME rtStart, rtStop; rtStart = m_rtFrameStart + (REFERENCE_TIME)(((double)m_TotalSamples / WavpackGetSampleRate(m_Codec->wpc)) * 10000000); m_TotalSamples += samples; rtStop = m_rtFrameStart + (REFERENCE_TIME)(((double)m_TotalSamples / WavpackGetSampleRate(m_Codec->wpc)) * 10000000); if(rtStart < 0 && rtStop < 0) { // No need to deliver this sample it will be skipped pOutSample->Release(); continue; } pOutSample->SetTime(&rtStart, &rtStop); pOutSample->SetSyncPoint(TRUE); pOutSample->SetDiscontinuity(m_MainBlockDiscontinuity); if(m_MainBlockDiscontinuity == TRUE) { m_MainBlockDiscontinuity = FALSE; } hr = m_pOutput->Deliver(pOutSample); if(FAILED(hr)) { pOutSample->Release(); break; } pOutSample->Release(); } else { pOutSample->Release(); break; } samplesLeft -= samples; } m_DecodedFrames++; m_CrcError = WavpackGetNumErrors(m_Codec->wpc); return S_OK; }
/* * 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 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; }
bool WavPackDecoder::Open(CFErrorRef *error) { if(IsOpen()) { LOGGER_WARNING("org.sbooth.AudioEngine.AudioDecoder.WavPack", "Open() called on an AudioDecoder that is already open"); return true; } // Ensure the input source is open if(!mInputSource->IsOpen() && !mInputSource->Open(error)) return false; mStreamReader.read_bytes = read_bytes_callback; mStreamReader.get_pos = get_pos_callback; mStreamReader.set_pos_abs = set_pos_abs_callback; mStreamReader.set_pos_rel = set_pos_rel_callback; mStreamReader.push_back_byte = push_back_byte_callback; mStreamReader.get_length = get_length_callback; mStreamReader.can_seek = can_seek_callback; char errorBuf [80]; // Setup converter mWPC = WavpackOpenFileInputEx(&mStreamReader, this, nullptr, errorBuf, OPEN_WVC | OPEN_NORMALIZE, 0); if(nullptr == mWPC) { if(error) { CFStringRef description = CFCopyLocalizedString(CFSTR("The file “%@” is not a valid WavPack file."), ""); CFStringRef failureReason = CFCopyLocalizedString(CFSTR("Not a WavPack file"), ""); CFStringRef recoverySuggestion = CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), ""); *error = CreateErrorForURL(AudioDecoderErrorDomain, AudioDecoderInputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); CFRelease(description), description = nullptr; CFRelease(failureReason), failureReason = nullptr; CFRelease(recoverySuggestion), recoverySuggestion = nullptr; } return false; } // Floating-point and lossy files will be handed off in the canonical Core Audio format int mode = WavpackGetMode(mWPC); if(MODE_FLOAT & mode || !(MODE_LOSSLESS & mode)) { // Canonical Core Audio format mFormat.mFormatID = kAudioFormatLinearPCM; mFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved; mFormat.mSampleRate = WavpackGetSampleRate(mWPC); mFormat.mChannelsPerFrame = WavpackGetNumChannels(mWPC); mFormat.mBitsPerChannel = 8 * sizeof(float); mFormat.mBytesPerPacket = (mFormat.mBitsPerChannel / 8); mFormat.mFramesPerPacket = 1; mFormat.mBytesPerFrame = mFormat.mBytesPerPacket * mFormat.mFramesPerPacket; mFormat.mReserved = 0; } else { mFormat.mFormatID = kAudioFormatLinearPCM; mFormat.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsNonInterleaved; // Don't set kAudioFormatFlagIsAlignedHigh for 32-bit integer files mFormat.mFormatFlags |= (32 == WavpackGetBitsPerSample(mWPC) ? kAudioFormatFlagIsPacked : kAudioFormatFlagIsAlignedHigh); mFormat.mSampleRate = WavpackGetSampleRate(mWPC); mFormat.mChannelsPerFrame = WavpackGetNumChannels(mWPC); mFormat.mBitsPerChannel = WavpackGetBitsPerSample(mWPC); mFormat.mBytesPerPacket = sizeof(int32_t); mFormat.mFramesPerPacket = 1; mFormat.mBytesPerFrame = mFormat.mBytesPerPacket * mFormat.mFramesPerPacket; mFormat.mReserved = 0; } mTotalFrames = WavpackGetNumSamples(mWPC); // Set up the source format mSourceFormat.mFormatID = 'WVPK'; mSourceFormat.mSampleRate = WavpackGetSampleRate(mWPC); mSourceFormat.mChannelsPerFrame = WavpackGetNumChannels(mWPC); mSourceFormat.mBitsPerChannel = WavpackGetBitsPerSample(mWPC); // Setup the channel layout switch(mFormat.mChannelsPerFrame) { case 1: mChannelLayout = CreateChannelLayoutWithTag(kAudioChannelLayoutTag_Mono); break; case 2: mChannelLayout = CreateChannelLayoutWithTag(kAudioChannelLayoutTag_Stereo); break; case 4: mChannelLayout = CreateChannelLayoutWithTag(kAudioChannelLayoutTag_Quadraphonic); break; } mBuffer = static_cast<int32_t *>(calloc(BUFFER_SIZE_FRAMES * mFormat.mChannelsPerFrame, sizeof(int32_t))); if(nullptr == mBuffer) { if(error) *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX, ENOMEM, nullptr); return false; } mIsOpen = true; return true; }
static gboolean gst_wavpack_parse_create_src_pad (GstWavpackParse * wvparse, GstBuffer * buf, WavpackHeader * header) { GstWavpackMetadata meta; GstCaps *caps = NULL; guchar *bufptr; g_assert (wvparse->srcpad == NULL); bufptr = GST_BUFFER_DATA (buf) + sizeof (WavpackHeader); while (gst_wavpack_read_metadata (&meta, GST_BUFFER_DATA (buf), &bufptr)) { switch (meta.id) { case ID_WVC_BITSTREAM:{ caps = gst_caps_new_simple ("audio/x-wavpack-correction", "framed", G_TYPE_BOOLEAN, TRUE, NULL); wvparse->srcpad = gst_pad_new_from_template (gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (wvparse), "wvcsrc"), "wvcsrc"); break; } case ID_WV_BITSTREAM: case ID_WVX_BITSTREAM:{ WavpackStreamReader *stream_reader = gst_wavpack_stream_reader_new (); WavpackContext *wpc; gchar error_msg[80]; read_id rid; gint channel_mask; rid.buffer = GST_BUFFER_DATA (buf); rid.length = GST_BUFFER_SIZE (buf); rid.position = 0; wpc = WavpackOpenFileInputEx (stream_reader, &rid, NULL, error_msg, 0, 0); if (!wpc) return FALSE; wvparse->samplerate = WavpackGetSampleRate (wpc); wvparse->channels = WavpackGetNumChannels (wpc); wvparse->total_samples = (header->total_samples == 0xffffffff) ? G_GINT64_CONSTANT (-1) : header->total_samples; caps = gst_caps_new_simple ("audio/x-wavpack", "width", G_TYPE_INT, WavpackGetBitsPerSample (wpc), "channels", G_TYPE_INT, wvparse->channels, "rate", G_TYPE_INT, wvparse->samplerate, "framed", G_TYPE_BOOLEAN, TRUE, NULL); #ifdef WAVPACK_OLD_API channel_mask = wpc->config.channel_mask; #else channel_mask = WavpackGetChannelMask (wpc); #endif if (channel_mask == 0) channel_mask = gst_wavpack_get_default_channel_mask (wvparse->channels); if (channel_mask != 0) { if (!gst_wavpack_set_channel_layout (caps, channel_mask)) { GST_WARNING_OBJECT (wvparse, "Failed to set channel layout"); gst_caps_unref (caps); caps = NULL; WavpackCloseFile (wpc); g_free (stream_reader); break; } } wvparse->srcpad = gst_pad_new_from_template (gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (wvparse), "src"), "src"); WavpackCloseFile (wpc); g_free (stream_reader); break; } default:{ GST_LOG_OBJECT (wvparse, "unhandled ID: 0x%02x", meta.id); break; } } if (caps != NULL) break; } if (caps == NULL || wvparse->srcpad == NULL) return FALSE; GST_DEBUG_OBJECT (wvparse, "Added src pad with caps %" GST_PTR_FORMAT, caps); gst_pad_set_query_function (wvparse->srcpad, GST_DEBUG_FUNCPTR (gst_wavpack_parse_src_query)); gst_pad_set_query_type_function (wvparse->srcpad, GST_DEBUG_FUNCPTR (gst_wavpack_parse_get_src_query_types)); gst_pad_set_event_function (wvparse->srcpad, GST_DEBUG_FUNCPTR (gst_wavpack_parse_src_event)); gst_pad_set_caps (wvparse->srcpad, caps); gst_caps_unref (caps); gst_pad_use_fixed_caps (wvparse->srcpad); gst_object_ref (wvparse->srcpad); gst_pad_set_active (wvparse->srcpad, TRUE); gst_element_add_pad (GST_ELEMENT (wvparse), wvparse->srcpad); gst_element_no_more_pads (GST_ELEMENT (wvparse)); return TRUE; }
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; }