Skip to content

Commit

Permalink
fs file rewrited, wave loader improved
Browse files Browse the repository at this point in the history
  • Loading branch information
mtiapko committed Jan 6, 2019
1 parent 350ba75 commit 9ea62d2
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 126 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
CC := g++
LD := g++

CC_FLAGS := -std=c++2a -MMD -MP -g
CC_FLAGS := -std=c++2a -Wall -Wextra -MMD -MP -g
CC_INCLUDES := -I./include
CC_DEFINES :=

Expand Down
4 changes: 2 additions & 2 deletions include/audio/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
func, \
[](string_view func_name) { \
if(auto err = alGetError(); err != AL_NO_ERROR) \
DK_LOG_ERROR(__FILE__, func_name, __LINE__, \
DK_LOG_ERROR_IMPL(__FILE__, func_name, __LINE__, \
"OpenAL function '", #func, "' failed: ", debug::code_to_str(err)); \
}(__FILE__)
}(__func__)

namespace dk::audio
{
Expand Down
19 changes: 11 additions & 8 deletions include/fs/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,20 @@ class file
file() noexcept;
~file() noexcept;

status open(string_view path) noexcept;
status read(uint8_t* data, size_t size) const noexcept;
status size(size_t& size_val) const noexcept;
static constexpr int BAD_ID = -1;
static constexpr size_t BAD_SIZE = (size_t)-1;
static constexpr size_t END_OF_FILE = 0;

static status read(string_view path, string& data) noexcept;

// TODO: is it needed: size_t read_to_buff(uint8_t* data, size_t max_size) noexcept; ???
status open(string_view path) noexcept;
status close() noexcept;

static status open(string_view path, int& fd) noexcept;
static status read(string& data, const string_view& path, int id) noexcept;
static status size(size_t& size_val, const string_view& path, int id) noexcept;
status size(size_t& val) const noexcept;
status move_cursor(ssize_t offset) const noexcept;
size_t read(void* data, size_t max_size) const noexcept;

static status read(string& data, string_view path) noexcept;
template<typename T> size_t read(T& data) const noexcept { return this->read(&data, sizeof(T)); }
};

}
Expand Down
Binary file removed res/audio/wind.wav
Binary file not shown.
2 changes: 1 addition & 1 deletion src/audio/core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ ALCcontext* core::s_context;
return status::ERROR;

ALfloat orientation[] = { 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f };
AL_CALL(alListener3f(AL_POSITION, 0.0f, 0.0f, 0.0f));
AL_CALL(alListener3f(AL_POSITION, 0.0f, 0.0f, 1.0f));
AL_CALL(alListener3f(AL_VELOCITY, 0.0f, 0.0f, 0.0f));
AL_CALL(alListenerfv(AL_ORIENTATION, orientation));
return status::OK;
Expand Down
137 changes: 77 additions & 60 deletions src/audio/fmts/wave_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,93 +14,110 @@ struct wave_header
uint32_t size;
};

struct
struct RIFF_chunk
{
chunk_header chunk;
uint32_t format;
} RIFF;
static constexpr uint32_t id = 0x46464952; /* "RIFF" */
uint32_t format;
};

struct
struct fmt_chunk
{
chunk_header sub_chunk;
static constexpr uint32_t id = 0x20746D66; /* "fmt " */

uint16_t audio_fmt; /* PCM = 1 */
uint16_t num_channels; /* mono = 1, stereo = 2, ... */
uint32_t sample_rate; /* 8000, 44100, ... */
uint32_t byte_rate; /* sample_rate * num_channels * bits_per_sample / 8 */
uint16_t block_align; /* num_channels * bits_per_sample / 8 */
uint16_t bits_per_sample; /* 8, 16, ... */
} fmt;
};

struct
struct data_chunk
{
chunk_header sub_chunk; /* size = num_samples (yeah, samples) * num_channels * bits_per_sample / 8 */
} data;
/* size = num_samples (yeah, samples) * num_channels * bits_per_sample / 8 */
static constexpr uint32_t id = 0x61746164; /* "data" */
};
};

