Serenity Operating System
at hosted 405 lines 13 kB view raw
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}