123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- /*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2021, kleines Filmröllchen <malu.bertsch@gmail.com>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include "Buffer.h"
- #include <AK/Atomic.h>
- #include <AK/Debug.h>
- #include <AK/String.h>
- namespace Audio {
- u16 pcm_bits_per_sample(PcmSampleFormat format)
- {
- switch (format) {
- case Uint8:
- return 8;
- case Int16:
- return 16;
- case Int24:
- return 24;
- case Int32:
- case Float32:
- return 32;
- case Float64:
- return 64;
- default:
- VERIFY_NOT_REACHED();
- }
- }
- String sample_format_name(PcmSampleFormat format)
- {
- bool is_float = format == Float32 || format == Float64;
- return String::formatted("PCM {}bit {}", pcm_bits_per_sample(format), is_float ? "Float" : "LE");
- }
- i32 Buffer::allocate_id()
- {
- static Atomic<i32> next_id;
- return next_id++;
- }
- template<typename SampleReader>
- static void read_samples_from_stream(InputMemoryStream& stream, SampleReader read_sample, Vector<Frame>& samples, ResampleHelper<double>& resampler, int num_channels)
- {
- double norm_l = 0;
- double norm_r = 0;
- switch (num_channels) {
- case 1:
- for (;;) {
- while (resampler.read_sample(norm_l, norm_r)) {
- samples.append(Frame(norm_l));
- }
- norm_l = read_sample(stream);
- if (stream.handle_any_error()) {
- break;
- }
- resampler.process_sample(norm_l, norm_r);
- }
- break;
- case 2:
- for (;;) {
- while (resampler.read_sample(norm_l, norm_r)) {
- samples.append(Frame(norm_l, norm_r));
- }
- norm_l = read_sample(stream);
- norm_r = read_sample(stream);
- if (stream.handle_any_error()) {
- break;
- }
- resampler.process_sample(norm_l, norm_r);
- }
- break;
- default:
- VERIFY_NOT_REACHED();
- }
- }
- static double read_float_sample_64(InputMemoryStream& stream)
- {
- LittleEndian<double> sample;
- stream >> sample;
- return double(sample);
- }
- static double read_float_sample_32(InputMemoryStream& stream)
- {
- LittleEndian<float> sample;
- stream >> sample;
- return double(sample);
- }
- static double read_norm_sample_24(InputMemoryStream& stream)
- {
- u8 byte = 0;
- stream >> byte;
- u32 sample1 = byte;
- stream >> byte;
- u32 sample2 = byte;
- stream >> byte;
- u32 sample3 = byte;
- i32 value = 0;
- value = sample1 << 8;
- value |= (sample2 << 16);
- value |= (sample3 << 24);
- return double(value) / NumericLimits<i32>::max();
- }
- static double read_norm_sample_16(InputMemoryStream& stream)
- {
- LittleEndian<i16> sample;
- stream >> sample;
- return double(sample) / NumericLimits<i16>::max();
- }
- static double read_norm_sample_8(InputMemoryStream& stream)
- {
- u8 sample = 0;
- stream >> sample;
- return double(sample) / NumericLimits<u8>::max();
- }
- RefPtr<Buffer> Buffer::from_pcm_data(ReadonlyBytes data, ResampleHelper<double>& resampler, int num_channels, PcmSampleFormat sample_format)
- {
- InputMemoryStream stream { data };
- return from_pcm_stream(stream, resampler, num_channels, sample_format, data.size() / (pcm_bits_per_sample(sample_format) / 8));
- }
- RefPtr<Buffer> Buffer::from_pcm_stream(InputMemoryStream& stream, ResampleHelper<double>& resampler, int num_channels, PcmSampleFormat sample_format, int num_samples)
- {
- Vector<Frame> fdata;
- fdata.ensure_capacity(num_samples);
- switch (sample_format) {
- case PcmSampleFormat::Uint8:
- read_samples_from_stream(stream, read_norm_sample_8, fdata, resampler, num_channels);
- break;
- case PcmSampleFormat::Int16:
- read_samples_from_stream(stream, read_norm_sample_16, fdata, resampler, num_channels);
- break;
- case PcmSampleFormat::Int24:
- read_samples_from_stream(stream, read_norm_sample_24, fdata, resampler, num_channels);
- break;
- case PcmSampleFormat::Float32:
- read_samples_from_stream(stream, read_float_sample_32, fdata, resampler, num_channels);
- break;
- case PcmSampleFormat::Float64:
- read_samples_from_stream(stream, read_float_sample_64, fdata, resampler, num_channels);
- break;
- default:
- VERIFY_NOT_REACHED();
- }
- // We should handle this in a better way above, but for now --
- // just make sure we're good. Worst case we just write some 0s where they
- // don't belong.
- VERIFY(!stream.handle_any_error());
- return Buffer::create_with_samples(move(fdata));
- }
- template<typename SampleType>
- ResampleHelper<SampleType>::ResampleHelper(double source, double target)
- : m_ratio(source / target)
- {
- }
- template ResampleHelper<i32>::ResampleHelper(double, double);
- template ResampleHelper<double>::ResampleHelper(double, double);
- template<typename SampleType>
- Vector<SampleType> ResampleHelper<SampleType>::resample(Vector<SampleType> to_resample)
- {
- Vector<SampleType> resampled;
- resampled.ensure_capacity(to_resample.size() * m_ratio);
- for (auto sample : to_resample) {
- process_sample(sample, sample);
- while (read_sample(sample, sample))
- resampled.unchecked_append(sample);
- }
- return resampled;
- }
- template Vector<i32> ResampleHelper<i32>::resample(Vector<i32>);
- template Vector<double> ResampleHelper<double>::resample(Vector<double>);
- template<typename SampleType>
- void ResampleHelper<SampleType>::process_sample(SampleType sample_l, SampleType sample_r)
- {
- m_last_sample_l = sample_l;
- m_last_sample_r = sample_r;
- m_current_ratio += 1;
- }
- template void ResampleHelper<i32>::process_sample(i32, i32);
- template void ResampleHelper<double>::process_sample(double, double);
- template<typename SampleType>
- bool ResampleHelper<SampleType>::read_sample(SampleType& next_l, SampleType& next_r)
- {
- if (m_current_ratio > 0) {
- m_current_ratio -= m_ratio;
- next_l = m_last_sample_l;
- next_r = m_last_sample_r;
- return true;
- }
- return false;
- }
- template bool ResampleHelper<i32>::read_sample(i32&, i32&);
- template bool ResampleHelper<double>::read_sample(double&, double&);
- }
|