Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice, this
10 * list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "AudioEngine.h"
29#include <LibAudio/WavLoader.h>
30#include <limits>
31#include <math.h>
32
33AudioEngine::AudioEngine()
34{
35 set_sustain_impl(1000);
36 set_attack(5);
37 set_decay(1000);
38 set_release(5);
39}
40
41AudioEngine::~AudioEngine()
42{
43}
44
45void AudioEngine::fill_buffer(FixedArray<Sample>& buffer)
46{
47 memset(buffer.data(), 0, buffer_size);
48
49 for (size_t i = 0; i < buffer.size(); ++i) {
50 for (size_t note = 0; note < note_count; ++note) {
51 if (!m_roll_iters[note].is_end()) {
52 if (m_roll_iters[note]->on_sample == m_time) {
53 set_note(note, On);
54 } else if (m_roll_iters[note]->off_sample == m_time) {
55 set_note(note, Off);
56 ++m_roll_iters[note];
57 if (m_roll_iters[note].is_end())
58 m_roll_iters[note] = m_roll_notes[note].begin();
59 }
60 }
61
62 switch (m_envelope[note]) {
63 case Done:
64 continue;
65 case Attack:
66 m_power[note] += m_attack_step;
67 if (m_power[note] >= 1) {
68 m_power[note] = 1;
69 m_envelope[note] = Decay;
70 }
71 break;
72 case Decay:
73 m_power[note] -= m_decay_step;
74 if (m_power[note] < m_sustain_level)
75 m_power[note] = m_sustain_level;
76 break;
77 case Release:
78 m_power[note] -= m_release_step[note];
79 if (m_power[note] <= 0) {
80 m_power[note] = 0;
81 m_envelope[note] = Done;
82 continue;
83 }
84 break;
85 default:
86 ASSERT_NOT_REACHED();
87 }
88
89 Audio::Sample sample;
90 switch (m_wave) {
91 case Wave::Sine:
92 sample = sine(note);
93 break;
94 case Wave::Saw:
95 sample = saw(note);
96 break;
97 case Wave::Square:
98 sample = square(note);
99 break;
100 case Wave::Triangle:
101 sample = triangle(note);
102 break;
103 case Wave::Noise:
104 sample = noise();
105 break;
106 case Wave::RecordedSample:
107 sample = recorded_sample(note);
108 break;
109 default:
110 ASSERT_NOT_REACHED();
111 }
112 buffer[i].left += sample.left * m_power[note] * volume;
113 buffer[i].right += sample.right * m_power[note] * volume;
114 }
115
116 if (m_delay) {
117 buffer[i].left += m_delay_buffer[m_delay_index].left * 0.333333;
118 buffer[i].right += m_delay_buffer[m_delay_index].right * 0.333333;
119 m_delay_buffer[m_delay_index].left = buffer[i].left;
120 m_delay_buffer[m_delay_index].right = buffer[i].right;
121 if (++m_delay_index >= m_delay_samples)
122 m_delay_index = 0;
123 }
124
125 if (++m_time >= roll_length) {
126 m_time = 0;
127 if (!m_should_loop)
128 break;
129 }
130 }
131
132 memcpy(m_back_buffer_ptr->data(), buffer.data(), buffer_size);
133 swap(m_front_buffer_ptr, m_back_buffer_ptr);
134}
135
136void AudioEngine::reset()
137{
138 memset(m_front_buffer.data(), 0, buffer_size);
139 memset(m_back_buffer.data(), 0, buffer_size);
140 m_front_buffer_ptr = &m_front_buffer;
141 m_back_buffer_ptr = &m_back_buffer;
142
143 memset(m_delay_buffer.data(), 0, m_delay_buffer.size() * sizeof(Sample));
144 m_delay_index = 0;
145
146 memset(m_note_on, 0, sizeof(m_note_on));
147 memset(m_power, 0, sizeof(m_power));
148 memset(m_envelope, 0, sizeof(m_envelope));
149
150 m_time = 0;
151}
152
153String AudioEngine::set_recorded_sample(const StringView& path)
154{
155 Audio::WavLoader wav_loader(path);
156 if (wav_loader.has_error())
157 return String(wav_loader.error_string());
158 auto wav_buffer = wav_loader.get_more_samples(60 * sample_rate * sizeof(Sample)); // 1 minute maximum
159
160 if (!m_recorded_sample.is_empty())
161 m_recorded_sample.clear();
162 m_recorded_sample.resize(wav_buffer->sample_count());
163
164 double peak = 0;
165 for (int i = 0; i < wav_buffer->sample_count(); ++i) {
166 double left_abs = fabs(wav_buffer->samples()[i].left);
167 double right_abs = fabs(wav_buffer->samples()[i].right);
168 if (left_abs > peak)
169 peak = left_abs;
170 if (right_abs > peak)
171 peak = right_abs;
172 }
173
174 if (peak) {
175 for (int i = 0; i < wav_buffer->sample_count(); ++i) {
176 m_recorded_sample[i].left = wav_buffer->samples()[i].left / peak;
177 m_recorded_sample[i].right = wav_buffer->samples()[i].right / peak;
178 }
179 }
180
181 return String::empty();
182}
183
184// All of the information for these waves is on Wikipedia.
185
186Audio::Sample AudioEngine::sine(size_t note)
187{
188 double pos = note_frequencies[note] / sample_rate;
189 double sin_step = pos * 2 * M_PI;
190 double w = sin(m_pos[note]);
191 m_pos[note] += sin_step;
192 return w;
193}
194
195Audio::Sample AudioEngine::saw(size_t note)
196{
197 double saw_step = note_frequencies[note] / sample_rate;
198 double t = m_pos[note];
199 double w = (0.5 - (t - floor(t))) * 2;
200 m_pos[note] += saw_step;
201 return w;
202}
203
204Audio::Sample AudioEngine::square(size_t note)
205{
206 double pos = note_frequencies[note] / sample_rate;
207 double square_step = pos * 2 * M_PI;
208 double w = sin(m_pos[note]) >= 0 ? 1 : -1;
209 m_pos[note] += square_step;
210 return w;
211}
212
213Audio::Sample AudioEngine::triangle(size_t note)
214{
215 double triangle_step = note_frequencies[note] / sample_rate;
216 double t = m_pos[note];
217 double w = fabs(fmod((4 * t) + 1, 4) - 2) - 1;
218 m_pos[note] += triangle_step;
219 return w;
220}
221
222Audio::Sample AudioEngine::noise() const
223{
224 double random_percentage = static_cast<double>(rand()) / RAND_MAX;
225 double w = (random_percentage * 2) - 1;
226 return w;
227}
228
229Audio::Sample AudioEngine::recorded_sample(size_t note)
230{
231 int t = m_pos[note];
232 if (t >= static_cast<int>(m_recorded_sample.size()))
233 return 0;
234 double w_left = m_recorded_sample[t].left;
235 double w_right = m_recorded_sample[t].right;
236 if (t + 1 < static_cast<int>(m_recorded_sample.size())) {
237 double t_fraction = m_pos[note] - t;
238 w_left += (m_recorded_sample[t + 1].left - m_recorded_sample[t].left) * t_fraction;
239 w_right += (m_recorded_sample[t + 1].right - m_recorded_sample[t].right) * t_fraction;
240 }
241 double recorded_sample_step = note_frequencies[note] / middle_c;
242 m_pos[note] += recorded_sample_step;
243 return { w_left, w_right };
244}
245
246static inline double calculate_step(double distance, int milliseconds)
247{
248 if (milliseconds == 0)
249 return distance;
250
251 constexpr double samples_per_millisecond = sample_rate / 1000.0;
252 double samples = milliseconds * samples_per_millisecond;
253 double step = distance / samples;
254 return step;
255}
256
257void AudioEngine::set_note(int note, Switch switch_note)
258{
259 ASSERT(note >= 0 && note < note_count);
260
261 if (switch_note == On) {
262 if (m_note_on[note] == 0) {
263 m_pos[note] = 0;
264 m_envelope[note] = Attack;
265 }
266 ++m_note_on[note];
267 } else {
268 if (m_note_on[note] >= 1) {
269 if (m_note_on[note] == 1) {
270 m_release_step[note] = calculate_step(m_power[note], m_release);
271 m_envelope[note] = Release;
272 }
273 --m_note_on[note];
274 }
275 }
276
277 ASSERT(m_note_on[note] != std::numeric_limits<u8>::max());
278 ASSERT(m_power[note] >= 0);
279}
280
281void AudioEngine::set_note_current_octave(int note, Switch switch_note)
282{
283 set_note(note + octave_base(), switch_note);
284}
285
286void AudioEngine::sync_roll(int note)
287{
288 auto it = m_roll_notes[note].find([&](auto& roll_note) { return roll_note.off_sample > m_time; });
289 if (it.is_end())
290 m_roll_iters[note] = m_roll_notes[note].begin();
291 else
292 m_roll_iters[note] = it;
293}
294
295void AudioEngine::set_roll_note(int note, u32 on_sample, u32 off_sample)
296{
297 RollNote new_roll_note = { on_sample, off_sample };
298
299 ASSERT(note >= 0 && note < note_count);
300 ASSERT(new_roll_note.off_sample < roll_length);
301 ASSERT(new_roll_note.length() >= 2);
302
303 for (auto it = m_roll_notes[note].begin(); !it.is_end();) {
304 if (it->on_sample > new_roll_note.off_sample) {
305 m_roll_notes[note].insert_before(it, new_roll_note);
306 sync_roll(note);
307 return;
308 }
309 if (it->on_sample == new_roll_note.on_sample && it->off_sample == new_roll_note.off_sample) {
310 if (m_time >= it->on_sample && m_time <= it->off_sample)
311 set_note(note, Off);
312 m_roll_notes[note].remove(it);
313 sync_roll(note);
314 return;
315 }
316 if ((new_roll_note.on_sample == 0 || it->on_sample >= new_roll_note.on_sample - 1) && it->on_sample <= new_roll_note.off_sample) {
317 if (m_time >= new_roll_note.off_sample && m_time <= it->off_sample)
318 set_note(note, Off);
319 m_roll_notes[note].remove(it);
320 it = m_roll_notes[note].begin();
321 continue;
322 }
323 if (it->on_sample < new_roll_note.on_sample && it->off_sample >= new_roll_note.on_sample) {
324 if (m_time >= new_roll_note.off_sample && m_time <= it->off_sample)
325 set_note(note, Off);
326 it->off_sample = new_roll_note.on_sample - 1;
327 ASSERT(it->length() >= 2);
328 }
329 ++it;
330 }
331
332 m_roll_notes[note].append(new_roll_note);
333 sync_roll(note);
334}
335
336void AudioEngine::set_octave(Direction direction)
337{
338 if (direction == Up) {
339 if (m_octave < octave_max)
340 ++m_octave;
341 } else {
342 if (m_octave > octave_min)
343 --m_octave;
344 }
345}
346
347void AudioEngine::set_wave(int wave)
348{
349 ASSERT(wave >= first_wave && wave <= last_wave);
350 m_wave = wave;
351}
352
353void AudioEngine::set_wave(Direction direction)
354{
355 if (direction == Up) {
356 if (++m_wave > last_wave)
357 m_wave = first_wave;
358 } else {
359 if (--m_wave < first_wave)
360 m_wave = last_wave;
361 }
362}
363
364void AudioEngine::set_attack(int attack)
365{
366 ASSERT(attack >= 0);
367 m_attack = attack;
368 m_attack_step = calculate_step(1, m_attack);
369}
370
371void AudioEngine::set_decay(int decay)
372{
373 ASSERT(decay >= 0);
374 m_decay = decay;
375 m_decay_step = calculate_step(1 - m_sustain_level, m_decay);
376}
377
378void AudioEngine::set_sustain_impl(int sustain)
379{
380 ASSERT(sustain >= 0);
381 m_sustain = sustain;
382 m_sustain_level = sustain / 1000.0;
383}
384
385void AudioEngine::set_sustain(int sustain)
386{
387 set_sustain_impl(sustain);
388 set_decay(m_decay);
389}
390
391void AudioEngine::set_release(int release)
392{
393 ASSERT(release >= 0);
394 m_release = release;
395}
396
397void AudioEngine::set_delay(int delay)
398{
399 ASSERT(delay >= 0);
400 m_delay = delay;
401 m_delay_samples = m_delay == 0 ? 0 : (sample_rate / (beats_per_minute / 60)) / m_delay;
402 m_delay_buffer.resize(m_delay_samples);
403 memset(m_delay_buffer.data(), 0, m_delay_buffer.size() * sizeof(Sample));
404 m_delay_index = 0;
405}