Project::OSiRiON - Git repositories
Project::OSiRiON
News . About . Screenshots . Downloads . Forum . Wiki . Tracker . Git
summaryrefslogtreecommitdiff
blob: b6ca71075ef6737dbcfde7530367bad7594c4abf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/*
   audio/wav.h
   This file is part of the Osirion project and is distributed under
   the terms of the GNU General Public License version 2
*/

/*
see

http://ccrma.stanford.edu/CCRMA/Courses/422/projects/WaveFormat/
*/

#include "string.h"

#include <iostream>
#include <string>

#include "audio/wav.h"
#include "filesystem/filesystem.h"
#include "sys/sys.h"

namespace audio
{

PCM *Wav::load(std::string const & name)
{
	if (!name.size())
		return 0;

	std::string filename("sounds/");
	filename.append(name);
	filename.append(".wav");

	filesystem::File *wav_file = filesystem::open(filename.c_str());
	if (!wav_file) {
		con_warn << "Could not open " << filename << std::endl;
		return 0;
	}

	unsigned char header[44];
	memset(header, 0, sizeof(header));
	if (!wav_file->read(header, 44)) {
		con_warn << "Error reading " << filename << std::endl;
		filesystem::close(wav_file);
		return 0;
	}

	// header RIFF
	if (strncmp((char *)header, "RIFF", 4)) {
		con_warn << "Error reading " << filename << ": invalid RIFF header!" << std::endl;
		filesystem::close(wav_file);
		return 0;
	}

	// format WAVE
	if (strncmp((char *)header + 8, "WAVE", 4) != 0) {
		con_warn << "Error reading " << filename << ": invalid WAVE header!" << std::endl;
		filesystem::close(wav_file);
		return 0;
	}

	// file size
	//size_t chunksize = header[4] + (header[5] << 8) + (header[6] << 16) + (header[7] << 24);

	if (strncmp((char *)header + 12, "fmt ", 4) != 0) {
		con_warn << "Error reading " << filename << ": invalid format header!" << std::endl;
		filesystem::close(wav_file);
		return 0;
	}

	size_t subchunksize1 = header[16] + (header[17] << 8) + (header[18] << 16) + (header[19] << 24);
	size_t audioformat = header[20] + (header[21] << 8);

	if ((subchunksize1 != 16) || (audioformat != 1)) {
		con_warn << "Error reading " << filename << ": unrecognized file format!" << std::endl;
		filesystem::close(wav_file);
		return 0;

	}

	unsigned int channels = header[22] + (header[23] << 8);
	if ((channels < 1) || (channels > 2)) {
		con_warn << "Error reading " << filename << ": invalid number of channels!" << std::endl;
		filesystem::close(wav_file);
		return 0;
	}

	unsigned int samplerate = header[24] + ((size_t)header[25] << 8) + ((size_t)header[26] << 16) + ((size_t)header[27] << 24);
	//size_t byterate  = header[28] + (header[29] << 8) + (header[30] << 16) + (header[31] << 24);
	//size_t blockalign = header[32] + (header[33] << 8);
	size_t bitspersample = header[34] + (header[35] << 8);

	if (strncmp((char *)header + 36, "data", 4) != 0) {
		con_warn << "Error reading " << filename << ": invalid data header!" << std::endl;
		filesystem::close(wav_file);
		return 0;
	}

	size_t datasize = header[40] + (header[41] << 8) + (header[42] << 16) + (header[43] << 24);

	PCM *pcm = new PCM(samplerate, bitspersample, channels, datasize);
	const size_t readblocksize = channels * (bitspersample / 8);
	size_t total_bytes = 0;

	while ((wav_file->read((void *)(*pcm)[total_bytes], readblocksize)) && (total_bytes < datasize)) {
		total_bytes += readblocksize;
	}

	if (total_bytes < datasize) {
		con_warn << "Error reading " << filename << ": file truncated!" << std::endl;
	}

	con_debug << "  " << filename << " " << pcm->samplerate() << "Hz " << pcm->bitspersample() << "bit " <<
	pcm->channels() << " chan " << pcm->size() << " bytes" << std::endl;

	filesystem::close(wav_file);
	return pcm;
}

}