-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexample.cpp
135 lines (120 loc) · 4.18 KB
/
example.cpp
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
#include <fstream>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include "sf2.hpp"
#define SAMPLE_RATE 16000
enum WAV_FormatTag : uint16_t
{
WAVE_FORMAT_PCM = 0x0001,
WAVE_FORMAT_IEEE_FLOAT = 0x0003,
WAVE_FORMAT_ALAW = 0x0006,
WAVE_FORMAT_MULAW = 0x0007,
WAVE_FORMAT_EXTENSIBLE = 0xFFFE
};
struct WAV_Header {
//RIFF chunk
uint8_t RIFF_ckID[4] = { 'R', 'I', 'F', 'F' };
uint32_t RIFF_cksize;
uint8_t RIFF_WAVEID[4] = { 'W', 'A', 'V', 'E' };
//fmt subchunk
uint8_t fmt_ckID[4] = { 'f', 'm', 't', ' ' };
uint32_t fmt_cksize = 16;
uint16_t fmt_wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
uint16_t fmt_nChannels = 2;
uint32_t fmt_nSamplesPerSec = SAMPLE_RATE;
uint32_t fmt_nAvgBytesPerSec = SAMPLE_RATE*fmt_nChannels*sizeof(float);
uint16_t fmt_nBlockAlign = fmt_nChannels*sizeof(float);
uint16_t fmt_wBitsPerSample = 8*sizeof(float);
//data subchunk
uint8_t data_ckID[4] = { 'd', 'a', 't', 'a' };
uint32_t data_cksize;
};
int main(int argc, char *argv[]) {
static_assert(sizeof(WAV_Header) == 44, "");
if(argc <= 1)
{
std::cerr << "must specify a path to sf2 file" << std::endl;
return EXIT_FAILURE;
}
std::string sf_path(argv[1]);
//setup RIFF parser and parse the soundfont
RIFF::stream stream;
stream.src = nullptr;
stream.func_read_ptr = [](void* src, void* dest, size_t size)->size_t
{
static_cast<std::ifstream*>(src)->read((char*)dest, size);
return static_cast<std::ifstream*>(src)->gcount();
};
stream.func_skip_ptr = [](void* src, size_t size)->size_t
{
static_cast<std::ifstream*>(src)->ignore(size);
return static_cast<std::ifstream*>(src)->gcount();
};
stream.func_getpos_ptr = [](void* src)->size_t
{
return static_cast<std::ifstream*>(src)->tellg();
};
stream.func_setpos_ptr = [](void* src, size_t pos)
{
static_cast<std::ifstream*>(src)->clear();
static_cast<std::ifstream*>(src)->seekg(pos, static_cast<std::ifstream*>(src)->beg);
};
RIFF::RIFF riff;
auto file = std::make_unique<std::ifstream>(sf_path, std::ios::binary);
stream.src = file.get();
riff.parse(stream, false);
//setup soundfont synthesizer and 1 channel
SF2::SoundFont2 sf(&riff, &stream);
SF2::SoundFont2::Channel channel;
channel.sf = &sf;
channel.SetPreset(0, 0);
//allocate output data
uint32_t
buffer_frames = 512,
num_buffers_hold = 90,
num_buffers_release = 10,
channel_num_samples = buffer_frames*(num_buffers_hold+num_buffers_release);
std::vector<float> output;
output.resize(channel_num_samples*2);
//play C major chord
channel.NoteOn(60, 127, SAMPLE_RATE);
channel.NoteOn(64, 127, SAMPLE_RATE);
channel.NoteOn(67, 127, SAMPLE_RATE);
//render 2-channel float data with keys held
channel.Render(
output.data(),
output.data()+channel_num_samples,
buffer_frames*num_buffers_hold,
SAMPLE_RATE
);
//release keys
channel.NoteOff(60);
channel.NoteOff(64);
channel.NoteOff(67);
//render the rest of the data with keys released
channel.Render(
output.data()+buffer_frames*num_buffers_hold,
output.data()+buffer_frames*num_buffers_hold+channel_num_samples,
buffer_frames*num_buffers_release,
SAMPLE_RATE
);
//interleave data
std::vector<float> tmp_output(output.size());
std::swap(tmp_output, output);
for(size_t i = 0; i < output.size()/2; ++i)
{
output[i*2] = tmp_output[i];
output[i*2+1] = tmp_output[i+channel_num_samples];
}
//write to WAV
WAV_Header wav;
size_t data_size = output.size()*sizeof(float);
wav.RIFF_cksize = data_size + sizeof(wav) - 8;
wav.data_cksize = data_size + sizeof(wav) - 44;
std::ofstream out("output.wav", std::ios::binary);
out.write(reinterpret_cast<const char *>(&wav), sizeof(wav));
out.write(reinterpret_cast<const char *>(output.data()), data_size);
return EXIT_SUCCESS;
}