status sound_data::load_wave(string_view file_path) noexcept
{
// TODO: WAVE file may have additional subchunks.
// If so, each will have a char[4] SubChunkID, and
// unsigned long SubChunkSize, and SubChunkSize amount of data

// TODO: write timer
fs::file wave;
if (auto res = wave.open(file_path); !res)
return res;

wave_header head;
if (auto res = wave.read((uint8_t*)&head, sizeof(head)); !res) {
DK_LOG_ERROR("Failed to read WAVE file '", file_path, "' header");
return res;
size_t readed_size;
size_t RIFF_chunk_size = 0;
size_t fmt_chunk_size = 0;
size_t data_chunk_size = 0;
size_t unknown_chunk_size = 0;
wave_header::chunk_header chunk_header;
while ((readed_size = wave.read(chunk_header)) == sizeof(chunk_header)) {
switch (chunk_header.id) {
case wave_header::RIFF_chunk::id: {
wave_header::RIFF_chunk RIFF_chunk;
if (wave.read(RIFF_chunk) != sizeof(RIFF_chunk)) {
return status::ERROR;
}

if (RIFF_chunk.format != 0x45564157) { /* "WAVE" */
DK_LOG_ERROR("Wrong format in RIFF chunk of WAVE file '", file_path, '\'');
return status::ERROR;
}

RIFF_chunk_size = chunk_header.size;
break;
}
case wave_header::fmt_chunk::id: {
wave_header::fmt_chunk fmt_chunk;
if (wave.read(fmt_chunk) != sizeof(fmt_chunk)) {
return status::ERROR;
}

if (chunk_header.size != 16) { /* PCM encoding format header size */
DK_LOG_ERROR("Unexpected fmt sub chunk size in WAVE file '", file_path, '\'');
return status::ERROR;
}

if (fmt_chunk.audio_fmt != 1) { /* PCM must be 1 - linear quantization */
DK_LOG_ERROR("Compressed WAVE file '", file_path, "' does not supported");
return status::ERROR;
}

m_num_channels = fmt_chunk.num_channels;
m_sample_rate = fmt_chunk.sample_rate;
m_bits_per_sample = fmt_chunk.bits_per_sample;
fmt_chunk_size = chunk_header.size + sizeof(wave_header::chunk_header);
break;
}
case wave_header::data_chunk::id: {
m_data = mem::alloc(chunk_header.size);
if (auto res = wave.read(m_data, chunk_header.size); !res) {
DK_LOG_ERROR("Failed to read WAVE file '", file_path, "' data");
return res;
}

m_size = chunk_header.size;
data_chunk_size = chunk_header.size + sizeof(wave_header::chunk_header);
break;
}
default:
unknown_chunk_size += chunk_header.size + sizeof(wave_header::chunk_header);
DK_LOG_WARNING("Unknown chunk id in WAVE file '", file_path, '\'');
if (auto res = wave.move_cursor(chunk_header.size); !res)
return res;
}
}

if (head.RIFF.chunk.id != 0x46464952) { /* "RIFF" */
DK_LOG_ERROR("Wrong RIFF chunk ID in WAVE file '", file_path, '\'');
if (readed_size == fs::file::BAD_SIZE)
return status::ERROR;
}

if (head.RIFF.format != 0x45564157) { /* "WAVE" */
DK_LOG_ERROR("Wrong format in RIFF chunk of WAVE file '", file_path, '\'');
return status::ERROR;
}

if (head.fmt.sub_chunk.id != 0x20746D66) { /* "fmt " */
DK_LOG_ERROR("Wrong fmt sub chunk ID in WAVE file '", file_path, '\'');
return status::ERROR;
}

if (head.fmt.sub_chunk.size != 16) { /* PCM encoding format header size */
DK_LOG_ERROR("Unexpected fmt sub chunk size in WAVE file '", file_path, '\'');
if (RIFF_chunk_size != sizeof(wave_header::chunk_header::id) /* RIFF chunk id */
+ fmt_chunk_size + data_chunk_size + unknown_chunk_size) {
DK_LOG_ERROR("Chunks size check failed in header of WAVE file '", file_path, '\'');
return status::ERROR;
}

if (head.fmt.audio_fmt != 1) { /* PCM must be 1 - linear quantization */
DK_LOG_ERROR("Compressed WAVE file '", file_path, "' does not supported");
return status::ERROR;
}

if (head.data.sub_chunk.id != 0x61746164) { /* "data" */
DK_LOG_ERROR("Wrong data sub chunk ID in WAVE file '", file_path, '\'');
return status::ERROR;
}

if (head.RIFF.chunk.size != sizeof(head.RIFF.chunk.id)
+ (sizeof(wave_header::chunk_header) + head.fmt.sub_chunk.size)
+ (sizeof(wave_header::chunk_header) + head.data.sub_chunk.size)) {
DK_LOG_ERROR("Invalid size in WAVE file '", file_path, "' header");
}

m_data = mem::alloc(head.data.sub_chunk.size);
if (auto res = wave.read(m_data, head.data.sub_chunk.size); !res) {
DK_LOG_ERROR("Failed to read WAVE file '", file_path, "' data");
return res;
}

m_size = head.data.sub_chunk.size;
m_num_channels = head.fmt.num_channels;
m_sample_rate = head.fmt.sample_rate;
m_bits_per_sample = head.fmt.bits_per_sample;

DK_LOG_OK("WAVE file '", file_path, "' loaded");
return status::OK;
}
Expand Down
5 changes: 2 additions & 3 deletions src/audio/sound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@ sound::~sound() noexcept
if (num_channels == 1) return AL_FORMAT_MONO8;
else if (num_channels == 2) return AL_FORMAT_STEREO8;

break;
DK_LOG_ERROR("Unsupported sound channels count: ", num_channels);
return 0;
case 16:
if (num_channels == 1) return AL_FORMAT_MONO16;
else if (num_channels == 2) return AL_FORMAT_STEREO16;

break;
default:
DK_LOG_ERROR("Unsupported sound channels count: ", num_channels);
return 0;
}
Expand Down
95 changes: 51 additions & 44 deletions src/fs/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,91 +9,98 @@ namespace dk::fs
{

file::file() noexcept
: m_id(-1)
: m_id(BAD_ID)
{}

file::~file() noexcept
{
if (m_id >= 0)
close(m_id); // TODO: write close() method
close();
}

status file::open(string_view path) noexcept
/* static */ status file::read(string_view path, string& data) noexcept
{
m_path = path;
return open(path, m_id);
}
file file;
if (auto res = file.open(path); !res)
return res;

status file::read(uint8_t* data, size_t size) const noexcept
{
if ((size_t)::read(m_id, data, size) != size) {
DK_LOG_ERROR("Failed to read ", size, " byte(s) from file '", m_path, '\'');
size_t size;
if (auto res = file.size(size); !res)
return res;

if (size == BAD_SIZE) {
DK_LOG_ERROR("File '", path, "' has undefined size");
return status::ERROR;
}

return status::OK;
}
size = file.read(data.data(), data.size());
if (size == BAD_SIZE)
return status::ERROR;

status file::size(size_t& size_val) const noexcept
{
return size(size_val, m_path, m_id);
if (size != data.size()) {
DK_LOG_ERROR("Failed to read whole file '", path, '\'');
return status::ERROR;
}

return status::OK;
}

/* static */ status file::open(string_view path, int& id) noexcept
status file::open(string_view path) noexcept
{
/* XXX: if path has wrong value - can be buffer overrun */
DK_ASSERT(!path.empty() && *(path.data() + path.size()) == '\0');

id = ::open(path.data(), O_RDONLY);
if (id < 0) {
DK_LOG_ERROR("Failed to open file '", path, ": ", strerror(errno));
m_path = path;
m_id = ::open(path.data(), O_RDONLY);
if (m_id == BAD_ID) {
DK_LOG_ERROR("Failed to open file '", path, "': ", strerror(errno));
return status::ERROR;
}

return status::OK;
}

/* static */ status file::read(string& data, const string_view& path, int id) noexcept
status file::close() noexcept
{
size_t size;
if (auto res = file::size(size, path, id); !res)
return res;

data.resize(size);
if ((size_t)::read(id, data.data(), data.size()) != size) {
DK_LOG_ERROR("Failed to read file '", path, '\'');
if (m_id >= BAD_ID && ::close(m_id) < 0) {
DK_LOG_ERROR("Failed to close file '", m_path, "': ", strerror(errno));
return status::ERROR;
}

m_id = BAD_ID;
return status::OK;
}

/* static */ status file::size(size_t& size_val, const string_view& path, int id) noexcept
status file::size(size_t& val) const noexcept
{
struct stat stat;
if (fstat(id, &stat) < 0) {
DK_LOG_ERROR("Failed to get stat of file '", path, ": ", strerror(errno));
return 0;
if (fstat(m_id, &stat) < 0) {
DK_LOG_ERROR("Failed to get stat of file '", m_path, "': ", strerror(errno));
return status::ERROR;
}

if (stat.st_size < 0) {
DK_LOG_ERROR("Failed to get size of file '", path, '\'');
return 0;
val = stat.st_size;
return status::OK;
}

status file::move_cursor(ssize_t offset) const noexcept
{
if (lseek(m_id, offset, SEEK_CUR) < 0) {
DK_LOG_ERROR("Failed to move cursor in file '", m_path, "': ", strerror(errno));
return status::ERROR;
}

size_val = stat.st_size;
return status::OK;
}

/* static */ status file::read(string& data, string_view path) noexcept
size_t file::read(void* data, size_t max_size) const noexcept
{
int id;
if (auto res = open(path, id); !res)
return res;

auto res = read(data, path, id);
::close(id);
size_t size = ::read(m_id, data, max_size);
if (size == BAD_SIZE) {
DK_LOG_ERROR("Failed to read file '", m_path, "': ", strerror(errno));
return BAD_SIZE;
}

return res;
return size;
}

}
Loading

0 comments on commit 9ea62d2

Please sign in to comment.