Easy playback library for PwmOutSpeaker.
Revision 0:41ab76b22961, committed 2017-07-06
- Comitter:
- dkato
- Date:
- Thu Jul 06 04:42:29 2017 +0000
- Commit message:
- first commit
Changed in this revision
diff -r 000000000000 -r 41ab76b22961 EasyPlaybackPWM.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EasyPlaybackPWM.cpp Thu Jul 06 04:42:29 2017 +0000 @@ -0,0 +1,134 @@ +/* mbed EasyPlaybackPWM Library + * Copyright (C) 2017 dkato + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbed.h" +#include "EasyPlaybackPWM.h" + +EasyPlaybackPWM::EasyPlaybackPWM(PinName pwm_l, PinName pwm_r) : audio(pwm_l, pwm_r), _skip(false), _pause(false) +{ + _audio_buf = new uint8_t[AUDIO_WRITE_BUFF_SIZE]; +} + +EasyPlaybackPWM::~EasyPlaybackPWM() +{ + delete [] _audio_buf; +} + +bool EasyPlaybackPWM::get_tag(const char* filename, char* p_title, char* p_artist, char* p_album, uint16_t tag_size) +{ + FILE * fp; + EasyDecoder * decoder; + bool ret = false; + + decoder = create_decoer_class(filename); + if (decoder == NULL) { + return false; + } + + fp = fopen(filename, "r"); + if (decoder->AnalyzeHeder(p_title, p_artist, p_album, tag_size, fp) != false) { + ret = true; + } + delete decoder; + fclose(fp); + + return ret; +} + +bool EasyPlaybackPWM::play(const char* filename) +{ + size_t audio_data_size = AUDIO_WRITE_BUFF_SIZE; + FILE * fp; + EasyDecoder * decoder; + bool ret = false; + + decoder = create_decoer_class(filename); + if (decoder == NULL) { + return false; + } + + _skip = false; + fp = fopen(filename, "r"); + if (decoder->AnalyzeHeder(NULL, NULL, NULL, 0, fp) == false) { + // do nothing + } else if ((decoder->GetChannel() != 2) + || (audio.format(decoder->GetBlockSize()) == false) + || (audio.frequency(decoder->GetSamplingRate()) == false)) { + // do nothing + } else { + while (audio_data_size == AUDIO_WRITE_BUFF_SIZE) { + while ((_pause) && (!_skip)) { + Thread::wait(100); + } + if (_skip) { + break; + } + audio_data_size = decoder->GetNextData(_audio_buf, AUDIO_WRITE_BUFF_SIZE); + if (audio_data_size > 0) { + audio.write(_audio_buf, audio_data_size); + } + } + Thread::wait(500); + ret = true; + } + delete decoder; + fclose(fp); + + return ret; +} + +bool EasyPlaybackPWM::is_paused(void) +{ + return _pause; +} + +void EasyPlaybackPWM::pause() +{ + _pause = !_pause; +} + +void EasyPlaybackPWM::pause(bool type) +{ + _pause = type; +} + +void EasyPlaybackPWM::skip(void) +{ + _skip = true; +} + +bool EasyPlaybackPWM::outputVolume(float VolumeOut) +{ + return audio.outputVolume(VolumeOut); +} + +EasyDecoder * EasyPlaybackPWM::create_decoer_class(const char* filename) +{ + std::map<std::string, EasyDecoder*(*)()>::iterator itr; + char *extension = strstr((char*)filename, "."); + + if (extension == NULL) { + return NULL; + } + + itr = m_lpDecoders.find(extension); + if (itr == m_lpDecoders.end()) { + return NULL; + } + + return (*itr).second(); +} +
diff -r 000000000000 -r 41ab76b22961 EasyPlaybackPWM.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EasyPlaybackPWM.h Thu Jul 06 04:42:29 2017 +0000 @@ -0,0 +1,54 @@ +/* mbed EasyPlaybackPWM Library + * Copyright (C) 2017 dkato + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __EASY_PLAYBACK_PWM_H__ +#define __EASY_PLAYBACK_PWM_H__ + +#include <string> +#include <map> +#include "EasyDecoder.h" +#include "PwmOutSpeaker.h" + +class EasyPlaybackPWM +{ +public: + EasyPlaybackPWM(PinName pwm_l, PinName pwm_r); + ~EasyPlaybackPWM(); + bool get_tag(const char* filename, char* p_title, char* p_artist, char* p_album, uint16_t tag_size); + bool play(const char* filename); + bool is_paused(void); + void pause(void); + void pause(bool type); + void skip(void); + bool outputVolume(float VolumeOut); + + template<typename T> + void add_decoder(const string& extension) { + m_lpDecoders[extension] = &T::inst; + } + +private: + #define AUDIO_WRITE_BUFF_SIZE (4096) + PwmOutSpeaker audio; + bool _skip; + bool _pause; + uint8_t *_audio_buf; + std::map<std::string, EasyDecoder*(*)()> m_lpDecoders; + + EasyDecoder * create_decoer_class(const char* filename); +}; + +#endif
diff -r 000000000000 -r 41ab76b22961 decoder/EasyDec_Wav.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/decoder/EasyDec_Wav.h Thu Jul 06 04:42:29 2017 +0000 @@ -0,0 +1,258 @@ +/* mbed EasyDec_Wav Library + * Copyright (C) 2017 dkato + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/**************************************************************************//** +* @file EasyDec_Wav.h +* @brief wav +******************************************************************************/ +#ifndef __EASY_DECODER_WAV_H__ +#define __EASY_DECODER_WAV_H__ + +#include "EasyDecoder.h" + +/** A class to communicate a EasyDec_Wav + * + */ +class EasyDec_Wav : public EasyDecoder { +public: + + static inline EasyDecoder* inst() { return new EasyDec_Wav; } + + /** analyze header + * + * @param p_title title tag buffer + * @param p_artist artist tag buffer + * @param p_album album tag buffer + * @param tag_size tag buffer size + * @param fp file pointer + * @return true = success, false = failure + */ + virtual bool AnalyzeHeder(char* p_title, char* p_artist, char* p_album, uint16_t tag_size, FILE* fp) { + bool result = false; + size_t read_size; + uint8_t wk_read_buff[36]; + char *data; + uint32_t chunk_size; + uint32_t sub_chunk_size; + uint32_t list_index_max; + bool list_ok = false; + uint32_t read_index = 0; + uint32_t data_index = 0; + uint16_t wk_len; + + if (fp == NULL) { + return false; + } + music_data_size = 0; + music_data_index = 0; + wav_fp = fp; + if (p_title != NULL) { + p_title[0] = '\0'; + } + if (p_artist != NULL) { + p_artist[0] = '\0'; + } + if (p_album != NULL) { + p_album[0] = '\0'; + } + + read_size = fread(&wk_read_buff[0], sizeof(char), 36, wav_fp); + if (read_size < 36) { + // do nothing + } else if (memcmp(&wk_read_buff[0], "RIFF", 4) != 0) { + // do nothing + } else if (memcmp(&wk_read_buff[8], "WAVE", 4) != 0) { + // do nothing + } else if (memcmp(&wk_read_buff[12], "fmt ", 4) != 0) { + // do nothing + } else { + read_index += 36; + channel = ((uint32_t)wk_read_buff[22] << 0) + ((uint32_t)wk_read_buff[23] << 8); + sampling_rate = ((uint32_t)wk_read_buff[24] << 0) + + ((uint32_t)wk_read_buff[25] << 8) + + ((uint32_t)wk_read_buff[26] << 16) + + ((uint32_t)wk_read_buff[27] << 24); + block_size = ((uint32_t)wk_read_buff[34] << 0) + ((uint32_t)wk_read_buff[35] << 8); + while (1) { + read_size = fread(&wk_read_buff[0], sizeof(char), 8, wav_fp); + read_index += 8; + if (read_size < 8) { + break; + } else { + chunk_size = ((uint32_t)wk_read_buff[4] << 0) + + ((uint32_t)wk_read_buff[5] << 8) + + ((uint32_t)wk_read_buff[6] << 16) + + ((uint32_t)wk_read_buff[7] << 24); + if (memcmp(&wk_read_buff[0], "data", 4) == 0) { + result = true; + music_data_size = chunk_size; + if (list_ok == true) { + break; + } else { + data_index = read_index; + fseek(wav_fp, chunk_size, SEEK_CUR); + read_index += chunk_size; + } + } else if (memcmp(&wk_read_buff[0], "LIST", 4) == 0) { + list_ok = true; + list_index_max = read_index + chunk_size; + read_size = fread(&wk_read_buff[0], sizeof(char), 4, wav_fp); + read_index += 4; + while (read_index < list_index_max) { + read_size = fread(&wk_read_buff[0], sizeof(char), 8, wav_fp); + read_index += 8; + if (read_size < 8) { + break; + } else if (memcmp(&wk_read_buff[0], "INAM", 4) == 0) { + data = p_title; + } else if (memcmp(&wk_read_buff[0], "IART", 4) == 0) { + data = p_artist; + } else if (memcmp(&wk_read_buff[0], "IPRD", 4) == 0) { + data = p_album; + } else { + data = NULL; + } + sub_chunk_size = ((uint32_t)wk_read_buff[4] << 0) + + ((uint32_t)wk_read_buff[5] << 8) + + ((uint32_t)wk_read_buff[6] << 16) + + ((uint32_t)wk_read_buff[7] << 24); + if ((data != NULL) && (tag_size != 0)) { + if (sub_chunk_size > (uint32_t)(tag_size - 1)) { + wk_len = (tag_size - 1); + } else { + wk_len = sub_chunk_size; + } + read_size = fread(data, sizeof(char), wk_len, wav_fp); + data[wk_len] = '\0'; + } + if ((sub_chunk_size & 0x00000001) != 0) { + sub_chunk_size += 1; + } + read_index += sub_chunk_size; + fseek(wav_fp, read_index, SEEK_SET); + } + if (data_index != 0) { + break; + } else { + fseek(wav_fp, list_index_max, SEEK_SET); + } + } else { + fseek(wav_fp, chunk_size, SEEK_CUR); + read_index += chunk_size; + } + } + } + + if (data_index != 0) { + fseek(wav_fp, data_index, SEEK_SET); + } + } + + return result; + }; + + /** get next data + * + * @param buf data buffer address + * @param len data buffer length + * @return get data size + */ + virtual size_t GetNextData(void *buf, size_t len) { + if (block_size == 24) { + // Add padding + uint32_t write_index = 0; + uint32_t wavfile_index; + uint32_t read_len; + uint32_t pading_index = 0; + uint8_t * p_buf = (uint8_t *)buf; + size_t ret; + + if ((music_data_index + len) > music_data_size) { + len = music_data_size - music_data_index; + } + while (write_index < (uint32_t)len) { + read_len = (len - write_index) * 3 / 4; + if (read_len > sizeof(wk_wavfile_buff)) { + read_len = sizeof(wk_wavfile_buff); + } + music_data_index += read_len; + ret = fread(wk_wavfile_buff, sizeof(char), read_len, wav_fp); + if (ret < read_len) { + break; + } + wavfile_index = 0; + while ((write_index < len) && (wavfile_index < read_len)) { + if (pading_index == 0) { + p_buf[write_index] = 0; + } else { + p_buf[write_index] = wk_wavfile_buff[wavfile_index]; + wavfile_index++; + } + if (pading_index < 3) { + pading_index++; + } else { + pading_index = 0; + } + write_index++; + } + } + + return write_index; + } else { + if ((music_data_index + len) > music_data_size) { + len = music_data_size - music_data_index; + } + music_data_index += len; + + return fread(buf, sizeof(char), len, wav_fp); + } + }; + + /** get channel + * + * @return channel + */ + virtual uint16_t GetChannel() { + return channel; + }; + + /** get block size + * + * @return block size + */ + virtual uint16_t GetBlockSize() { + return block_size; + }; + + /** get sampling rate + * + * @return sampling rate + */ + virtual uint32_t GetSamplingRate() { + return sampling_rate; + }; + +private: + FILE * wav_fp; + uint32_t music_data_size; + uint32_t music_data_index; + uint16_t channel; + uint16_t block_size; + uint32_t sampling_rate; + uint8_t wk_wavfile_buff[3072]; +}; + +#endif
diff -r 000000000000 -r 41ab76b22961 decoder/EasyDec_WavCnv2ch.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/decoder/EasyDec_WavCnv2ch.h Thu Jul 06 04:42:29 2017 +0000 @@ -0,0 +1,299 @@ +/* mbed EasyDec_WavCnv2ch Library + * Copyright (C) 2017 dkato + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/**************************************************************************//** +* @file EasyDec_WavCnv2ch.h +* @brief wav +******************************************************************************/ +#ifndef __EASY_DEC_WAV_CNV_2CH_H__ +#define __EASY_DEC_WAV_CNV_2CH_H__ + +#include "EasyDecoder.h" + +/** A class to communicate a EasyDec_WavCnv2ch + * + */ +class EasyDec_WavCnv2ch : public EasyDecoder { +public: + + static inline EasyDecoder* inst() { return new EasyDec_WavCnv2ch; } + + /** analyze header + * + * @param p_title title tag buffer + * @param p_artist artist tag buffer + * @param p_album album tag buffer + * @param tag_size tag buffer size + * @param fp file pointer + * @return true = success, false = failure + */ + virtual bool AnalyzeHeder(char* p_title, char* p_artist, char* p_album, uint16_t tag_size, FILE* fp) { + bool result = false; + size_t read_size; + uint8_t wk_read_buff[36]; + char *data; + uint32_t chunk_size; + uint32_t sub_chunk_size; + uint32_t list_index_max; + bool list_ok = false; + uint32_t read_index = 0; + uint32_t data_index = 0; + uint16_t wk_len; + + if (fp == NULL) { + return false; + } + music_data_size = 0; + music_data_index = 0; + wav_fp = fp; + if (p_title != NULL) { + p_title[0] = '\0'; + } + if (p_artist != NULL) { + p_artist[0] = '\0'; + } + if (p_album != NULL) { + p_album[0] = '\0'; + } + + read_size = fread(&wk_read_buff[0], sizeof(char), 36, wav_fp); + if (read_size < 36) { + // do nothing + } else if (memcmp(&wk_read_buff[0], "RIFF", 4) != 0) { + // do nothing + } else if (memcmp(&wk_read_buff[8], "WAVE", 4) != 0) { + // do nothing + } else if (memcmp(&wk_read_buff[12], "fmt ", 4) != 0) { + // do nothing + } else { + read_index += 36; + channel = ((uint32_t)wk_read_buff[22] << 0) + ((uint32_t)wk_read_buff[23] << 8); + sampling_rate = ((uint32_t)wk_read_buff[24] << 0) + + ((uint32_t)wk_read_buff[25] << 8) + + ((uint32_t)wk_read_buff[26] << 16) + + ((uint32_t)wk_read_buff[27] << 24); + block_size = ((uint32_t)wk_read_buff[34] << 0) + ((uint32_t)wk_read_buff[35] << 8); + while (1) { + read_size = fread(&wk_read_buff[0], sizeof(char), 8, wav_fp); + read_index += 8; + if (read_size < 8) { + break; + } else { + chunk_size = ((uint32_t)wk_read_buff[4] << 0) + + ((uint32_t)wk_read_buff[5] << 8) + + ((uint32_t)wk_read_buff[6] << 16) + + ((uint32_t)wk_read_buff[7] << 24); + if (memcmp(&wk_read_buff[0], "data", 4) == 0) { + result = true; + music_data_size = chunk_size; + if (list_ok == true) { + break; + } else { + data_index = read_index; + fseek(wav_fp, chunk_size, SEEK_CUR); + read_index += chunk_size; + } + } else if (memcmp(&wk_read_buff[0], "LIST", 4) == 0) { + list_ok = true; + list_index_max = read_index + chunk_size; + read_size = fread(&wk_read_buff[0], sizeof(char), 4, wav_fp); + read_index += 4; + while (read_index < list_index_max) { + read_size = fread(&wk_read_buff[0], sizeof(char), 8, wav_fp); + read_index += 8; + if (read_size < 8) { + break; + } else if (memcmp(&wk_read_buff[0], "INAM", 4) == 0) { + data = p_title; + } else if (memcmp(&wk_read_buff[0], "IART", 4) == 0) { + data = p_artist; + } else if (memcmp(&wk_read_buff[0], "IPRD", 4) == 0) { + data = p_album; + } else { + data = NULL; + } + sub_chunk_size = ((uint32_t)wk_read_buff[4] << 0) + + ((uint32_t)wk_read_buff[5] << 8) + + ((uint32_t)wk_read_buff[6] << 16) + + ((uint32_t)wk_read_buff[7] << 24); + if ((data != NULL) && (tag_size != 0)) { + if (sub_chunk_size > (uint32_t)(tag_size - 1)) { + wk_len = (tag_size - 1); + } else { + wk_len = sub_chunk_size; + } + read_size = fread(data, sizeof(char), wk_len, wav_fp); + data[wk_len] = '\0'; + } + if ((sub_chunk_size & 0x00000001) != 0) { + sub_chunk_size += 1; + } + read_index += sub_chunk_size; + fseek(wav_fp, read_index, SEEK_SET); + } + if (data_index != 0) { + break; + } else { + fseek(wav_fp, list_index_max, SEEK_SET); + } + } else { + fseek(wav_fp, chunk_size, SEEK_CUR); + read_index += chunk_size; + } + } + } + + if (data_index != 0) { + fseek(wav_fp, data_index, SEEK_SET); + } + } + + return result; + }; + + /** get next data + * + * @param buf data buffer address + * @param len data buffer length + * @return get data size + */ + virtual size_t GetNextData(void *buf, size_t len) { + size_t ret_size; + size_t read_max = len; + + if ((block_size < 8) || ((block_size & 0x07) != 0)) { + return -1; + } + + if ((channel == 1) && (len != 0)) { + read_max /= 2; + } + + if (block_size == 24) { + // Add padding + uint32_t write_index = 0; + uint32_t wavfile_index; + uint32_t read_len; + uint32_t pading_index = 0; + uint8_t * p_buf = (uint8_t *)buf; + size_t ret; + + if ((music_data_index + read_max) > music_data_size) { + read_max = music_data_size - music_data_index; + } + while (write_index < (uint32_t)read_max) { + read_len = (read_max - write_index) * 3 / 4; + if (read_len > sizeof(wk_wavfile_buff)) { + read_len = sizeof(wk_wavfile_buff); + } + music_data_index += read_len; + ret = fread(wk_wavfile_buff, sizeof(char), read_len, wav_fp); + if (ret < read_len) { + break; + } + wavfile_index = 0; + while ((write_index < read_max) && (wavfile_index < read_len)) { + if (pading_index == 0) { + p_buf[write_index] = 0; + } else { + p_buf[write_index] = wk_wavfile_buff[wavfile_index]; + wavfile_index++; + } + if (pading_index < 3) { + pading_index++; + } else { + pading_index = 0; + } + write_index++; + } + } + ret_size = write_index; + } else { + if ((music_data_index + read_max) > music_data_size) { + read_max = music_data_size - music_data_index; + } + music_data_index += read_max; + + ret_size = fread(buf, sizeof(char), read_max, wav_fp); + } + + if ((channel == 1) && (ret_size > 0)) { + int block_byte; + int idx_w = len - 1; + int idx_r = ret_size - 1; + int idx_r_last; + int j; + + if (block_size == 24) { + block_byte = 4; + } else { + block_byte = block_size / 8; + } + while (idx_w >= 0) { + idx_r_last = idx_r; + for (j = 0; j < block_byte; j++) { + ((uint8_t*)buf)[idx_w--] = ((uint8_t*)buf)[idx_r--]; + } + idx_r = idx_r_last; + for (j = 0; j < block_byte; j++) { + ((uint8_t*)buf)[idx_w--] = ((uint8_t*)buf)[idx_r--]; + } + } + ret_size *= 2; + } + + return ret_size; + }; + + /** get channel + * + * @return channel + */ + virtual uint16_t GetChannel() { + if (channel == 1) { + return 2; + } else { + return channel; + } + }; + + /** get block size + * + * @return block size + */ + virtual uint16_t GetBlockSize() { + return block_size; + }; + + /** get sampling rate + * + * @return sampling rate + */ + virtual uint32_t GetSamplingRate() { + return sampling_rate; + }; + +private: + FILE * wav_fp; + uint32_t music_data_size; + uint32_t music_data_index; + uint16_t channel; + uint16_t block_size; + uint32_t sampling_rate; + uint8_t wk_wavfile_buff[3072]; +}; + +#endif
diff -r 000000000000 -r 41ab76b22961 decoder/EasyDecoder.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/decoder/EasyDecoder.h Thu Jul 06 04:42:29 2017 +0000 @@ -0,0 +1,66 @@ +/* mbed EasyDecoder Library + * Copyright (C) 2017 dkato + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __EASY_DECODER_H__ +#define __EASY_DECODER_H__ + +#include "mbed.h" + +class EasyDecoder { +public: + + virtual ~EasyDecoder(){} + + /** analyze header + * + * @param p_title title tag buffer + * @param p_artist artist tag buffer + * @param p_album album tag buffer + * @param tag_size tag buffer size + * @param fp file pointer + * @return true = success, false = failure + */ + virtual bool AnalyzeHeder(char* p_title, char* p_artist, char* p_album, uint16_t tag_size, FILE* fp) = 0; + + /** get next data + * + * @param buf data buffer address + * @param len data buffer length + * @return get data size + */ + virtual size_t GetNextData(void *buf, size_t len) = 0; + + /** get channel + * + * @return channel + */ + virtual uint16_t GetChannel() = 0; + + /** get block size + * + * @return block size + */ + virtual uint16_t GetBlockSize() = 0; + + /** get sampling rate + * + * @return sampling rate + */ + virtual uint32_t GetSamplingRate() = 0; + +}; + +#endif