PWM drives the speaker.

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?

UserRevisionLine numberNew 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 }