From 48c93ed0432e23cb22669ddb8873988058a772f1 Mon Sep 17 00:00:00 2001 From: Fabian Schlenz Date: Mon, 11 Nov 2019 17:40:47 +0100 Subject: [PATCH] Added recording mode to detect volumes. --- include/player.h | 14 +++++++-- src/player.cpp | 82 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 87 insertions(+), 9 deletions(-) diff --git a/include/player.h b/include/player.h index 1a5baf5..c1b72f0 100644 --- a/include/player.h +++ b/include/player.h @@ -4,7 +4,6 @@ #include #include #include -#include #include "spi_master.h" #define SCI_MODE 0x00 @@ -15,20 +14,28 @@ #define SCI_VOL 0x0B #define SCI_WRAMADDR 0x07 #define SCI_WRAM 0x06 +#define SCI_HDAT0 0x08 +#define SCI_HDAT1 0x09 +#define SCI_AICTRL0 0x0C +#define SCI_AICTRL1 0x0D +#define SCI_AICTRL2 0x0E +#define SCI_AICTRL3 0x0F #define CMD_WRITE 0x02 #define CMD_READ 0x03 #define ADDR_ENDBYTE 0x1E06 +#define SM_RESET 0x0004 #define SM_CANCEL 0x0008 +#define SM_ADPCM 0x1000 #define SS_DO_NOT_JUMP 0x8000 class Player { private: enum state { uninitialized, idle, playing, stopping, system_sound_while_playing, system_sound_while_stopped, - sleeping }; + sleeping, recording }; struct album_state { uint8_t index; uint32_t position; @@ -39,6 +46,7 @@ private: void _wait(); uint16_t _read_control_register(uint8_t address); void _write_control_register(uint8_t address, uint16_t value); + void _write_direct(uint8_t address, uint16_t value); void _write_data(uint8_t* data); uint16_t _read_wram(uint16_t address); state _state = state::uninitialized; @@ -58,6 +66,8 @@ private: void _unmute(); void _sleep(); void _wakeup(); + void _record(); + void _patch_adpcm(); void _speaker_off(); void _speaker_on(); diff --git a/src/player.cpp b/src/player.cpp index 72f16c2..2d29603 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -108,12 +108,25 @@ void Player::_wakeup() { set_volume(_volume, false); _write_control_register(SCI_AUDATA, 0x0000); _write_control_register(SCI_CLOCKF, 0x6000); + _write_control_register(SCI_MODE, 0x4800 | SM_RESET); delay(10); //_speaker_on(); _spi_settings = &_spi_settings_fast; _state = idle; } +void Player::_record() { + _write_control_register(SCI_AICTRL0, 8000U); // Sampling rate 8000 Hz + _write_control_register(SCI_AICTRL1, 2048U); // Manual gain, 2x + _write_control_register(SCI_AICTRL2, 2048U); // Maximum gain for autogain - ignored + _write_control_register(SCI_AICTRL3, 6); // 2 (left channel) + 4 (PCM) + uint16_t mode = _read_control_register(SCI_MODE); + mode = mode | SM_RESET | SM_ADPCM; + _write_control_register(SCI_MODE, mode); + _patch_adpcm(); + _state = recording; +} + void Player::_check_system_sound(String filename) { String path = String("/system/") + filename; if (!SD.exists(path)) { @@ -144,16 +157,57 @@ uint16_t Player::_read_control_register(uint8_t address) { } void Player::_write_control_register(uint8_t address, uint16_t value) { - uint8_t b1 = value >> 8; - uint8_t b2 = value & 0xFF; _wait(); _spi->select_vs1053_xcs(); SPI.beginTransaction(*_spi_settings); + _write_direct(address, value); + SPI.endTransaction(); + _spi->select_vs1053_xcs(false); +} + +void Player::_write_direct(uint8_t target, uint16_t value) { SPI.transfer(CMD_WRITE); - SPI.transfer(address); - SPI.transfer(b1); - SPI.transfer(b2); + SPI.transfer(target); + SPI.transfer(value >> 8); + SPI.transfer(value & 0xFF); _wait(); +} + +void Player::_patch_adpcm() { + _spi->select_vs1053_xcs(); + SPI.beginTransaction(*_spi_settings); + _write_direct(SCI_WRAMADDR, 0x8010); + _write_direct(SCI_WRAM, 0x3e12); + _write_direct(SCI_WRAM, 0xb817); + _write_direct(SCI_WRAM, 0x3e14); + _write_direct(SCI_WRAM, 0xf812); + _write_direct(SCI_WRAM, 0x3e01); + _write_direct(SCI_WRAM, 0xb811); + _write_direct(SCI_WRAM, 0x0007); + _write_direct(SCI_WRAM, 0x9717); + _write_direct(SCI_WRAM, 0x0020); + _write_direct(SCI_WRAM, 0xffd2); + _write_direct(SCI_WRAM, 0x0030); + _write_direct(SCI_WRAM, 0x11d1); + _write_direct(SCI_WRAM, 0x3111); + _write_direct(SCI_WRAM, 0x8024); + _write_direct(SCI_WRAM, 0x3704); + _write_direct(SCI_WRAM, 0xc024); + _write_direct(SCI_WRAM, 0x3b81); + _write_direct(SCI_WRAM, 0x8024); + _write_direct(SCI_WRAM, 0x3101); + _write_direct(SCI_WRAM, 0x8024); + _write_direct(SCI_WRAM, 0x3b81); + _write_direct(SCI_WRAM, 0x8024); + _write_direct(SCI_WRAM, 0x3f04); + _write_direct(SCI_WRAM, 0xc024); + _write_direct(SCI_WRAM, 0x2808); + _write_direct(SCI_WRAM, 0x4800); + _write_direct(SCI_WRAM, 0x36f1); + _write_direct(SCI_WRAM, 0x9811); + _write_direct(SCI_WRAMADDR, 0x8028); + _write_direct(SCI_WRAM, 0x2a00); + _write_direct(SCI_WRAM, 0x040e); SPI.endTransaction(); _spi->select_vs1053_xcs(false); } @@ -354,7 +408,7 @@ bool Player::play_album(String album) { } bool Player::play_song(String album, uint8_t index, uint32_t skip_to) { - if (_state == sleeping) _wakeup(); + if (_state == sleeping || _state == recording) _wakeup(); if (_state != idle) return false; DEBUG("Trying to play song at index %d, offset %d of album %s\n", index, skip_to, album.c_str()); String path = _find_album_dir(album); @@ -572,9 +626,23 @@ bool Player::loop() { _refill(); return true; } + + if (_state == recording) { + uint16_t samples_available = _read_control_register(SCI_HDAT1); + if (samples_available >= 500) { + unsigned long sum = 0; + for (int i=0; i<500; i++) { + uint16_t sample = _read_control_register(SCI_HDAT0); + sum += sample * sample; + } + double result = sqrt(sum / 500); + DEBUG("Loudness: %f", result); + } + } if (_state == idle && _stopped_at < millis() - VS1053_SLEEP_DELAY) { - _sleep(); + //_sleep(); + _record(); } return false; }