1// Copyright 2017 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <zircon/assert.h> 6#include <math.h> 7#include <fbl/algorithm.h> 8#include <fbl/limits.h> 9 10#include "sine-source.h" 11 12zx_status_t SineSource::Init(float freq, 13 float amp, 14 float duration_secs, 15 uint32_t frame_rate, 16 uint32_t channels, 17 audio_sample_format_t sample_format) { 18 19 if (!frame_rate) 20 return ZX_ERR_INVALID_ARGS; 21 22 if (!channels) 23 return ZX_ERR_INVALID_ARGS; 24 25 frame_rate_ = frame_rate; 26 channels_ = channels; 27 28 frames_to_produce_ = (duration_secs == 0.0) 29 ? fbl::numeric_limits<uint64_t>::max() 30 : static_cast<uint64_t>(duration_secs * static_cast<float>(frame_rate_)); 31 sine_scalar_ = (freq * 2.0 * M_PI) / frame_rate_; 32 amp_ = fbl::clamp<double>(amp, 0.0, 1.0); 33 34 switch(static_cast<audio_sample_format_t>(sample_format & ~AUDIO_SAMPLE_FORMAT_FLAG_MASK)) { 35 case AUDIO_SAMPLE_FORMAT_8BIT: return InitInternal<AUDIO_SAMPLE_FORMAT_8BIT>(); 36 case AUDIO_SAMPLE_FORMAT_16BIT: return InitInternal<AUDIO_SAMPLE_FORMAT_16BIT>(); 37 case AUDIO_SAMPLE_FORMAT_20BIT_IN32: return InitInternal<AUDIO_SAMPLE_FORMAT_20BIT_IN32>(); 38 case AUDIO_SAMPLE_FORMAT_24BIT_IN32: return InitInternal<AUDIO_SAMPLE_FORMAT_24BIT_IN32>(); 39 case AUDIO_SAMPLE_FORMAT_32BIT: return InitInternal<AUDIO_SAMPLE_FORMAT_32BIT>(); 40 default: return ZX_ERR_INVALID_ARGS; 41 } 42} 43 44zx_status_t SineSource::GetFormat(Format* out_format) { 45 if (out_format == nullptr) 46 return ZX_ERR_INVALID_ARGS; 47 48 out_format->frame_rate = frame_rate_; 49 out_format->channels = static_cast<uint16_t>(channels_); 50 out_format->sample_format = sample_format_; 51 52 return ZX_OK; 53} 54 55zx_status_t SineSource::GetFrames(void* buffer, uint32_t buf_space, uint32_t* out_packed) { 56 ZX_DEBUG_ASSERT(get_frames_thunk_ != nullptr); 57 return ((*this).*(get_frames_thunk_))(buffer, buf_space, out_packed); 58} 59 60namespace { 61 62template <audio_sample_format_t SAMPLE_FORMAT> 63struct SampleTraits; 64 65template <> 66struct SampleTraits<AUDIO_SAMPLE_FORMAT_8BIT> { 67 using SampleType = uint8_t; 68 using ComputedType = int8_t; 69 static SampleType encode(ComputedType v) { 70 return static_cast<ComputedType>(static_cast<SampleType>(v) + 0x80); 71 } 72}; 73 74template <> 75struct SampleTraits<AUDIO_SAMPLE_FORMAT_16BIT> { 76 using SampleType = int16_t; 77 using ComputedType = int16_t; 78 static SampleType encode(ComputedType v) { return v; } 79}; 80 81template <> 82struct SampleTraits<AUDIO_SAMPLE_FORMAT_20BIT_IN32> { 83 using SampleType = int32_t; 84 using ComputedType = int32_t; 85 static SampleType encode(ComputedType v) { 86 return static_cast<SampleType>(static_cast<uint32_t>(v) & 0xFFFFF000); 87 } 88}; 89 90template <> 91struct SampleTraits<AUDIO_SAMPLE_FORMAT_24BIT_IN32> { 92 using SampleType = int32_t; 93 using ComputedType = int32_t; 94 static SampleType encode(ComputedType v) { 95 return static_cast<SampleType>(static_cast<uint32_t>(v) & 0xFFFFFF00); 96 } 97}; 98 99template <> 100struct SampleTraits<AUDIO_SAMPLE_FORMAT_32BIT> { 101 using SampleType = int32_t; 102 using ComputedType = int32_t; 103 static SampleType encode(ComputedType v) { return v; } 104}; 105 106} // Anon namespace 107 108template <audio_sample_format_t SAMPLE_FORMAT> 109zx_status_t SineSource::InitInternal() { 110 using SampleType = typename SampleTraits<SAMPLE_FORMAT>::SampleType; 111 using ComputedType = typename SampleTraits<SAMPLE_FORMAT>::ComputedType; 112 113 sample_format_ = SAMPLE_FORMAT; 114 get_frames_thunk_ = &SineSource::GetFramesInternal<SAMPLE_FORMAT>; 115 frame_size_ = static_cast<uint32_t>(sizeof(SampleType) * channels_); 116 amp_ *= fbl::numeric_limits<ComputedType>::max() - 1; 117 118 return ZX_OK; 119} 120 121template <audio_sample_format_t SAMPLE_FORMAT> 122zx_status_t SineSource::GetFramesInternal(void* buffer, uint32_t buf_space, uint32_t* out_packed) { 123 using Traits = SampleTraits<SAMPLE_FORMAT>; 124 using SampleType = typename SampleTraits<SAMPLE_FORMAT>::SampleType; 125 using ComputedType = typename SampleTraits<SAMPLE_FORMAT>::ComputedType; 126 127 if ((buffer == nullptr) || (out_packed == nullptr)) 128 return ZX_ERR_INVALID_ARGS; 129 130 if (finished()) 131 return ZX_ERR_BAD_STATE; 132 133 ZX_DEBUG_ASSERT(frames_produced_ < frames_to_produce_); 134 uint64_t todo = fbl::min<uint64_t>(frames_to_produce_ - frames_produced_, 135 buf_space / frame_size_); 136 double pos = sine_scalar_ * static_cast<double>(frames_produced_); 137 auto buf = reinterpret_cast<SampleType*>(buffer); 138 139 for (uint64_t i = 0; i < todo; ++i) { 140 auto val = static_cast<ComputedType>(amp_ * sin(pos)); 141 142 for (uint32_t j = 0; j < channels_; ++j) 143 *(buf++) = Traits::encode(val); 144 145 pos += sine_scalar_; 146 } 147 148 *out_packed = static_cast<uint32_t>(todo * frame_size_); 149 frames_produced_ += todo; 150 151 return ZX_OK; 152} 153