Result SoundSourceWV::tryOpen(const AudioSourceConfig& audioSrcCfg) { DEBUG_ASSERT(!m_wpc); char msg[80]; // hold possible error message int openFlags = OPEN_WVC | OPEN_NORMALIZE; if ((kChannelCountMono == audioSrcCfg.channelCountHint) || (kChannelCountStereo == audioSrcCfg.channelCountHint)) { openFlags |= OPEN_2CH_MAX; } m_wpc = WavpackOpenFileInput( getLocalFileNameBytes().constData(), msg, openFlags, 0); if (!m_wpc) { qDebug() << "SSWV::open: failed to open file : " << msg; return ERR; } setChannelCount(WavpackGetReducedChannels(m_wpc)); setFrameRate(WavpackGetSampleRate(m_wpc)); setFrameCount(WavpackGetNumSamples(m_wpc)); if (WavpackGetMode(m_wpc) & MODE_FLOAT) { m_sampleScaleFactor = CSAMPLE_PEAK; } else { const int bitsPerSample = WavpackGetBitsPerSample(m_wpc); const uint32_t wavpackPeakSampleValue = uint32_t(1) << (bitsPerSample - 1); m_sampleScaleFactor = CSAMPLE_PEAK / CSAMPLE(wavpackPeakSampleValue); } return OK; }
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; }
SoundSource::OpenResult SoundSourceWV::tryOpen( OpenMode /*mode*/, const OpenParams& params) { DEBUG_ASSERT(!m_wpc); char msg[80]; // hold possible error message int openFlags = OPEN_WVC | OPEN_NORMALIZE; if ((params.channelCount() == 1) || (params.channelCount() == 2)) { openFlags |= OPEN_2CH_MAX; } // We use WavpackOpenFileInputEx to support Unicode paths on windows // http://www.wavpack.com/lib_use.txt QString wavPackFileName = getLocalFileName(); m_pWVFile = new QFile(wavPackFileName); m_pWVFile->open(QFile::ReadOnly); QString correctionFileName(wavPackFileName + "c"); if (QFile::exists(correctionFileName)) { // If there is a correction file, open it as well m_pWVCFile = new QFile(correctionFileName); m_pWVCFile->open(QFile::ReadOnly); } m_wpc = WavpackOpenFileInputEx(&s_streamReader, m_pWVFile, m_pWVCFile, msg, openFlags, 0); if (!m_wpc) { kLogger.warning() << "failed to open file : " << msg; return OpenResult::Failed; } setChannelCount(WavpackGetReducedChannels(m_wpc)); setSampleRate(WavpackGetSampleRate(m_wpc)); initFrameIndexRangeOnce( mixxx::IndexRange::forward( 0, WavpackGetNumSamples(m_wpc))); if (WavpackGetMode(m_wpc) & MODE_FLOAT) { m_sampleScaleFactor = CSAMPLE_PEAK; } else { const int bitsPerSample = WavpackGetBitsPerSample(m_wpc); if ((bitsPerSample >= 8) && (bitsPerSample <= 32)) { // Range of signed sample values: [-2 ^ (bitsPerSample - 1), 2 ^ (bitsPerSample - 1) - 1] const uint32_t absSamplePeak = 1u << (bitsPerSample - 1); DEBUG_ASSERT(absSamplePeak > 0); // Scaled range of sample values: [-CSAMPLE_PEAK, CSAMPLE_PEAK) m_sampleScaleFactor = CSAMPLE_PEAK / absSamplePeak; } else { kLogger.warning() << "Invalid bits per sample:" << bitsPerSample; return OpenResult::Aborted; } } m_curFrameIndex = frameIndexMin(); return OpenResult::Succeeded; }
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); }
static int wavpack_assign_values(struct mpxplay_filehand_buffered_func_s *fbfs,void *fbds,struct wavpack_decoder_data *wpdi,struct mpxplay_infile_info_s *miis) { struct mpxplay_audio_decoder_info_s *adi=miis->audio_decoder_infos; unsigned int encmode; unsigned long pcmdatalen; adi->filechannels = adi->outchannels = WavpackGetReducedChannels(wpdi->wpc);//WavpackGetNumChannels(wpdi->wpc); if((adi->outchannels<PCM_MIN_CHANNELS) || (adi->outchannels>PCM_MAX_CHANNELS)) return 0; adi->bits = WavpackGetBitsPerSample(wpdi->wpc); if((adi->bits<PCM_MIN_BITS) || (adi->bits>PCM_MAX_BITS)) return 0; adi->freq = WavpackGetSampleRate(wpdi->wpc); wpdi->bytes_per_sample = WavpackGetBytesPerSample(wpdi->wpc); if(!adi->freq || !wpdi->bytes_per_sample) return 0; pcmdatalen=WavpackGetNumSamples(wpdi->wpc); miis->timemsec=(float)pcmdatalen*1000.0/adi->freq; encmode=WavpackGetMode(wpdi->wpc); if(encmode&MODE_FLOAT){ adi->infobits|=ADI_FLAG_FLOATOUT; adi->bits=1; wpdi->bytes_per_sample=sizeof(MPXPLAY_PCMOUT_FLOAT_T); } miis->longname="WavPack "; if(encmode&MODE_HYBRID){ adi->bitrate=(long)((float)miis->filesize*8.0/1000.0*(float)adi->freq/(float)pcmdatalen); }else{ long compr_ratio; adi->bitratetext=malloc(MPXPLAY_ADITEXTSIZE_BITRATE+8); if(!adi->bitratetext) return 0; compr_ratio=(long)(1000.0*(float)miis->filesize/(float)pcmdatalen/(float)wpdi->bytes_per_sample/(float)adi->filechannels); sprintf(adi->bitratetext,"%2d/%2.2d.%1.1d%%",adi->bits,compr_ratio/10,compr_ratio%10); } return 1; }
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; }
SoundSource::OpenResult SoundSourceWV::tryOpen(const AudioSourceConfig& audioSrcCfg) { DEBUG_ASSERT(!m_wpc); char msg[80]; // hold possible error message int openFlags = OPEN_WVC | OPEN_NORMALIZE; if ((kChannelCountMono == audioSrcCfg.getChannelCount()) || (kChannelCountStereo == audioSrcCfg.getChannelCount())) { openFlags |= OPEN_2CH_MAX; } // We use WavpackOpenFileInputEx to support Unicode paths on windows // http://www.wavpack.com/lib_use.txt QString wavPackFileName = getLocalFileName(); m_pWVFile = new QFile(wavPackFileName); m_pWVFile->open(QFile::ReadOnly); QString correctionFileName(wavPackFileName + "c"); if (QFile::exists(correctionFileName)) { // If there is a correction file, open it as well m_pWVCFile = new QFile(correctionFileName); m_pWVCFile->open(QFile::ReadOnly); } m_wpc = WavpackOpenFileInputEx(&s_streamReader, m_pWVFile, m_pWVCFile, msg, openFlags, 0); if (!m_wpc) { qDebug() << "SSWV::open: failed to open file : " << msg; return OpenResult::FAILED; } setChannelCount(WavpackGetReducedChannels(m_wpc)); setSamplingRate(WavpackGetSampleRate(m_wpc)); setFrameCount(WavpackGetNumSamples(m_wpc)); if (WavpackGetMode(m_wpc) & MODE_FLOAT) { m_sampleScaleFactor = CSAMPLE_PEAK; } else { const int bitsPerSample = WavpackGetBitsPerSample(m_wpc); const uint32_t wavpackPeakSampleValue = 1u << (bitsPerSample - 1); m_sampleScaleFactor = CSAMPLE_PEAK / wavpackPeakSampleValue; } return OpenResult::SUCCEEDED; }
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; }
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; }
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 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 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; } }
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, 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); }
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 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; }
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; }
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; }