You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

103 lines
3.1KB

  1. // Copyright 2009 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. //
  16. // -----------------------------------------------------------------------------
  17. //
  18. // Audio output. Supports PWM (through a PwmOutput object) and DAC (through a
  19. // Dac object, for example the one defined in mcp492x.h).
  20. #ifndef AVRLIB_AUDIO_OUTPUT_H_
  21. #define AVRLIB_AUDIO_OUTPUT_H_
  22. #include "avrlib/base.h"
  23. #include "avrlib/avrlib.h"
  24. #include "avrlib/ring_buffer.h"
  25. namespace avrlib {
  26. enum UnderrunPolicy {
  27. EMIT_CLICK = 0,
  28. HOLD_SAMPLE = 1
  29. };
  30. template<typename OutputPort,
  31. uint8_t buffer_size_ = 32,
  32. uint8_t block_size = 16,
  33. UnderrunPolicy underrun_policy = HOLD_SAMPLE>
  34. class AudioOutput {
  35. public:
  36. AudioOutput() { }
  37. enum {
  38. buffer_size = buffer_size_,
  39. data_size = OutputPort::data_size,
  40. };
  41. typedef AudioOutput<OutputPort, buffer_size_, block_size, underrun_policy> Me;
  42. typedef typename DataTypeForSize<data_size>::Type Value;
  43. typedef RingBuffer<Me> OutputBuffer;
  44. static inline void Init() {
  45. OutputPort::Init();
  46. }
  47. static inline void Write(Value v) { while (!writable()); Overwrite(v); }
  48. static inline void Overwrite(Value v) { OutputBuffer::Overwrite(v); }
  49. static inline uint8_t writable() { return OutputBuffer::writable(); }
  50. static inline uint8_t writable_block() {
  51. return OutputBuffer::writable() >= block_size;
  52. }
  53. static inline uint8_t NonBlockingWrite(Value v) {
  54. if (!writable()) {
  55. return 0;
  56. }
  57. Overwrite(v);
  58. return 1;
  59. }
  60. static inline void DiscardSample() {
  61. OutputBuffer::ImmediateRead();
  62. }
  63. // Called from data emission interrupt.
  64. static inline void EmitSample() {
  65. if (OutputBuffer::readable()) {
  66. OutputPort::Write(Value(OutputBuffer::ImmediateRead()));
  67. } else {
  68. ++num_glitches_;
  69. if (underrun_policy == EMIT_CLICK) {
  70. // Introduces clicks to allow underruns to be easily detected.
  71. OutputPort::Write(0);
  72. }
  73. }
  74. }
  75. static inline uint8_t num_glitches() { return num_glitches_; }
  76. static inline void ResetGlitchCounter() { num_glitches_ = 0; }
  77. private:
  78. static uint8_t num_glitches_;
  79. DISALLOW_COPY_AND_ASSIGN(AudioOutput);
  80. };
  81. /* static */
  82. template<typename OutputPort, uint8_t buffer_size_, uint8_t block_size,
  83. UnderrunPolicy underrun_policy>
  84. uint8_t AudioOutput<OutputPort, buffer_size_, block_size,
  85. underrun_policy>::num_glitches_ = 0;
  86. } // namespace avrlib
  87. #endif // AVRLIB_AUDIO_OUTPUT_H_