Serenity Operating System
at hosted 146 lines 4.4 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#pragma once 28 29#include <AK/ByteBuffer.h> 30#include <AK/SharedBuffer.h> 31#include <AK/Types.h> 32#include <AK/Vector.h> 33#include <string.h> 34 35namespace Audio { 36 37// A single sample in an audio buffer. 38// Values are floating point, and should range from -1.0 to +1.0 39struct Sample { 40 Sample() 41 : left(0) 42 , right(0) 43 { 44 } 45 46 // For mono 47 Sample(double left) 48 : left(left) 49 , right(left) 50 { 51 } 52 53 // For stereo 54 Sample(double left, double right) 55 : left(left) 56 , right(right) 57 { 58 } 59 60 void clip() 61 { 62 if (left > 1) 63 left = 1; 64 else if (left < -1) 65 left = -1; 66 67 if (right > 1) 68 right = 1; 69 else if (right < -1) 70 right = -1; 71 } 72 73 void scale(int percent) 74 { 75 double pct = (double)percent / 100.0; 76 left *= pct; 77 right *= pct; 78 } 79 80 Sample& operator+=(const Sample& other) 81 { 82 left += other.left; 83 right += other.right; 84 return *this; 85 } 86 87 double left; 88 double right; 89}; 90 91// Small helper to resample from one playback rate to another 92// This isn't really "smart", in that we just insert (or drop) samples. 93// Should do better... 94class ResampleHelper { 95public: 96 ResampleHelper(double source, double target); 97 98 void process_sample(double sample_l, double sample_r); 99 bool read_sample(double& next_l, double& next_r); 100 101private: 102 const double m_ratio; 103 double m_current_ratio { 0 }; 104 double m_last_sample_l { 0 }; 105 double m_last_sample_r { 0 }; 106}; 107 108// A buffer of audio samples, normalized to 44100hz. 109class Buffer : public RefCounted<Buffer> { 110public: 111 static RefPtr<Buffer> from_pcm_data(ByteBuffer& data, ResampleHelper& resampler, int num_channels, int bits_per_sample); 112 static NonnullRefPtr<Buffer> create_with_samples(Vector<Sample>&& samples) 113 { 114 return adopt(*new Buffer(move(samples))); 115 } 116 static NonnullRefPtr<Buffer> create_with_shared_buffer(NonnullRefPtr<SharedBuffer>&& buffer, int sample_count) 117 { 118 return adopt(*new Buffer(move(buffer), sample_count)); 119 } 120 121 const Sample* samples() const { return (const Sample*)data(); } 122 int sample_count() const { return m_sample_count; } 123 const void* data() const { return m_buffer->data(); } 124 int size_in_bytes() const { return m_sample_count * (int)sizeof(Sample); } 125 int shbuf_id() const { return m_buffer->shbuf_id(); } 126 SharedBuffer& shared_buffer() { return *m_buffer; } 127 128private: 129 explicit Buffer(Vector<Sample>&& samples) 130 : m_buffer(*SharedBuffer::create_with_size(samples.size() * sizeof(Sample))) 131 , m_sample_count(samples.size()) 132 { 133 memcpy(m_buffer->data(), samples.data(), samples.size() * sizeof(Sample)); 134 } 135 136 explicit Buffer(NonnullRefPtr<SharedBuffer>&& buffer, int sample_count) 137 : m_buffer(move(buffer)) 138 , m_sample_count(sample_count) 139 { 140 } 141 142 NonnullRefPtr<SharedBuffer> m_buffer; 143 const int m_sample_count; 144}; 145 146}