// Copyright (C) 2013 Jérôme Leclercq // This file is part of the "Nazara Engine - Audio module" // For conditions of distribution and use, see copyright notice in Config.hpp #include #include #include #include #include #include #include #include #include #include #include #include namespace { sf_count_t GetSize(void* user_data) { NzInputStream* stream = static_cast(user_data); return stream->GetSize(); } sf_count_t Read(void* ptr, sf_count_t count, void* user_data) { NzInputStream* stream = static_cast(user_data); return static_cast(stream->Read(ptr, static_cast(count))); } sf_count_t Seek(sf_count_t offset, int whence, void* user_data) { NzInputStream* stream = static_cast(user_data); switch (whence) { case SEEK_CUR: stream->Read(nullptr, static_cast(offset)); break; case SEEK_END: stream->SetCursorPos(stream->GetSize() + offset); // L'offset est négatif ici break; case SEEK_SET: stream->SetCursorPos(offset); break; default: NazaraInternalError("Seek mode not handled"); } return stream->GetCursorPos(); } sf_count_t Tell(void* user_data) { NzInputStream* stream = reinterpret_cast(user_data); return stream->GetCursorPos(); } static SF_VIRTUAL_IO callbacks = {GetSize, Seek, Read, nullptr, Tell}; bool IsSupported(const NzString& extension) { static std::set supportedExtensions = { "aiff", "au", "avr", "caf", "flac", "htk", "ircam", "mat4", "mat5", "mpc2k", "nist","ogg", "pvf", "raw", "rf64", "sd2", "sds", "svx", "voc", "w64", "wav", "wve" }; return supportedExtensions.find(extension) != supportedExtensions.end(); } nzTernary Check(NzInputStream& stream, const NzSoundBufferParams& parameters) { NazaraUnused(parameters); SF_INFO info; info.format = 0; SNDFILE* file = sf_open_virtual(&callbacks, SFM_READ, &info, &stream); if (file) { sf_close(file); return nzTernary_True; } else return nzTernary_False; } bool Load(NzSoundBuffer* soundBuffer, NzInputStream& stream, const NzSoundBufferParams& parameters) { NazaraUnused(parameters); SF_INFO info; info.format = 0; SNDFILE* file = sf_open_virtual(&callbacks, SFM_READ, &info, &stream); if (!file) { NazaraError("Failed to load sound file: " + NzString(sf_strerror(file))); return false; } nzAudioFormat format = NzAudio::GetAudioFormat(info.channels); if (format == nzAudioFormat_Unknown) { NazaraError("Channel count not handled"); sf_close(file); return false; } // https://github.com/LaurentGomila/SFML/issues/271 // http://www.mega-nerd.com/libsndfile/command.html#SFC_SET_SCALE_FLOAT_INT_READ ///FIXME: Seulement le Vorbis ? if (info.format & SF_FORMAT_VORBIS) sf_command(file, SFC_SET_SCALE_FLOAT_INT_READ, nullptr, SF_TRUE); sf_count_t sampleCount = info.frames * info.channels; std::unique_ptr samples(new nzInt16[sampleCount]); if (sf_read_short(file, samples.get(), sampleCount) != sampleCount) { sf_close(file); NazaraError("Failed to read samples"); return false; } if (!soundBuffer->Create(format, static_cast(sampleCount), info.samplerate, samples.get())) { sf_close(file); NazaraError("Failed to create sound buffer"); return false; } return true; } } void NzLoaders_sndfile_Register() { NzSoundBufferLoader::RegisterLoader(IsSupported, Check, Load); } void NzLoaders_sndfile_Unregister() { NzSoundBufferLoader::UnregisterLoader(IsSupported, Check, Load); }