-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathwavfilewriter.cpp
More file actions
143 lines (126 loc) · 3.94 KB
/
wavfilewriter.cpp
File metadata and controls
143 lines (126 loc) · 3.94 KB
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include "wavfilewriter.h"
#include <vector>
#include <fstream>
#include <cmath>
using namespace std;
//Structs for WAVFileWriter::writeToFile
struct RIFF_Header
{
int8_t chunkID[4];
int32_t chunkSize;
int8_t format[4];
};
struct WAVE_Format
{
int8_t subChunkID[4];
int32_t subChunkSize;
int16_t audioFormat;
int16_t numChannels;
int32_t sampleRate;
int32_t byteRate;
int16_t blockAlign;
int16_t bitsPerSample;
};
struct WAVE_Data
{
int8_t subChunkID[4];
int32_t subChunkSize;
};
//Helper function that uses the current tempo and offset to create WAV data for a Voice
vector<sample_t> WAVFileWriter::convertVoiceToSamples(const Voice& v)
{
vector<sample_t> samples;
const vector<Note>& notes = v.getNotes();
const instrument_t& inst = v.getInstrument();
double norm = 0.0;
for (int i = 0; i < inst.size(); i++)
norm += inst[i];
for (int n = 0; n < notes.size(); n++)
{
double freq = FREQUENCY[notes[n].getPitch()] / (1 << (OCTAVE_OFFSET - notes[n].getOctave()));
double delta = 2 * M_PI * freq / SAMPLE_RATE;
int num_samples = notes[n].getDuration() * SECONDS_PER_MINUTE * SAMPLE_RATE / tempo + EPSILON;
for (int i = 0; i < num_samples; i++)
{
double s = 0.0;
for (int j = 0; j < inst.size(); j++)
s += inst[j] * sin((j+1) * i * delta);
samples.push_back(static_cast<sample_t>(v.getVolume() * s / norm));
}
}
return samples;
}
//Sets the song to be written
//Clears any current audio data
void WAVFileWriter::setSong(const Song& s)
{
sample_data.clear();
tempo = s.getTempo();
const vector<Voice>& voices = s.getVoices();
for (int i = 0; i < voices.size(); i++)
addVoice(voices[i]);
}
//Adds a voice to the audio data, using the current tempo
void WAVFileWriter::addVoice(const Voice& v)
{
offset = 0.0;
vector<sample_t> samples = convertVoiceToSamples(v);
int min = sample_data.size();
if (samples.size() < min)
min = samples.size();
for (int i = 0; i < min; i++)
sample_data[i] += samples[i];
for (int i = min; i < samples.size(); i++)
sample_data.push_back(samples[i]);
}
//Removes a voice from the audio data
void WAVFileWriter::removeVoice(const Voice& v)
{
offset = 0.0;
vector<sample_t> samples = convertVoiceToSamples(v);
int min = sample_data.size();
if (samples.size() < min)
min = samples.size();
for (int i = 0; i < min; i++)
sample_data[i] -= samples[i];
for (int i = min; i < samples.size(); i++)
sample_data.push_back(-samples[i]);
}
//Writes the current audio data to file
void WAVFileWriter::writeToFile() const
{
struct WAVE_Data datahead;
datahead.subChunkID[0] = 'd';
datahead.subChunkID[1] = 'a';
datahead.subChunkID[2] = 't';
datahead.subChunkID[3] = 'a';
datahead.subChunkSize = sample_data.size() * BYTES_PER_SAMPLE;
struct WAVE_Format fmt;
fmt.subChunkID[0] = 'f';
fmt.subChunkID[1] = 'm';
fmt.subChunkID[2] = 't';
fmt.subChunkID[3] = ' ';
fmt.subChunkSize = 16;
fmt.audioFormat = 1;
fmt.numChannels = NUM_CHANNELS;
fmt.sampleRate = SAMPLE_RATE;
fmt.byteRate = NUM_CHANNELS * BYTES_PER_SAMPLE;
fmt.blockAlign = SAMPLE_RATE * NUM_CHANNELS;
fmt.bitsPerSample = BYTES_PER_SAMPLE * BITS_PER_BYTE;
struct RIFF_Header fileheader;
fileheader.chunkID[0] = 'R';
fileheader.chunkID[1] = 'I';
fileheader.chunkID[2] = 'F';
fileheader.chunkID[3] = 'F';
fileheader.chunkSize = 36 + datahead.subChunkSize;
fileheader.format[0] = 'W';
fileheader.format[1] = 'A';
fileheader.format[2] = 'V';
fileheader.format[3] = 'E';
ofstream out(filename, ios::binary);
out.write((const char*) &fileheader, sizeof(struct RIFF_Header));
out.write((const char*) &fmt, sizeof(struct WAVE_Format));
out.write((const char*) &datahead, sizeof(struct WAVE_Data));
out.write((const char*) sample_data.data(), sample_data.size() * BYTES_PER_SAMPLE);
out.close();
}