// Copyright 2009 Olivier Gillet. // // Author: Olivier Gillet (ol.gillet@gmail.com) // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // ----------------------------------------------------------------------------- // // Audio output. Supports PWM (through a PwmOutput object) and DAC (through a // Dac object, for example the one defined in mcp492x.h). #ifndef AVRLIB_AUDIO_OUTPUT_H_ #define AVRLIB_AUDIO_OUTPUT_H_ #include "avrlib/base.h" #include "avrlib/avrlib.h" #include "avrlib/ring_buffer.h" namespace avrlib { enum UnderrunPolicy { EMIT_CLICK = 0, HOLD_SAMPLE = 1 }; template class AudioOutput { public: AudioOutput() { } enum { buffer_size = buffer_size_, data_size = OutputPort::data_size, }; typedef AudioOutput Me; typedef typename DataTypeForSize::Type Value; typedef RingBuffer OutputBuffer; static inline void Init() { OutputPort::Init(); } static inline void Write(Value v) { while (!writable()); Overwrite(v); } static inline void Overwrite(Value v) { OutputBuffer::Overwrite(v); } static inline uint8_t writable() { return OutputBuffer::writable(); } static inline uint8_t writable_block() { return OutputBuffer::writable() >= block_size; } static inline uint8_t NonBlockingWrite(Value v) { if (!writable()) { return 0; } Overwrite(v); return 1; } static inline void DiscardSample() { OutputBuffer::ImmediateRead(); } // Called from data emission interrupt. static inline void EmitSample() { if (OutputBuffer::readable()) { OutputPort::Write(Value(OutputBuffer::ImmediateRead())); } else { ++num_glitches_; if (underrun_policy == EMIT_CLICK) { // Introduces clicks to allow underruns to be easily detected. OutputPort::Write(0); } } } static inline uint8_t num_glitches() { return num_glitches_; } static inline void ResetGlitchCounter() { num_glitches_ = 0; } private: static uint8_t num_glitches_; DISALLOW_COPY_AND_ASSIGN(AudioOutput); }; /* static */ template uint8_t AudioOutput::num_glitches_ = 0; } // namespace avrlib #endif // AVRLIB_AUDIO_OUTPUT_H_