wav files streaming
This commit is contained in:
+3
-1
@@ -121,7 +121,9 @@ Sound* audio::createSound(std::shared_ptr<PCM> pcm, bool keepPCM) {
|
|||||||
|
|
||||||
PCMStream* audio::openPCMStream(const fs::path& file) {
|
PCMStream* audio::openPCMStream(const fs::path& file) {
|
||||||
std::string ext = file.extension().u8string();
|
std::string ext = file.extension().u8string();
|
||||||
if (ext == ".ogg" || ext == ".OGG") {
|
if (ext == ".wav" || ext == ".WAV") {
|
||||||
|
return wav::create_stream(file);
|
||||||
|
} else if (ext == ".ogg" || ext == ".OGG") {
|
||||||
return ogg::create_stream(file);
|
return ogg::create_stream(file);
|
||||||
}
|
}
|
||||||
throw std::runtime_error("unsupported audio stream format");
|
throw std::runtime_error("unsupported audio stream format");
|
||||||
|
|||||||
+117
-5
@@ -3,6 +3,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include "../audio/audio.h"
|
#include "../audio/audio.h"
|
||||||
@@ -27,7 +28,108 @@ std::int32_t convert_to_int(char* buffer, std::size_t len){
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
audio::PCM* wav::load_pcm(const std::filesystem::path& file, bool headerOnly) {
|
/// @brief Seekable WAV-file PCM stream
|
||||||
|
class WavStream : public audio::PCMStream {
|
||||||
|
std::ifstream in;
|
||||||
|
uint channels;
|
||||||
|
uint bytesPerSample;
|
||||||
|
uint sampleRate;
|
||||||
|
size_t totalSize;
|
||||||
|
size_t totalSamples;
|
||||||
|
size_t initialPosition;
|
||||||
|
public:
|
||||||
|
WavStream(
|
||||||
|
std::ifstream in,
|
||||||
|
uint channels,
|
||||||
|
uint bitsPerSample,
|
||||||
|
uint sampleRate,
|
||||||
|
size_t size
|
||||||
|
) : in(std::move(in)),
|
||||||
|
channels(channels),
|
||||||
|
bytesPerSample(bitsPerSample/8),
|
||||||
|
sampleRate(sampleRate),
|
||||||
|
totalSize(size)
|
||||||
|
{
|
||||||
|
totalSamples = totalSize / channels / bytesPerSample;
|
||||||
|
initialPosition = in.tellg();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t read(char* buffer, size_t bufferSize, bool loop) override {
|
||||||
|
if (!isOpen()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
long bytes = 0;
|
||||||
|
size_t size = 0;
|
||||||
|
do {
|
||||||
|
do {
|
||||||
|
in.read(buffer, bufferSize);
|
||||||
|
if (in.failbit) {
|
||||||
|
std::cerr << "Wav::load_pcm: I/O error ocurred" << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bytes = in.gcount();
|
||||||
|
size += bytes;
|
||||||
|
bufferSize -= bytes;
|
||||||
|
buffer += bytes;
|
||||||
|
} while (bytes > 0 && bufferSize > 0);
|
||||||
|
|
||||||
|
if (bufferSize == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loop) {
|
||||||
|
seek(0);
|
||||||
|
}
|
||||||
|
if (bufferSize == 0) {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
} while (loop);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close() override {
|
||||||
|
if (!isOpen())
|
||||||
|
return;
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isOpen() const override {
|
||||||
|
return in.is_open();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t getTotalSamples() const override {
|
||||||
|
return totalSamples;
|
||||||
|
}
|
||||||
|
|
||||||
|
audio::duration_t getTotalDuration() const override {
|
||||||
|
return totalSamples / static_cast<audio::duration_t>(sampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint getChannels() const override {
|
||||||
|
return channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint getSampleRate() const override {
|
||||||
|
return sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint getBitsPerSample() const override {
|
||||||
|
return bytesPerSample * 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSeekable() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void seek(size_t position) override {
|
||||||
|
if (!isOpen())
|
||||||
|
return;
|
||||||
|
position %= totalSamples;
|
||||||
|
in.seekg(initialPosition + position * channels * bytesPerSample);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
audio::PCMStream* wav::create_stream(const std::filesystem::path& file) {
|
||||||
std::ifstream in(file, std::ios::binary);
|
std::ifstream in(file, std::ios::binary);
|
||||||
if(!in.is_open()){
|
if(!in.is_open()){
|
||||||
throw std::runtime_error("could not to open file '"+file.u8string()+"'");
|
throw std::runtime_error("could not to open file '"+file.u8string()+"'");
|
||||||
@@ -105,14 +207,24 @@ audio::PCM* wav::load_pcm(const std::filesystem::path& file, bool headerOnly) {
|
|||||||
if(in.fail()){
|
if(in.fail()){
|
||||||
throw std::runtime_error("fail state set on the file");
|
throw std::runtime_error("fail state set on the file");
|
||||||
}
|
}
|
||||||
|
return new WavStream(std::move(in), channels, bitsPerSample, sampleRate, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
audio::PCM* wav::load_pcm(const std::filesystem::path& file, bool headerOnly) {
|
||||||
|
std::unique_ptr<audio::PCMStream> stream(wav::create_stream(file));
|
||||||
|
|
||||||
|
size_t totalSamples = stream->getTotalSamples();
|
||||||
|
uint channels = stream->getChannels();
|
||||||
|
uint bitsPerSample = stream->getBitsPerSample();
|
||||||
|
uint sampleRate = stream->getSampleRate();
|
||||||
|
|
||||||
std::vector<char> data;
|
std::vector<char> data;
|
||||||
size_t totalSamples = size / (bitsPerSample / 8);
|
|
||||||
if (!headerOnly) {
|
if (!headerOnly) {
|
||||||
|
size_t size = stream->getTotalSamples() *
|
||||||
|
(stream->getBitsPerSample()/8) *
|
||||||
|
stream->getChannels();
|
||||||
data.resize(size);
|
data.resize(size);
|
||||||
if (!in.read(data.data(), size)) {
|
stream->read(data.data(), size, false);
|
||||||
throw std::runtime_error("could not load wav data of '"+file.u8string()+"'");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return new audio::PCM(std::move(data), totalSamples, channels, bitsPerSample, sampleRate, true);
|
return new audio::PCM(std::move(data), totalSamples, channels, bitsPerSample, sampleRate, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,12 @@
|
|||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
struct PCM;
|
struct PCM;
|
||||||
|
class PCMStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace wav {
|
namespace wav {
|
||||||
extern audio::PCM* load_pcm(const std::filesystem::path& file, bool headerOnly);
|
extern audio::PCM* load_pcm(const std::filesystem::path& file, bool headerOnly);
|
||||||
|
extern audio::PCMStream* create_stream(const std::filesystem::path& file);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CODERS_WAV_H_
|
#endif // CODERS_WAV_H_
|
||||||
|
|||||||
Reference in New Issue
Block a user