FLACSource::FLACSource(const FLACModule &module, const std::shared_ptr<FILE> &fp): m_eof(false), m_giveup(false), m_initialize_done(false), m_length(0), m_position(0), m_fp(fp), m_module(module) { char buffer[33]; util::check_eof(util::nread(fileno(m_fp.get()), buffer, 33) == 33); if (std::memcmp(buffer, "ID3", 3) == 0) { uint32_t size = 0; for (int i = 6; i < 10; ++i) { size <<= 7; size |= buffer[i]; } CHECKCRT(_lseeki64(fileno(m_fp.get()), 10 + size, SEEK_SET) < 0); util::check_eof(util::nread(fileno(m_fp.get()), buffer, 33) == 33); } uint32_t fcc = util::fourcc(buffer); if ((fcc != 'fLaC' && fcc != 'OggS') || (fcc == 'OggS' && std::memcmp(&buffer[28], "\177FLAC", 5))) throw std::runtime_error("Not a FLAC file"); CHECKCRT(_lseeki64(fileno(m_fp.get()), 0, SEEK_SET) < 0); m_decoder = decoder_t(m_module.stream_decoder_new(), std::bind1st(std::mem_fun(&FLACSource::close), this)); TRYFL(m_module.stream_decoder_set_metadata_respond( m_decoder.get(), FLAC__METADATA_TYPE_VORBIS_COMMENT)); TRYFL(m_module.stream_decoder_set_metadata_respond( m_decoder.get(), FLAC__METADATA_TYPE_PICTURE)); TRYFL((fcc == 'OggS' ? m_module.stream_decoder_init_ogg_stream : m_module.stream_decoder_init_stream) (m_decoder.get(), staticReadCallback, staticSeekCallback, staticTellCallback, staticLengthCallback, staticEofCallback, staticWriteCallback, staticMetadataCallback, staticErrorCallback, this) == FLAC__STREAM_DECODER_INIT_STATUS_OK); TRYFL(m_module.stream_decoder_process_until_end_of_metadata( m_decoder.get())); if (m_giveup || m_asbd.mBitsPerChannel == 0) flac::want(false); m_buffer.set_unit(m_asbd.mChannelsPerFrame); m_initialize_done = true; }
void FLACSource::seekTo(int64_t count) { if (count == m_position) return; m_buffer.reset(); TRYFL(m_module.stream_decoder_seek_absolute(m_decoder.get(), count)); m_position = count; }
size_t FLACSource::readSamples(void *buffer, size_t nsamples) { if (m_giveup) throw std::runtime_error("FLAC decoder error"); if (!m_buffer.count()) { if (m_module.stream_decoder_get_state(m_decoder.get()) == FLAC__STREAM_DECODER_END_OF_STREAM) return 0; TRYFL(m_module.stream_decoder_process_single(m_decoder.get())); } uint32_t count = std::min(m_buffer.count(), nsamples); if (count) { uint32_t bytes = count * m_asbd.mChannelsPerFrame * 4; std::memcpy(buffer, m_buffer.read(count), bytes); m_position += count; } return count; }
FLACSink::FLACSink(FILE *fp, uint64_t duration, const SampleFormat &fmt, const FLACModule &module, const std::map<uint32_t, std::wstring> &tags) :m_fp(fp), m_module(module), m_format(fmt) { if (fmt.m_type == SampleFormat::kIsFloat) throw std::runtime_error("Can't handle float source"); if (fmt.m_endian == SampleFormat::kIsBigEndian) throw std::runtime_error("Can't handle big endian source"); m_encoder.swap(encoder_t(m_module.stream_encoder_new(), std::bind1st(std::mem_fun(&FLACSink::closeEncoder), this))); TRYFL(m_module.stream_encoder_set_channels( m_encoder.get(), fmt.m_nchannels)); TRYFL(m_module.stream_encoder_set_bits_per_sample( m_encoder.get(), fmt.m_bitsPerSample)); TRYFL(m_module.stream_encoder_set_sample_rate( m_encoder.get(), fmt.m_rate)); TRYFL(m_module.stream_encoder_set_total_samples_estimate( m_encoder.get(), duration)); TRYFL(m_module.stream_encoder_set_compression_level( m_encoder.get(), 5)); FLAC__StreamMetadata *meta[2]; meta[0] = m_module.metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); meta[1] = m_module.metadata_object_new(FLAC__METADATA_TYPE_PADDING); meta[1]->length = 0x1000; m_metadata_holder[0].swap( metadata_t(meta[0], m_module.metadata_object_delete)); m_metadata_holder[1].swap( metadata_t(meta[1], m_module.metadata_object_delete)); { FLAC__StreamMetadata_VorbisComment_Entry entry; std::map<uint32_t, std::wstring>::const_iterator ii; utf8_codecvt_facet u8codec; for (ii = tags.begin(); ii != tags.end(); ++ii) { const char *key = GetNameFromTagID(ii->first); if (!key) continue; std::string value = w2m(ii->second, u8codec); m_module.metadata_object_vorbiscomment_entry_from_name_value_pair( &entry, key, value.c_str()); m_module.metadata_object_vorbiscomment_append_comment( meta[0], entry, false); } } m_module.stream_encoder_set_metadata(m_encoder.get(), meta, 2); TRYFL(m_module.stream_encoder_init_stream(m_encoder.get(), staticWriteCallback, 0, 0, 0, this) == FLAC__STREAM_ENCODER_INIT_STATUS_OK); }
void FLACSink::writeSamples(const void *data, size_t length, size_t nsamples) { std::vector<int32_t> buff; switch (m_format.m_bitsPerSample) { case 8: { const char *src = reinterpret_cast<const char *>(data); for (size_t i = 0; i < length; ++i) buff.push_back(src[i]); } break; case 16: { const int16_t *src = reinterpret_cast<const int16_t*>(data); for (size_t i = 0; i < length / 2; ++i) buff.push_back(src[i]); } break; case 24: { const uint8_t *src = reinterpret_cast<const uint8_t*>(data); for (size_t i = 0; i < length / 3; ++i) { int32_t hv = static_cast<int8_t>(src[i*3+2]); int32_t v = (src[i*3] | (src[i*3+1] << 8) | (hv << 16)); buff.push_back(v); } } break; case 32: { const int32_t *src = reinterpret_cast<const int32_t *>(data); for (size_t i = 0; i < length / 4; ++i) buff.push_back(src[i]); } break; } TRYFL(m_module.stream_encoder_process_interleaved( m_encoder.get(), &buff[0], nsamples)); }