-
Notifications
You must be signed in to change notification settings - Fork 8
/
sounds.h
76 lines (61 loc) · 2.74 KB
/
sounds.h
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
#include <cmath>
#include <fstream>
#include <iostream>
using namespace std;
//Adapted from http://www.cplusplus.com/forum/beginner/166954/
namespace little_endian_io {
template <typename Word>
std::ostream& write_word( std::ostream& outs, Word value, unsigned size = sizeof( Word ) ) {
for( ; size; --size, value >>= 8 ) // value >>= 1 means "set value to itself shifted by one bit to the right".
outs.put( static_cast <char> ( value & 0xFF ) );
return outs;
}
}
using namespace little_endian_io;
void output_sounds( uint8_t* notes, int notes_n ) {
ofstream f( "output.wav", ios::binary );
// Write the file headers
f << "RIFF----WAVEfmt "; // (chunk size to be filled in later)
write_word( f, 16, 4 ); // no extension data
write_word( f, 1, 2 ); // PCM - integer samples
write_word( f, 2, 2 ); // two channels (stereo file)
write_word( f, 44100, 4 ); // samples per second (Hz)
write_word( f, 176400, 4 ); // (Sample Rate * BitsPerSample * Channels) / 8
write_word( f, 4, 2 ); // data block size (size of two integer samples, one for each channel, in bytes)
write_word( f, 16, 2 ); // number of bits per sample (use a multiple of 8)
// Write the data chunk header
size_t data_chunk_pos = f.tellp();
f << "data----"; // (chunk size to be filled in later)
// Write the audio samples
double two_pi = 6.283185307179586476925286766559;
double max_amplitude = 32760; // "volume"
double hz = 44100; // samples per second
double frequency = 110; // A2 (25th note)
double seconds = 0.5; // time
int N = hz * seconds; // total number of samples
for (int n = 0; n < N; n++) {
double c_amplitude = max_amplitude*notes[0]/255.0;
double amplitude = (double)n / N * c_amplitude;
double value = sin( (two_pi * n * frequency) / hz );
write_word( f, (int)( amplitude * value), 2 );
write_word( f, (int)((c_amplitude - amplitude) * value), 2 ); //MAX_ O C_
}
for( int i = 1; i < notes_n; i++ ) {
frequency *= pow( 2, 1.0/12 );
double c_amplitude = max_amplitude*notes[i]/255.0;
for (int n = 0; n < N; n++) {
double amplitude = (double)n / N * c_amplitude;
double value = sin( (two_pi * n * frequency) / hz );
write_word( f, (int)( amplitude * value), 2 );
write_word( f, (int)((c_amplitude - amplitude) * value), 2 ); //MAX_ O C_
}
}
// (We'll need the final file size to fix the chunk sizes above)
size_t file_length = f.tellp();
// Fix the data chunk header to contain the data size
f.seekp( data_chunk_pos + 4 );
write_word( f, file_length - data_chunk_pos + 8 );
// Fix the file header to contain the proper RIFF chunk size, which is (file size - 8) bytes
f.seekp( 0 + 4 );
write_word( f, file_length - 8, 4 );
}