PWM drives the speaker.
PwmOutSpeaker.cpp@3:37a886d77bae, 2018-07-24 (annotated)
- Committer:
- dkato
- Date:
- Tue Jul 24 08:31:11 2018 +0000
- Revision:
- 3:37a886d77bae
- Parent:
- 2:436529700217
Changed to be usable with EasyPlayback
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
dkato | 0:aba6e62b51a7 | 1 | /* mbed PwmOutSpeaker Library |
dkato | 0:aba6e62b51a7 | 2 | * Copyright (C) 2016 dkato |
dkato | 0:aba6e62b51a7 | 3 | * |
dkato | 0:aba6e62b51a7 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
dkato | 0:aba6e62b51a7 | 5 | * you may not use this file except in compliance with the License. |
dkato | 0:aba6e62b51a7 | 6 | * You may obtain a copy of the License at |
dkato | 0:aba6e62b51a7 | 7 | * |
dkato | 0:aba6e62b51a7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
dkato | 0:aba6e62b51a7 | 9 | * |
dkato | 0:aba6e62b51a7 | 10 | * Unless required by applicable law or agreed to in writing, software |
dkato | 0:aba6e62b51a7 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
dkato | 0:aba6e62b51a7 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
dkato | 0:aba6e62b51a7 | 13 | * See the License for the specific language governing permissions and |
dkato | 0:aba6e62b51a7 | 14 | * limitations under the License. |
dkato | 0:aba6e62b51a7 | 15 | */ |
dkato | 0:aba6e62b51a7 | 16 | |
dkato | 0:aba6e62b51a7 | 17 | #include "PwmOutSpeaker.h" |
dkato | 1:8ec133daca4c | 18 | #if defined(TARGET_RZ_A1H) || defined(TARGET_VK_RZ_A1H) || defined(TARGET_GR_LYCHEE) |
dkato | 1:8ec133daca4c | 19 | #include "vfp_neon_push_pop.h" |
dkato | 1:8ec133daca4c | 20 | #else |
dkato | 1:8ec133daca4c | 21 | static void dummy_func(void) {} |
dkato | 1:8ec133daca4c | 22 | #define __vfp_neon_push dummy_func |
dkato | 1:8ec133daca4c | 23 | #define __vfp_neon_pop dummy_func |
dkato | 1:8ec133daca4c | 24 | #endif |
dkato | 0:aba6e62b51a7 | 25 | |
dkato | 0:aba6e62b51a7 | 26 | PwmOutSpeaker::PwmOutSpeaker(PinName pwm_l, PinName pwm_r) : _speaker_l(pwm_l), _speaker_r(pwm_r) { |
dkato | 0:aba6e62b51a7 | 27 | _bottom = 0; |
dkato | 0:aba6e62b51a7 | 28 | _top = 0; |
dkato | 0:aba6e62b51a7 | 29 | _playing = false; |
dkato | 3:37a886d77bae | 30 | outputVolume(1.0f, 1.0f); |
dkato | 3:37a886d77bae | 31 | format(16); |
dkato | 0:aba6e62b51a7 | 32 | frequency(44100); |
dkato | 0:aba6e62b51a7 | 33 | } |
dkato | 0:aba6e62b51a7 | 34 | |
dkato | 3:37a886d77bae | 35 | bool PwmOutSpeaker::format(char length) { |
dkato | 0:aba6e62b51a7 | 36 | switch (length) { |
dkato | 0:aba6e62b51a7 | 37 | case 8: |
dkato | 0:aba6e62b51a7 | 38 | case 16: |
dkato | 0:aba6e62b51a7 | 39 | break; |
dkato | 0:aba6e62b51a7 | 40 | default: |
dkato | 0:aba6e62b51a7 | 41 | return false; |
dkato | 0:aba6e62b51a7 | 42 | } |
dkato | 0:aba6e62b51a7 | 43 | _length = length; |
dkato | 0:aba6e62b51a7 | 44 | _data_cnt = 0; |
dkato | 0:aba6e62b51a7 | 45 | return true; |
dkato | 0:aba6e62b51a7 | 46 | } |
dkato | 0:aba6e62b51a7 | 47 | |
dkato | 0:aba6e62b51a7 | 48 | bool PwmOutSpeaker::frequency(int hz) { |
dkato | 0:aba6e62b51a7 | 49 | int wk_us; |
dkato | 0:aba6e62b51a7 | 50 | |
dkato | 0:aba6e62b51a7 | 51 | switch (hz) { |
dkato | 0:aba6e62b51a7 | 52 | case 48000: |
dkato | 0:aba6e62b51a7 | 53 | _hz_multi = 6; |
dkato | 0:aba6e62b51a7 | 54 | break; |
dkato | 0:aba6e62b51a7 | 55 | case 44100: |
dkato | 0:aba6e62b51a7 | 56 | _hz_multi = 5; |
dkato | 0:aba6e62b51a7 | 57 | break; |
dkato | 0:aba6e62b51a7 | 58 | case 32000: |
dkato | 0:aba6e62b51a7 | 59 | _hz_multi = 4; |
dkato | 0:aba6e62b51a7 | 60 | break; |
dkato | 0:aba6e62b51a7 | 61 | case 8021: |
dkato | 0:aba6e62b51a7 | 62 | case 8000: |
dkato | 0:aba6e62b51a7 | 63 | _hz_multi = 1; |
dkato | 0:aba6e62b51a7 | 64 | break; |
dkato | 0:aba6e62b51a7 | 65 | default: |
dkato | 0:aba6e62b51a7 | 66 | return false; |
dkato | 0:aba6e62b51a7 | 67 | } |
dkato | 0:aba6e62b51a7 | 68 | _speaker_l.write(0.5f); |
dkato | 0:aba6e62b51a7 | 69 | _speaker_r.write(0.5f); |
dkato | 0:aba6e62b51a7 | 70 | _playing = false; |
dkato | 0:aba6e62b51a7 | 71 | _speaker_l.period_us(10); // 100kHz |
dkato | 0:aba6e62b51a7 | 72 | _speaker_r.period_us(10); // 100kHz |
dkato | 0:aba6e62b51a7 | 73 | wk_us = (int)(1000000.0f / hz * _hz_multi + 0.5f); |
dkato | 0:aba6e62b51a7 | 74 | _timer.attach_us(Callback<void()>(this, &PwmOutSpeaker::sound_out), wk_us); |
dkato | 0:aba6e62b51a7 | 75 | _data_cnt = 0; |
dkato | 0:aba6e62b51a7 | 76 | |
dkato | 0:aba6e62b51a7 | 77 | return true; |
dkato | 0:aba6e62b51a7 | 78 | } |
dkato | 0:aba6e62b51a7 | 79 | |
dkato | 3:37a886d77bae | 80 | int PwmOutSpeaker::write(void * const p_data, uint32_t data_size, const rbsp_data_conf_t * const p_data_conf) { |
dkato | 0:aba6e62b51a7 | 81 | int data_num; |
dkato | 0:aba6e62b51a7 | 82 | int i = 0; |
dkato | 3:37a886d77bae | 83 | float wk_vol_l; |
dkato | 3:37a886d77bae | 84 | float wk_ofs_l; |
dkato | 3:37a886d77bae | 85 | float wk_vol_r; |
dkato | 3:37a886d77bae | 86 | float wk_ofs_r; |
dkato | 0:aba6e62b51a7 | 87 | |
dkato | 0:aba6e62b51a7 | 88 | if (_length == 8) { |
dkato | 0:aba6e62b51a7 | 89 | data_num = data_size; |
dkato | 0:aba6e62b51a7 | 90 | } else { |
dkato | 0:aba6e62b51a7 | 91 | data_num = data_size / 2; |
dkato | 0:aba6e62b51a7 | 92 | } |
dkato | 0:aba6e62b51a7 | 93 | while (i < data_num) { |
dkato | 0:aba6e62b51a7 | 94 | if (_data_cnt < (_hz_multi - 1)) { |
dkato | 0:aba6e62b51a7 | 95 | _data_cnt++; |
dkato | 3:37a886d77bae | 96 | i += 2; |
dkato | 0:aba6e62b51a7 | 97 | } else { |
dkato | 0:aba6e62b51a7 | 98 | _data_cnt = 0; |
dkato | 0:aba6e62b51a7 | 99 | while (((_bottom + 2) & MSK_RING_BUFF) == _top) { |
dkato | 0:aba6e62b51a7 | 100 | Thread::wait(1); |
dkato | 0:aba6e62b51a7 | 101 | } |
dkato | 3:37a886d77bae | 102 | wk_vol_l = _speaker_vol_l; |
dkato | 3:37a886d77bae | 103 | wk_ofs_l = (1.0f - wk_vol_l) / 2; |
dkato | 3:37a886d77bae | 104 | wk_vol_r = _speaker_vol_r; |
dkato | 3:37a886d77bae | 105 | wk_ofs_r = (1.0f - wk_vol_r) / 2; |
dkato | 0:aba6e62b51a7 | 106 | if (_length == 8) { |
dkato | 3:37a886d77bae | 107 | _pwm_duty_buf[_bottom] = ((float)((uint8_t *)p_data)[i++] / (float)0xff) * wk_vol_l + wk_ofs_l; |
dkato | 3:37a886d77bae | 108 | _pwm_duty_buf[_bottom + 1] = ((float)((uint8_t *)p_data)[i++] / (float)0xff) * wk_vol_r + wk_ofs_r; |
dkato | 0:aba6e62b51a7 | 109 | } else { |
dkato | 3:37a886d77bae | 110 | _pwm_duty_buf[_bottom] = ((float)(((int16_t *)p_data)[i++] + 0x8000) / (float)0xffff) * wk_vol_l + wk_ofs_l; |
dkato | 3:37a886d77bae | 111 | _pwm_duty_buf[_bottom + 1] = ((float)(((int16_t *)p_data)[i++] + 0x8000) / (float)0xffff) * wk_vol_r + wk_ofs_r; |
dkato | 0:aba6e62b51a7 | 112 | } |
dkato | 0:aba6e62b51a7 | 113 | _bottom = (_bottom + 2) & MSK_RING_BUFF; |
dkato | 0:aba6e62b51a7 | 114 | } |
dkato | 0:aba6e62b51a7 | 115 | } |
dkato | 3:37a886d77bae | 116 | |
dkato | 3:37a886d77bae | 117 | if (p_data_conf != NULL) { |
dkato | 3:37a886d77bae | 118 | return data_size; |
dkato | 3:37a886d77bae | 119 | } |
dkato | 3:37a886d77bae | 120 | |
dkato | 3:37a886d77bae | 121 | if (p_data_conf->p_notify_func != NULL) { |
dkato | 3:37a886d77bae | 122 | p_data_conf->p_notify_func(p_data, data_size, p_data_conf->p_app_data); |
dkato | 3:37a886d77bae | 123 | } |
dkato | 3:37a886d77bae | 124 | |
dkato | 0:aba6e62b51a7 | 125 | return 0; |
dkato | 0:aba6e62b51a7 | 126 | } |
dkato | 0:aba6e62b51a7 | 127 | |
dkato | 3:37a886d77bae | 128 | bool PwmOutSpeaker::outputVolume(float leftVolumeOut, float rightVolumeOut) { |
dkato | 3:37a886d77bae | 129 | if ((leftVolumeOut < 0.0) || (leftVolumeOut > 1.0)) { |
dkato | 0:aba6e62b51a7 | 130 | return false; |
dkato | 0:aba6e62b51a7 | 131 | } |
dkato | 3:37a886d77bae | 132 | if ((rightVolumeOut < 0.0) || (rightVolumeOut > 1.0)) { |
dkato | 3:37a886d77bae | 133 | return false; |
dkato | 3:37a886d77bae | 134 | } |
dkato | 3:37a886d77bae | 135 | _speaker_vol_l = leftVolumeOut; |
dkato | 3:37a886d77bae | 136 | _speaker_vol_r = rightVolumeOut; |
dkato | 0:aba6e62b51a7 | 137 | return true; |
dkato | 0:aba6e62b51a7 | 138 | } |
dkato | 0:aba6e62b51a7 | 139 | |
dkato | 0:aba6e62b51a7 | 140 | void PwmOutSpeaker::sound_out(void) { |
dkato | 0:aba6e62b51a7 | 141 | if (_top != _bottom) { |
dkato | 1:8ec133daca4c | 142 | __vfp_neon_push(); |
dkato | 0:aba6e62b51a7 | 143 | _speaker_l.write(_pwm_duty_buf[_top + 0]); |
dkato | 0:aba6e62b51a7 | 144 | _speaker_r.write(_pwm_duty_buf[_top + 1]); |
dkato | 1:8ec133daca4c | 145 | __vfp_neon_pop(); |
dkato | 0:aba6e62b51a7 | 146 | _top = (_top + 2) & MSK_RING_BUFF; |
dkato | 0:aba6e62b51a7 | 147 | _playing = true; |
dkato | 0:aba6e62b51a7 | 148 | } else if (_playing) { |
dkato | 1:8ec133daca4c | 149 | __vfp_neon_push(); |
dkato | 0:aba6e62b51a7 | 150 | _speaker_l.write(0.5f); |
dkato | 0:aba6e62b51a7 | 151 | _speaker_r.write(0.5f); |
dkato | 1:8ec133daca4c | 152 | __vfp_neon_pop(); |
dkato | 0:aba6e62b51a7 | 153 | _playing = false; |
dkato | 0:aba6e62b51a7 | 154 | } else { |
dkato | 0:aba6e62b51a7 | 155 | // do nothing |
dkato | 0:aba6e62b51a7 | 156 | } |
dkato | 0:aba6e62b51a7 | 157 | } |