5 #include "rapidjson/stringbuffer.h" 17 unsigned char riff[4];
19 unsigned char wave[4];
20 unsigned char fmt_chunk_marker[4];
28 unsigned char data_chunk_header[4];
35 namespace datastructure {
102 const bool debug =
false;
108 vector<AudioChannel> channels;
110 union ShortByteUnion {
111 signed short asShort;
112 unsigned char asBytes[2];
123 AudioClip(
int sampleCount,
int numChannels,
int sampleBits,
int sampleRate) {
124 if (sampleCount > 1000000000) {
125 throw "sampleCount must be less than 1 million";
129 if (sampleBits != 8 && sampleBits != 16 && sampleBits != 24 && sampleBits != 32) {
130 throw "sampleBits must be either 8, 16, 24, or 32";
133 if (numChannels <= 0) {
134 throw "numChannels should be positive";
137 if (sampleRate <= 0) {
138 throw "sampleRate should be positive";
143 this->sampleCount = sampleCount;
144 this->numChannels = numChannels;
145 this->channels = vector<AudioChannel>();
147 for (
int i = 0; i < numChannels; i++) {
150 for (
int j = 0; j < sampleCount; j++) {
151 this->channels[i].setSample(j, 0);
155 this->sampleRate = sampleRate;
156 this->sampleBits = sampleBits;
170 parseWaveFile (wave_file);
177 int len = numChannels * sampleCount * (sampleBits / 8);
178 std::vector<BYTE> byteBuff;
180 int checkSampleBits = sampleBits;
182 for (
int i = 0; i < sampleCount; i++) {
183 for (
int c = 0; c < numChannels; c++) {
184 int num = getSample(c, i);
186 if (this->sampleBits == 8) {
187 byteBuff.push_back(num & 0x000000FF);
189 else if (this->sampleBits == 16) {
191 sbu.asShort = (uint16_t)num;
192 byteBuff.push_back(sbu.asBytes[0]);
193 byteBuff.push_back(sbu.asBytes[1]);
195 else if (this->sampleBits == 32 || this->sampleBits == 24) {
197 int minmax = (int)((pow(2, sampleBits) / 2) - 1);
198 int minmax16 = (int)((pow(2, 16) / 2) - 1);
200 num = (int)((num / (
float)minmax) * minmax16) & 0xFFFF;
203 sbu.asShort = (uint16_t)num;
204 byteBuff.push_back(sbu.asBytes[0]);
205 byteBuff.push_back(sbu.asBytes[1]);
206 checkSampleBits = 16;
228 return this->numChannels;
236 return this->sampleRate;
247 return this->sampleCount;
265 return this->sampleBits;
277 int getSample(
int channelIndex,
int sampleIndex)
const {
278 return channels.at(channelIndex).getSample(sampleIndex);
288 void setSample(
int channelIndex,
int sampleIndex,
int value) {
289 if (value >= pow(2, getSampleBits() - 1) ||
290 value < -pow(2, getSampleBits() - 1))
291 throw "Audio value Out of Bound";
293 channels[channelIndex].setSample(sampleIndex, value);
304 void parseWaveFile (
const string & wave_file) {
309 infile.open (wave_file.c_str(), ios::binary | ios::in);
311 throw "Could not open " + wave_file;
315 WaveHeader wave_header = readWaveHeader(infile);
317 long size_of_each_sample = (wave_header.
channels *
321 if (this->sampleCount > 1000000000) {
322 throw "sampleCount must be less than 1 million";
327 for (
int i = 0; i < numChannels; i++) {
328 this->channels.push_back(
AudioChannel(this->sampleCount));
334 char data_buffer[size_of_each_sample];
335 int size_is_correct =
true;
339 long bytes_in_each_channel = (size_of_each_sample / wave_header.
channels);
340 if ((bytes_in_each_channel * wave_header.
channels) != size_of_each_sample) {
341 cout <<
"Error: Incorrect chunk size.. " << bytes_in_each_channel
342 <<
", " << wave_header.
channels <<
", " << size_of_each_sample <<
"\n";
343 size_is_correct =
false;
346 if (size_is_correct) {
349 long high_limit = 0l;
361 low_limit = -16777216;
362 high_limit = 16777215;
365 low_limit = -2147483648;
366 high_limit = 2147483647;
369 for (
int sample = 0; sample < this->sampleCount;
372 if (!infile.fail()) {
373 for (
int ch = 0; ch < wave_header.
channels;
376 infile.read(data_buffer, bytes_in_each_channel);
379 switch (bytes_in_each_channel) {
381 amplitude = data_buffer[0] & 0x00ff;
386 (data_buffer[0] & 0x00ff) |
387 (data_buffer[1] << 8);
391 (data_buffer[0] & 0x00ff) |
392 ((data_buffer[1] & 0x00ff) << 8) |
393 (data_buffer[2] << 16);
397 (data_buffer[0] & 0x00ff) |
398 ((data_buffer[1] & 0x00ff) << 8) |
399 ((data_buffer[2] & 0x00ff) << 16) |
400 (data_buffer[3] << 24);
403 this->setSample(ch, sample, amplitude);
407 cout <<
"Error reading file\n.";
425 infile.read ((
char *)wave_header.
riff, 4);
427 if (wave_header.
riff[0] !=
'R' ||
428 wave_header.
riff[1] !=
'I' ||
429 wave_header.
riff[2] !=
'F' ||
430 wave_header.
riff[3] !=
'F')
431 throw "malformed RIFF header";
434 unsigned char *buffer =
new unsigned char[4];
435 infile.read ((
char*) buffer, 4);
438 wave_header.
overall_size = buffer[0] | (buffer[1] << 8) |
439 (buffer[2] << 16) | (buffer[3] << 24);
442 std::cout <<
"overall size: " << wave_header.
overall_size << std::endl;
444 infile.read ((
char*) wave_header.
wave, 4);
446 if (wave_header.
wave[0] !=
'W' ||
447 wave_header.
wave[1] !=
'A' ||
448 wave_header.
wave[2] !=
'V' ||
449 wave_header.
wave[3] !=
'E')
450 throw "format is not WAVE";
458 throw "malformed wave file";
461 infile.read ((
char *) buffer, 4);
463 (buffer[2] << 16) | (buffer[3] << 24);
466 std::cout <<
"length of format: " << wave_header.
length_of_fmt << std::endl;
468 char *buffer2 =
new char[2];
469 infile.read (buffer2, 2);
470 wave_header.
format_type = buffer2[0] | (buffer2[1] << 8);
472 string format_name =
"";
478 format_name =
"A-law";
481 format_name =
"Mu-law";
484 throw "unsupported format";
488 infile.read (buffer2, 2);
489 wave_header.
channels = buffer2[0] | (buffer2[1] << 8);
490 this->numChannels = wave_header.
channels;
493 std::cout <<
"numChannels: " << numChannels << std::endl;
496 infile.read ((
char *) buffer, 4);
497 wave_header.
sample_rate = buffer[0] | (buffer[1] << 8) |
498 (buffer[2] << 16) | (buffer[3] << 24);
502 std::cout <<
"sampleRate: " << sampleRate << std::endl;
504 infile.read ((
char *) buffer, 4);
505 wave_header.
byterate = buffer[0] | (buffer[1] << 8) |
506 (buffer[2] << 16) | (buffer[3] << 24);
509 std::cout <<
"byte rate: " << wave_header.
byterate << std::endl;
511 infile.read (buffer2, 2);
512 wave_header.
block_align = buffer2[0] | (buffer2[1] << 8);
514 infile.read (buffer2, 2);
520 std::cout <<
"sample Bits: " << sampleBits << std::endl;
524 throw "malformed wave file";
529 bool data_chunk_found =
false;
530 while (!data_chunk_found) {
533 infile.read ((
char *) buffer, 4);
534 wave_header.
data_size = buffer[0] | (buffer[1] << 8) |
535 (buffer[2] << 16) | (buffer[3] << 24);
542 int padding = (wave_header.
data_size % 2 ? 0 : 1);
543 infile.ignore(wave_header.
data_size + padding);
546 data_chunk_found =
true;
552 long num_samples = (8 * wave_header.
data_size) /
554 this->sampleCount = num_samples;
557 std::cout <<
"sample Count: " << this->sampleCount << std::endl;
561 long size_of_each_sample = (wave_header.
channels *
570 throw "malformed RIFF header";
virtual const string getDataStructureRepresentation() const override final
Definition: AudioClip.h:174
This is the superclass of all data structure types in BRIDGES.
Definition: DataStructure.h:73
string encode(BYTE const *buf, unsigned int bufLen)
Definition: base64.h:59
const string COLON
Definition: DataStructure.h:51
class that represents an audio channel.
Definition: AudioChannel.h:9
virtual const string getDStype() const override
Definition: AudioClip.h:159
This class provides support for reading, modifying, and playing audio waveforms.
Definition: AudioClip.h:101
const string CLOSE_CURLY
Definition: DataStructure.h:53
int getSampleCount() const
returns the number of samples in the clip
Definition: AudioClip.h:246
AudioClip(int sampleCount, int numChannels, int sampleBits, int sampleRate)
create an audio clip
Definition: AudioClip.h:123
AudioClip(const string &wave_file)
create an audio clip from a File
Definition: AudioClip.h:169
these methods convert byte arrays in to base64 codes and are used in BRIDGES to represent the color a...
Definition: alltypes.h:4
int getSampleBits() const
returns the sampling depth.
Definition: AudioClip.h:264
void setSample(int channelIndex, int sampleIndex, int value)
change a particular sample
Definition: AudioClip.h:288
int getSampleRate() const
returns the sampling rate of the clip
Definition: AudioClip.h:235
const string COMMA
Definition: DataStructure.h:50
const string QUOTE
Definition: DataStructure.h:49
int getSample(int channelIndex, int sampleIndex) const
access a particular sample
Definition: AudioClip.h:277
int getNumChannels() const
returns the number of channels of the clip
Definition: AudioClip.h:227
std::string JSONencode(const T &d)
Definition: JSONutil.h:37