// Based on https://github.com/mpflaga/Arduino_Library-vs1053_for_SdFat/blob/master/src/vs1053_SdFat.cpp #include "player.h" #include "spi_master.h" #include //Player::_spi_settings Player::Player(SPIMaster* s) { _spi = s; PIN_VS1053_XRESET_SETUP(); PIN_VS1053_XRESET(HIGH); _speaker_off(); _spi->disable(); PIN_VS1053_DREQ_SETUP(); init(); } void Player::register_controller(Controller* c) { _controller = c; } void Player::_reset() { PIN_VS1053_XRESET(LOW); delay(100); PIN_VS1053_XRESET(HIGH); delay(100); _state = uninitialized; _spi_settings = &_spi_settings_slow; // After reset, communication has to be slow } void Player::init() { DEBUG("Resetting VS1053...\n"); _reset(); uint16_t result = _read_control_register(SCI_MODE); DEBUG("SCI_MODE: 0x%04X\n", result); if (result != 0x4800) { ERROR("SCI_MODE was 0x%04X, expected was 0x4800. Rebooting.\n", result); delay(500); ESP.restart(); } result = _read_control_register(SCI_STATUS); DEBUG("SCI_STATUS: 0x%04X\n", result); if (result != 0x0040 && result != 0x0048) { ERROR("SCI_STATUS was 0x%04X, expected was 0x0040 or 0x0048. Rebooting.\n", result); delay(500); ESP.restart(); } result = _read_control_register(SCI_CLOCKF); DEBUG("SCI_CLOCKF: 0x%04X\n", result); DEBUG("VS1053 Init looking good.\n"); DEBUG("Upping VS1053 multiplier...\n"); _write_control_register(SCI_CLOCKF, 0xC000); delay(10); _spi_settings = &_spi_settings_fast; result = _read_control_register(SCI_CLOCKF); DEBUG("SCI_CLOCKF: 0x%04X\n", result); if (result != 0xC000) { ERROR("Error: SCI_CLOCKF was 0x%04X, expected was 0xC000. Rebooting.\n", result); delay(500); ESP.restart(); } set_volume(VOLUME_DEFAULT); INFO("VS1053 initialization completed.\n"); _state = idle; } void Player::_speaker_off() { DEBUG("Speaker off\n"); PIN_SPEAKER_L(LOW); PIN_SPEAKER_R(LOW); } void Player::_speaker_on() { DEBUG("Speaker on\n"); PIN_SPEAKER_L(HIGH); PIN_SPEAKER_R(HIGH); } void Player::_sleep() { DEBUG("VS1053 going to sleep.\n"); _speaker_off(); _write_control_register(SCI_CLOCKF, 0x0000); _spi_settings = &_spi_settings_slow; _write_control_register(SCI_AUDATA, 0x0010); set_volume(0, false); _state = sleeping; TRACE("VS1053 is sleeping now.\n"); } void Player::_wakeup() { if (_state != sleeping && _state != recording) return; _stopped_at = millis(); DEBUG("Waking VS1053...\n"); 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() { // http://www.vlsi.fi/fileadmin/software/VS10XX/VS1053_VS1063_PcmRecorder.pdf DEBUG("Starting recording.\n"); set_volume(1, false); // Disable SCI_BASS _write_control_register(SCI_BASS, 0); // Disable user applications _write_control_register(SCI_AIADDR, 0); // Disable interrupts _write_control_register(SCI_WRAMADDR, 0xC01A); _write_control_register(SCI_WRAM, 0x0002); _patch_adpcm(); _write_control_register(SCI_MODE, SM_ADPCM); _write_control_register(SCI_AICTRL0, 0x8000); // Mono VU meter _write_control_register(SCI_AICTRL1, 1024); // Manual gain, 1x _write_control_register(SCI_AICTRL2, 0); // Maximum gain for autogain - ignored _write_control_register(SCI_AICTRL3, 0); // status: record _write_control_register(SCI_AIADDR, 0x0034, false); delay(1); DEBUG("Recording.\n"); delay(10); _state = recording; } inline void Player::_wait() { while(!PIN_VS1053_DREQ()); } uint16_t Player::_read_control_register(uint8_t address, bool do_wait) { if (do_wait) _wait(); _spi->select_vs1053_xcs(); SPI.beginTransaction(*_spi_settings); SPI.transfer(CMD_READ); SPI.transfer(address); uint8_t b1 = SPI.transfer(0xFF); _wait(); uint8_t b2 = SPI.transfer(0xFF); _wait(); SPI.endTransaction(); _spi->select_vs1053_xcs(false); return (b1 << 8) | b2; } void Player::_write_control_register(uint8_t address, uint16_t value, bool do_wait) { _wait(); _spi->select_vs1053_xcs(); SPI.beginTransaction(*_spi_settings); SPI.transfer(CMD_WRITE); SPI.transfer(address); SPI.transfer(value >> 8); SPI.transfer(value & 0xFF); SPI.endTransaction(); _spi->select_vs1053_xcs(false); if (do_wait) _wait(); } void Player::_patch_adpcm() { static const uint16_t patch_data[] = { 0x0007, 0x0001, 0xc01a, 0x0006, 0x0001, 0x0002, 0x0007, 0x0001, /* 0 */ 0x0008, 0x0006, 0x8002, 0x0000, 0x0007, 0x0001, 0x000c, 0x0006, /* 8 */ 0x0002, 0x7000, 0x0017, 0x0007, 0x0001, 0x8034, 0x0006, 0x0022, /* 10 */ 0x0030, 0x0490, 0xb080, 0x0024, 0x3800, 0x0024, 0x0000, 0x1090, /* 18 */ 0xf400, 0x5404, 0x0000, 0x0851, 0xf400, 0x5648, 0xf400, 0x5404, /* 20 */ 0xf400, 0x5658, 0xf400, 0x5404, 0xf400, 0x5640, 0x0000, 0x800a, /* 28 */ 0x2900, 0x9180, 0x0006, 0x2016, 0x2a00, 0x1bce, 0x2a00, 0x114e, /* 30 */ 0x2a00, 0x168e, 0x0007, 0x0001, 0x1800, 0x0006, 0x8006, 0x0000, /* 38 */ 0x0007, 0x0001, 0x8045, 0x0006, 0x002a, 0x3e12, 0xb817, 0x3e12, /* 40 */ 0x7808, 0x3e18, 0x3821, 0x3e18, 0xb823, 0x3e15, 0x4024, 0x3e10, /* 48 */ 0x7800, 0x48b2, 0x0024, 0x0000, 0x800a, 0x2900, 0x3e80, 0x3e10, /* 50 */ 0x7800, 0x36f0, 0x5800, 0x2210, 0x0000, 0x36f0, 0x5800, 0x36f5, /* 58 */ 0x4024, 0x36f8, 0x9823, 0x36f8, 0x1821, 0x36f2, 0x5808, 0x3602, /* 60 */ 0x8024, 0x0030, 0x0717, 0x2100, 0x0000, 0x3f05, 0xdbd7, 0x0007, /* 68 */ 0x0001, 0x805a, 0x0006, 0x002a, 0x3e12, 0xb817, 0x3e12, 0x7808, /* 70 */ 0x3e18, 0x3821, 0x3e18, 0xb823, 0x3e15, 0x4024, 0x3e10, 0x7800, /* 78 */ 0x48b2, 0x0024, 0x0000, 0x800a, 0x2900, 0x5e40, 0x3e10, 0x7800, /* 80 */ 0x36f0, 0x5800, 0x2210, 0x0000, 0x36f0, 0x5800, 0x36f5, 0x4024, /* 88 */ 0x36f8, 0x9823, 0x36f8, 0x1821, 0x36f2, 0x5808, 0x3602, 0x8024, /* 90 */ 0x0030, 0x0717, 0x2100, 0x0000, 0x3f05, 0xdbd7, 0x0007, 0x0001, /* 98 */ 0x806f, 0x0006, 0x0030, 0x3e12, 0xb817, 0x3e12, 0x7808, 0x3e18, /* a0 */ 0x3821, 0x3e18, 0xb823, 0x3e10, 0x7800, 0xb880, 0x3855, 0x0030, /* a8 */ 0x0497, 0x48b2, 0x3c00, 0x0000, 0x800a, 0x2900, 0x7300, 0x3e10, /* b0 */ 0x7800, 0x36f0, 0x5800, 0x2210, 0x0000, 0x6890, 0x1bd5, 0x0030, /* b8 */ 0x0497, 0x3f00, 0x0024, 0x36f0, 0x5800, 0x36f8, 0x9823, 0x36f8, /* c0 */ 0x1821, 0x36f2, 0x5808, 0x3602, 0x8024, 0x0030, 0x0717, 0x2100, /* c8 */ 0x0000, 0x3f05, 0xdbd7, 0x0007, 0x0001, 0x8010, 0x0006, 0x000e, /* d0 */ 0x3e02, 0x8024, 0x0001, 0x000a, 0x6012, 0x0024, 0xfea2, 0x0024, /* d8 */ 0x48b2, 0x1bca, 0x2000, 0x0000, 0x4180, 0x0024, 0x0007, 0x0001, /* e0 */ 0x8087, 0x0006, 0x00e6, 0x3e00, 0x7843, 0x3e01, 0x3845, 0x3e04, /* e8 */ 0x3812, 0x0006, 0x08d0, 0x3000, 0x4024, 0x6182, 0x0024, 0x0030, /* f0 */ 0x06d0, 0x2800, 0x2655, 0xb882, 0x0024, 0x0000, 0x0201, 0x0000, /* f8 */ 0x0005, 0x0030, 0x0210, 0xa016, 0x4004, 0x1fff, 0xfe01, 0xae1a, /* 100 */ 0x0024, 0xc342, 0x0024, 0xb882, 0x2001, 0x0030, 0x06d0, 0x3800, /* 108 */ 0x4024, 0x0006, 0x0890, 0x3004, 0x0024, 0x3000, 0x4024, 0x0006, /* 110 */ 0x12d0, 0x6182, 0x0024, 0x3000, 0x4024, 0x2800, 0x3e05, 0xf400, /* 118 */ 0x4050, 0x3009, 0x2000, 0x0006, 0x08d0, 0x0006, 0x0892, 0x3000, /* 120 */ 0x4024, 0x6192, 0x0024, 0x3800, 0x4024, 0x0030, 0x0250, 0xb882, /* 128 */ 0x2001, 0x0030, 0x0710, 0x3800, 0x4024, 0x0006, 0x12d0, 0x3000, /* 130 */ 0x4024, 0x6192, 0x0024, 0x3800, 0x4024, 0x3204, 0x0024, 0x3023, /* 138 */ 0x0024, 0x30e0, 0xc024, 0x6312, 0x0024, 0x0000, 0x00c3, 0x2800, /* 140 */ 0x3141, 0x0000, 0x0024, 0x3033, 0x0024, 0x3a04, 0x0024, 0x3000, /* 148 */ 0x4024, 0x6182, 0x0024, 0x0006, 0x0890, 0x2800, 0x2fd8, 0x0006, /* 150 */ 0x0301, 0x3a00, 0x4024, 0x0000, 0x00c3, 0x3004, 0x0024, 0x3013, /* 158 */ 0x0024, 0x3000, 0x4024, 0x0006, 0x12d0, 0x3800, 0x4024, 0x0030, /* 160 */ 0x0310, 0xf000, 0x0001, 0x6236, 0x0024, 0x001f, 0xffc3, 0x2800, /* 168 */ 0x3395, 0x0000, 0x0024, 0x0000, 0x0203, 0xa132, 0x0024, 0x001f, /* 170 */ 0xffc3, 0xb136, 0x0024, 0x6306, 0x0024, 0x0000, 0x0024, 0x2800, /* 178 */ 0x3611, 0x0000, 0x0024, 0x0020, 0x0003, 0xb132, 0x0024, 0x0000, /* 180 */ 0x0024, 0x2800, 0x3a85, 0x0000, 0x0024, 0x0000, 0x0081, 0xb212, /* 188 */ 0x0024, 0x0000, 0x0024, 0x2800, 0x3a05, 0x0000, 0x0024, 0x6892, /* 190 */ 0x0024, 0xb212, 0x0024, 0x0000, 0x0005, 0x2800, 0x3c55, 0x0030, /* 198 */ 0x0310, 0x0000, 0x3fc1, 0x3000, 0x8024, 0xb214, 0x0024, 0x003f, /* 1a0 */ 0xc001, 0xb010, 0x0024, 0xc200, 0x0024, 0x0030, 0x0310, 0x3800, /* 1a8 */ 0x0024, 0x36f4, 0x1812, 0x36f1, 0x1805, 0x36f0, 0x5803, 0x2000, /* 1b0 */ 0x0000, 0x0000, 0x0024, 0x0030, 0x0310, 0x0000, 0x0005, 0x003f, /* 1b8 */ 0xc001, 0x4088, 0x0002, 0xb214, 0x0024, 0x1fff, 0xfe01, 0xae12, /* 1c0 */ 0x0024, 0x2800, 0x3a00, 0xc200, 0x0024, 0x2800, 0x28c0, 0x3800, /* 1c8 */ 0x0024, 0x0007, 0x0001, 0x80fa, 0x0006, 0x00fe, 0x3e12, 0x0024, /* 1d0 */ 0x3e05, 0xb814, 0x3615, 0x0024, 0x3e00, 0x3841, 0x3e00, 0xb843, /* 1d8 */ 0x3e01, 0x3845, 0x3e04, 0x3851, 0x0030, 0x10d0, 0x3e04, 0x8024, /* 1e0 */ 0x3010, 0x0024, 0x3000, 0x8024, 0x0006, 0x1190, 0x3000, 0x4024, /* 1e8 */ 0x6182, 0x0024, 0x0000, 0x0024, 0x2800, 0x5dd5, 0x0000, 0x0024, /* 1f0 */ 0x0030, 0x03d0, 0x0000, 0x00c1, 0x3000, 0xc024, 0xb318, 0x0024, /* 1f8 */ 0x6896, 0x0024, 0x6436, 0x0024, 0x0020, 0x0003, 0x2800, 0x59c5, /* 200 */ 0x0000, 0x0024, 0x0006, 0x1150, 0x3000, 0x4024, 0x6136, 0x0024, /* 208 */ 0x0000, 0x0024, 0x2800, 0x4741, 0x0000, 0x0024, 0x0000, 0x0803, /* 210 */ 0x4132, 0x0024, 0x3800, 0x4024, 0x0006, 0x0190, 0x0006, 0xf011, /* 218 */ 0x2900, 0xb500, 0x3613, 0x0024, 0x0006, 0xf011, 0x0006, 0x1152, /* 220 */ 0x0006, 0x0250, 0x4082, 0x0800, 0xfe82, 0x184c, 0x1fff, 0xfc41, /* 228 */ 0x48ba, 0x0024, 0xae1a, 0x0024, 0x2900, 0xb500, 0x4280, 0x4103, /* 230 */ 0x0006, 0x1110, 0x4084, 0x0800, 0xfe84, 0x0002, 0x48ba, 0x0024, /* 238 */ 0xae12, 0x0024, 0xf400, 0x4001, 0x0000, 0x0180, 0x6200, 0x0024, /* 240 */ 0x0000, 0x0080, 0x2800, 0x5241, 0x4200, 0x0024, 0x3800, 0x0024, /* 248 */ 0x0006, 0x1090, 0x3004, 0x8024, 0xf400, 0x4491, 0x3113, 0x0024, /* 250 */ 0x3804, 0x4024, 0x3a00, 0xc024, 0x3004, 0x8024, 0xf400, 0x4491, /* 258 */ 0x3113, 0x0024, 0x3804, 0x4024, 0x3a00, 0x4024, 0x0006, 0x1081, /* 260 */ 0x3000, 0x0024, 0x6012, 0x0024, 0x0006, 0x0f00, 0x2800, 0x5248, /* 268 */ 0x0000, 0x0024, 0x3800, 0x0024, 0x0030, 0x0010, 0x0000, 0x0080, /* 270 */ 0x3000, 0x4024, 0x0030, 0x0710, 0xb104, 0x0024, 0x0000, 0x0001, /* 278 */ 0x3800, 0x4024, 0x0006, 0x08d0, 0x3001, 0x0024, 0x0006, 0x0910, /* 280 */ 0x3000, 0x4024, 0x6100, 0x0024, 0x6042, 0x0024, 0x0030, 0x06d0, /* 288 */ 0x2800, 0x5711, 0xb880, 0x0024, 0x2900, 0x21c0, 0x4380, 0x184c, /* 290 */ 0xb880, 0x0024, 0x3800, 0x0024, 0x36f4, 0x8024, 0x36f4, 0x1811, /* 298 */ 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f0, 0x1801, 0x3405, 0x9014, /* 2a0 */ 0x36f3, 0x0024, 0x36f2, 0x0024, 0x2000, 0x0000, 0x0000, 0x0024, /* 2a8 */ 0x0006, 0x1152, 0x0000, 0x0804, 0x3200, 0xc024, 0x6346, 0x0024, /* 2b0 */ 0x6386, 0x2803, 0x0000, 0x0024, 0x2800, 0x4755, 0x0000, 0x0024, /* 2b8 */ 0x3800, 0x4024, 0x0030, 0x0690, 0x0000, 0x0081, 0xb882, 0x22c1, /* 2c0 */ 0x3800, 0x4024, 0x0030, 0x0590, 0x2800, 0x4740, 0x3800, 0x4024, /* 2c8 */ 0x2800, 0x5700, 0x4190, 0x0024, 0x0007, 0x0001, 0x8179, 0x0006, /* 2d0 */ 0x00a6, 0x3e12, 0x0024, 0x3e05, 0xb814, 0x3625, 0x0024, 0x3e00, /* 2d8 */ 0x3841, 0x3e00, 0xb843, 0x3e04, 0x3851, 0x0006, 0x1110, 0x3e04, /* 2e0 */ 0xb813, 0x3000, 0x0024, 0x6080, 0x0024, 0x0006, 0x11d2, 0x2800, /* 2e8 */ 0x70c5, 0x0000, 0x0081, 0x6010, 0x984c, 0x3800, 0x0024, 0x0006, /* 2f0 */ 0x10d0, 0x3200, 0x0024, 0xf100, 0x0011, 0xf100, 0x0024, 0xf102, /* 2f8 */ 0x0400, 0x0006, 0x1311, 0x2900, 0x0400, 0x3100, 0x8024, 0x0030, /* 300 */ 0x1293, 0x3413, 0x184c, 0x3c04, 0x4024, 0x3b00, 0x0024, 0x3004, /* 308 */ 0xc024, 0xf400, 0x44d1, 0x3113, 0x0024, 0x3804, 0x4024, 0x3310, /* 310 */ 0x0024, 0x3a00, 0x0024, 0x0006, 0x1212, 0x3200, 0x0024, 0xf100, /* 318 */ 0x13d1, 0xf100, 0x0402, 0x2900, 0x0400, 0xf102, 0x0c00, 0x0030, /* 320 */ 0x12d1, 0x0006, 0x1081, 0x3900, 0x0024, 0x3004, 0xc024, 0xf400, /* 328 */ 0x44d1, 0x3113, 0x0024, 0x3804, 0x4024, 0x3300, 0x0024, 0x3a00, /* 330 */ 0x0024, 0xf400, 0x4440, 0x6010, 0x0024, 0x1fee, 0xe002, 0x2800, /* 338 */ 0x6bc8, 0x0006, 0x0f00, 0x3800, 0x0024, 0x0006, 0x0010, 0xb886, /* 340 */ 0x0040, 0x30f0, 0x4024, 0x6c92, 0x40c3, 0x3810, 0x0024, 0xb182, /* 348 */ 0x23c1, 0x0006, 0x0950, 0x3000, 0x0024, 0x6090, 0x0024, 0x6cd2, /* 350 */ 0x2000, 0x0000, 0x0000, 0x2800, 0x70c8, 0x0000, 0x0024, 0x3800, /* 358 */ 0x0024, 0x0000, 0x0210, 0x3010, 0x0024, 0x30f0, 0x4024, 0x6c92, /* 360 */ 0x0024, 0x3810, 0x0024, 0x38f0, 0x4024, 0x36f4, 0x9813, 0x36f4, /* 368 */ 0x1811, 0x36f0, 0x9803, 0x36f0, 0x1801, 0x3405, 0x9014, 0x36f3, /* 370 */ 0x0024, 0x36f2, 0x0024, 0x2000, 0x0000, 0x0000, 0x0024, 0x0007, /* 378 */ 0x0001, 0x81cc, 0x0006, 0x00f4, 0x3e00, 0x3841, 0x0000, 0x0201, /* 380 */ 0x3e00, 0xb843, 0x3e01, 0x3845, 0x3e04, 0x3812, 0x0030, 0x0410, /* 388 */ 0x3000, 0x0024, 0x6012, 0x0024, 0x0006, 0x08d0, 0x2800, 0x8045, /* 390 */ 0x0000, 0x0181, 0x6012, 0x0024, 0x0006, 0x1250, 0x2800, 0x7e45, /* 398 */ 0x0000, 0x05c1, 0x6012, 0x0024, 0x0030, 0x01d0, 0x2800, 0x7c45, /* 3a0 */ 0x0000, 0x0581, 0x6010, 0x03cc, 0x0000, 0x0024, 0x2800, 0x7a95, /* 3a8 */ 0x0000, 0x0024, 0x3000, 0x8024, 0x0006, 0x1250, 0x3000, 0x0024, /* 3b0 */ 0x6092, 0x0024, 0x3800, 0x4024, 0xf400, 0x4010, 0x3800, 0x8024, /* 3b8 */ 0x36f4, 0x1812, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f0, 0x1801, /* 3c0 */ 0x2000, 0x0000, 0x0000, 0x0024, 0x0030, 0x01d0, 0x3000, 0x0024, /* 3c8 */ 0x0006, 0x1250, 0x3800, 0x0024, 0xf400, 0x4010, 0x3000, 0x0024, /* 3d0 */ 0x0030, 0x0190, 0x2800, 0x7a80, 0x3800, 0x0024, 0x3000, 0x0024, /* 3d8 */ 0x6090, 0x0024, 0x3800, 0x0024, 0xf400, 0x4010, 0x3000, 0x0024, /* 3e0 */ 0x0030, 0x0190, 0x2800, 0x7a80, 0x3800, 0x0024, 0x3000, 0x0024, /* 3e8 */ 0x6080, 0x0024, 0x0000, 0x0024, 0x2800, 0x8515, 0x0000, 0x0024, /* 3f0 */ 0x0006, 0x1350, 0x0000, 0x0082, 0x0030, 0x0352, 0xb886, 0x0040, /* 3f8 */ 0x30f0, 0x4024, 0x4cd2, 0x0024, 0x3810, 0x0024, 0x38f0, 0x4024, /* 400 */ 0x3a00, 0x0024, 0x3010, 0x0024, 0x30f0, 0x4024, 0x0030, 0x0390, /* 408 */ 0x2800, 0x7a80, 0x4180, 0x2001, 0x4090, 0x0024, 0x3800, 0x0024, /* 410 */ 0x0030, 0x0250, 0x3800, 0x0024, 0x0006, 0x1290, 0x3000, 0x0024, /* 418 */ 0x6090, 0x0024, 0x3800, 0x0024, 0x0006, 0x0850, 0x3004, 0x8024, /* 420 */ 0x3223, 0x0024, 0x32e0, 0x4024, 0x6100, 0x0024, 0x0000, 0x0024, /* 428 */ 0x2800, 0x8c81, 0x0000, 0x0024, 0x3233, 0x0024, 0x3804, 0x8024, /* 430 */ 0x3200, 0x0024, 0x6080, 0x0024, 0x0006, 0x0300, 0x2800, 0x8b18, /* 438 */ 0x0000, 0x0024, 0x3800, 0x0024, 0x0006, 0x0850, 0x3004, 0x0024, /* 440 */ 0x3013, 0x0024, 0x3000, 0x0024, 0x0006, 0x1290, 0x3800, 0x0024, /* 448 */ 0x0006, 0x0850, 0x3004, 0x0024, 0x3000, 0x0024, 0x0006, 0x1290, /* 450 */ 0x6080, 0x0024, 0x3000, 0x0024, 0x2800, 0x9115, 0xf400, 0x4010, /* 458 */ 0x3000, 0x0024, 0x0000, 0x0201, 0x0000, 0x0005, 0x0030, 0x0210, /* 460 */ 0xa014, 0x4004, 0x1fff, 0xfe01, 0xae12, 0x0024, 0xc200, 0x0024, /* 468 */ 0x2800, 0x8180, 0x3800, 0x0024, 0x2800, 0x8ec0, 0x3009, 0x0000, /* 470 */ 0x0007, 0x0001, 0x8246, 0x0006, 0x0104, 0x0030, 0x1092, 0x0007, /* 478 */ 0x9250, 0x003f, 0xfc42, 0xb880, 0x184c, 0x3e12, 0x0024, 0x3800, /* 480 */ 0x0024, 0x0030, 0x0290, 0x38f0, 0x0024, 0x3800, 0x0024, 0x0030, /* 488 */ 0x0050, 0x3000, 0x4024, 0xb122, 0x0024, 0x6894, 0x2001, 0x0000, /* 490 */ 0x0141, 0x3a70, 0x4024, 0x0004, 0x1fc1, 0x3a00, 0x4024, 0x0030, /* 498 */ 0x00d2, 0x0030, 0x0001, 0x3a00, 0x4024, 0x0030, 0x0552, 0x3a10, /* 4a0 */ 0x0024, 0x3a00, 0x0024, 0x3000, 0x4024, 0xc122, 0x0024, 0x3800, /* 4a8 */ 0x4024, 0x0030, 0x05d0, 0x0000, 0x03c1, 0x3820, 0x4024, 0x3800, /* 4b0 */ 0x0024, 0x0000, 0x0310, 0x3010, 0x0024, 0x30f0, 0x4024, 0xf2c2, /* 4b8 */ 0x0024, 0x3810, 0x0024, 0x0000, 0x3fc0, 0x38f0, 0x4024, 0x0030, /* 4c0 */ 0x02d0, 0x3000, 0x4024, 0x2912, 0x1400, 0xb104, 0x0024, 0x0006, /* 4c8 */ 0x1312, 0x6802, 0x0024, 0x000d, 0xac00, 0x6012, 0x2801, 0x0000, /* 4d0 */ 0x0024, 0x2800, 0x9dc1, 0x0000, 0x0024, 0x3a00, 0x0024, 0x2909, /* 4d8 */ 0x1b40, 0x3613, 0x0024, 0x0000, 0x0084, 0x0000, 0x1905, 0x2908, /* 4e0 */ 0xbe80, 0x3613, 0x0024, 0x0000, 0x0000, 0x0006, 0x0302, 0x4002, /* 4e8 */ 0x0024, 0x4012, 0x0024, 0x4212, 0x0024, 0xf400, 0x4050, 0x3000, /* 4f0 */ 0x4024, 0x6182, 0x0024, 0x0006, 0x0350, 0x2800, 0xa6c8, 0x0000, /* 4f8 */ 0x0024, 0x4002, 0x0024, 0x4014, 0x0024, 0x0006, 0x0301, 0x4124, /* 500 */ 0x0024, 0x0000, 0x0081, 0x4212, 0x0024, 0x4002, 0x4050, 0x4014, /* 508 */ 0x0003, 0x0006, 0x0301, 0x4122, 0x0024, 0x6192, 0x0024, 0x6090, /* 510 */ 0x4050, 0x3000, 0x4024, 0x0006, 0x0910, 0x6312, 0x0024, 0x6194, /* 518 */ 0x0001, 0x4122, 0x0024, 0x2800, 0x9f80, 0x3800, 0x4024, 0x0006, /* 520 */ 0x12d2, 0x0006, 0x0991, 0x3000, 0x0024, 0x0006, 0x1290, 0x3a00, /* 528 */ 0x0024, 0x3800, 0x0024, 0xf400, 0x4010, 0x2900, 0xb200, 0x0000, /* 530 */ 0x0580, 0x0030, 0x0210, 0x0014, 0x9240, 0x003f, 0xf502, 0x003f, /* 538 */ 0xffc3, 0x3800, 0x0024, 0x0000, 0x0580, 0x0006, 0x1350, 0x3200, /* 540 */ 0x4024, 0x4102, 0x0024, 0x3a00, 0x4024, 0x3810, 0x8024, 0x38f0, /* 548 */ 0xc024, 0x0006, 0x08d0, 0x3800, 0x0024, 0x0030, 0x0690, 0x0000, /* 550 */ 0x8280, 0xb880, 0x2080, 0x3800, 0x0024, 0x6890, 0x2000, 0x0030, /* 558 */ 0x0490, 0x3800, 0x0024, 0x0030, 0x0010, 0x0000, 0x0100, 0x3000, /* 560 */ 0x584c, 0xb100, 0x0024, 0x0000, 0x0024, 0x2800, 0xb185, 0x0000, /* 568 */ 0x0024, 0x003f, 0xfec1, 0x3000, 0x1bcc, 0xb010, 0x0024, 0x2908, /* 570 */ 0x0b80, 0x3800, 0x0024, 0x3613, 0x0024, 0x2910, 0x0180, 0x0000, /* 578 */ 0xae48, 0x0007, 0x0001, 0x1806, 0x0006, 0x8007, 0x0000, 0x0006, /* 580 */ 0x002f, 0x0010, 0x17ff, 0x0000, 0x1a00, 0x1dff, 0x0000, 0x1f00, /* 588 */ 0x3fff, 0x0001, 0x0000, 0x17ff, 0x0001, 0x1c00, 0x3fff, 0x0001, /* 590 */ 0xe000, 0xfffd, 0xffff, 0x0000, 0x0000, 0x180c, 0x180c, 0x0000, /* 598 */ 0x0000, 0x0000, 0x4952, 0x4646, 0xffff, 0xffff, 0x4157, 0x4556, /* 5a0 */ 0x6d66, 0x2074, 0x0010, 0x0000, 0x0001, 0x0001, 0xbb80, 0x0000, /* 5a8 */ 0x7700, 0x0001, 0x0002, 0x0010, 0x6164, 0x6174, 0xffff, 0xffff, /* 5b0 */ 0x0006, 0x8006, 0x0000, 0x0006, 0x0005, 0x183c, 0x183c, 0x0000, /* 5b8 */ 0x0020, 0x0040, 0x0006, 0x8003, 0x0000, 0x0007, 0x0001, 0x5bc0, /* 5c0 */ 0x0006, 0x0009, 0x801c, 0x7fe4, 0x8039, 0x804e, 0x7fb2, 0x809d, /* 5c8 */ 0x809c, 0x7f64, 0x8139, 0x0007, 0x0001, 0x82c8, 0x0006, 0x0018, /* 5d0 */ 0x4080, 0x184c, 0x3e13, 0x780f, 0x2800, 0xb405, 0x4090, 0x380e, /* 5d8 */ 0x2400, 0xb3c0, 0xf400, 0x4417, 0x3110, 0x0024, 0x3f10, 0x0024, /* 5e0 */ 0x36f3, 0x8024, 0x36f3, 0x580f, 0x2000, 0x0000, 0x0000, 0x0024, /* 5e8 */ 0x0007, 0x0001, 0x82d4, 0x0006, 0x002a, 0x3e11, 0xb807, 0x3009, /* 5f0 */ 0x384a, 0x3e11, 0x3805, 0x3e10, 0xb803, 0x3e00, 0x4442, 0x0001, /* 5f8 */ 0x800a, 0xbf8e, 0x8443, 0xfe06, 0x0045, 0x3011, 0x0401, 0x545e, /* 600 */ 0x0385, 0x525e, 0x2040, 0x72ce, 0x1bc1, 0x48ba, 0x9803, 0x4588, /* 608 */ 0x4885, 0x6fee, 0x1bc2, 0x4ffe, 0x9805, 0xf6fe, 0x1bc4, 0xf7f0, /* 610 */ 0x2046, 0x3801, 0xdbca, 0x2000, 0x0000, 0x36f1, 0x9807, }; const uint16_t patch_size = 1567; DEBUG("Patching...\n"); _spi->select_vs1053_xcs(); SPI.beginTransaction(*_spi_settings); for (int i=0; i> 8); SPI.transfer(val & 0xFF); _wait(); } } else { /* Copy run, copy n samples */ while (n--) { val = patch_data[i++]; SPI.transfer(val >> 8); SPI.transfer(val & 0xFF); _wait(); } } } SPI.endTransaction(); _spi->select_vs1053_xcs(false); DEBUG("Patch sent.\n"); } void Player::_write_data(uint8_t* buffer) { _spi->select_vs1053_xdcs(); SPI.beginTransaction(*_spi_settings); for (uint i=0; iselect_vs1053_xdcs(false); } uint16_t Player::_read_wram(uint16_t address) { DEBUG("Reading WRAM address 0x%04X...\n", address); _write_control_register(SCI_WRAMADDR, address); uint16_t r1 = _read_control_register(SCI_WRAM); _write_control_register(SCI_WRAMADDR, address); uint16_t r2 = _read_control_register(SCI_WRAM); if (r1 == r2) return r1; DEBUG("Reading WRAM resulted in different values: 0x%04X and 0x%04X.\n", r1, r2); _write_control_register(SCI_WRAMADDR, address); r1 = _read_control_register(SCI_WRAM); if (r1 == r2) return r1; DEBUG("Reading WRAM resulted in different values: 0x%04X and 0x%04X.\n", r1, r2); _write_control_register(SCI_WRAMADDR, address); r2 = _read_control_register(SCI_WRAM); if (r1 == r2) return r1; DEBUG("Reading WRAM resulted in different values: 0x%04X and 0x%04X.\n", r1, r2); DEBUG("Returning last value (0x%04X)...\n", r2); return r2; } int8_t Player::_get_endbyte() { int8_t endbyte = _read_wram(ADDR_ENDBYTE) & 0xFF; DEBUG("Endbyte is 0x%02X.\n", endbyte); return endbyte; } void Player::set_volume(uint8_t vol, bool save) { if (save) { _volume = vol; } INFO("Setting volume to %d\n", vol); vol = 0xFF - vol; uint16_t value = (vol<<8)|vol; DEBUG("Setting volume register to 0x%04X\n", value); _write_control_register(SCI_VOL, value); } void Player::vol_up() { if (!is_playing()) return; uint16_t vol = _volume + VOLUME_STEP; if (vol > VOLUME_MAX) vol=VOLUME_MAX; set_volume(vol); } void Player::vol_down() { if (!is_playing()) return; int16_t vol = _volume - VOLUME_STEP; if (vol < VOLUME_MIN) vol=VOLUME_MIN; set_volume(vol); } void Player::_mute() { INFO("Muting.\n"); _speaker_off(); set_volume(1, false); } void Player::_unmute() { INFO("Unmuting.\n"); set_volume(_volume, false); _speaker_on(); } void Player::track_next() { if (_state != playing) return; if (!_current_playlist->has_track_next()) { return; } stop(); _current_playlist->track_next(); play(); } void Player::track_prev() { if (_state != playing) return; if (_current_play_position > 100000) { stop(); _current_playlist->track_restart(); play(); } else { if (!_current_playlist->has_track_prev()) { return; } stop(); _current_playlist->track_prev(); play(); } } void Player::set_track(uint8_t id) { stop(); _current_playlist->set_track(id); play(); } bool Player::is_playing() { return _state == playing; } bool Player::play(Playlist* p) { _current_playlist = p; return play(); } bool Player::play() { if (_state == sleeping || _state == recording) _wakeup(); if (_state != idle) return false; if (_current_playlist == NULL) return false; if (_current_playlist->get_file_count()==0) return false; _speaker_on(); _current_playlist->start(); String file; if (!_current_playlist->get_current_file(&file)) { return false; } uint32_t position = _current_playlist->get_position(); _state = playing; _play_file(file, position); _controller->send_player_status(); return true; } void Player::_play_file(String file, uint32_t file_offset) { INFO("play_file('%s', %d)\n", file.c_str(), file_offset); _spi->select_sd(); if (file.startsWith("/")) { _file = new SDDataSource(file); } else if (file.startsWith("http")) { _file = new HTTPSDataSource(file); } else { return; } _file_size = _file->size(); _spi->select_sd(false); if (!_file || !_file->usable()) { DEBUG("Could not open file %s", file.c_str()); return; } DEBUG("Resetting SCI_DECODE_TIME...\n"); _write_control_register(SCI_DECODE_TIME, 0); DEBUG("Resetting SS_DO_NOT_JUMP...\n"); _write_control_register(SCI_STATUS, _read_control_register(SCI_STATUS) & ~SS_DO_NOT_JUMP); delay(100); _spi->select_sd(); if (file_offset == 0) { _file->skip_id3_tag(); } _refills = 0; _current_play_position = _file->position(); _spi->select_sd(false); _skip_to = file_offset; if (_skip_to>0) _mute(); else _speaker_on(); INFO("Now playing.\n"); _controller->send_player_status(); } void Player::_flush(uint count, int8_t byte) { _spi->select_vs1053_xdcs(); SPI.beginTransaction(*_spi_settings); for(uint i=0; iselect_vs1053_xdcs(false); } void Player::_finish_playing() { uint8_t endbyte = _get_endbyte(); _flush(2052, endbyte); _write_control_register(SCI_MODE, _read_control_register(SCI_MODE) | SM_CANCEL); for (int i=0; i<64; i++) { _flush(32, endbyte); uint16_t mode = _read_control_register(SCI_MODE); if ((mode & SM_CANCEL) == 0) return; } // If we reached this, the Chip didn't stop. That should not happen. // (That's written in the manual.) // Reset the chip. init(); } void Player::stop(bool turn_speaker_off) { if (_state != playing) return; INFO("Stopping...\n"); _current_playlist->set_position(_current_play_position); _controller->pm->persist(_current_playlist); _state = stopping; _stop_delay = 0; _write_control_register(SCI_MODE, _read_control_register(SCI_MODE) | SM_CANCEL); uint8_t endbyte = _get_endbyte(); while (true) { _refill(); uint16_t mode = _read_control_register(SCI_MODE); if ((mode & SM_CANCEL) == 0) { _flush(2052, endbyte); _finish_stopping(turn_speaker_off); break; } else if (_stop_delay > 2048) { init(); break; } _stop_delay++; } } void Player::_finish_stopping(bool turn_speaker_off) { if (turn_speaker_off) _speaker_off(); _state = idle; _stopped_at = millis(); if (_file) { _file->close(); delete _file; } _current_play_position = 0; _file_size = 0; INFO("Stopped.\n"); _controller->send_player_status(); } void Player::_refill() { _spi->select_sd(); _refills++; if (_refills % 1000 == 0) DEBUG("."); uint8_t result = _file->read(_buffer, sizeof(_buffer)); _spi->select_sd(false); if (result == 0) { // File is over. DEBUG("EOF reached.\n"); _skip_to = 0; _finish_playing(); _finish_stopping(false); if (_current_playlist->has_track_next()) { _current_playlist->track_next(); play(); } else { _current_playlist->reset(); _controller->send_player_status(); } return; } _current_play_position+=result; _write_data(_buffer); if (_skip_to > 0) { if (_skip_to > _file->position()) { uint16_t status = _read_control_register(SCI_STATUS); if ((status & SS_DO_NOT_JUMP) == 0) { DEBUG("Skipping to %d.\n", _skip_to); _flush(2048, _get_endbyte()); _spi->select_sd(); _file->seek(_skip_to); _spi->select_sd(false); _skip_to = 0; _unmute(); _controller->send_position(); } } else { _skip_to = 0; _unmute(); } } } bool Player::_refill_needed() { return _state==playing || _state==stopping; } bool Player::loop() { if (PIN_VS1053_DREQ() && _refill_needed()) { _refill(); return true; } if (_state == recording) { DEBUG("r"); uint16_t samples_available = _read_control_register(SCI_HDAT1, false); uint16_t vu_value = _read_control_register(SCI_AICTRL0, false); DEBUG("Samples available: %4d, VU meter: 0x%04X\n", samples_available, vu_value); if (samples_available >= 500) { unsigned long sum = 0; for (int i=0; i<500; i++) { uint16_t sample = _read_control_register(SCI_HDAT0, false); sum += sample * sample; } double result = sqrt(sum / 500); DEBUG("Loudness: %f", result); } } if (_state == idle && _stopped_at < millis() - VS1053_SLEEP_DELAY) { _sleep(); //_record(); } return false; } String Player::json() { DynamicJsonDocument json(10240); json["_type"] = "player"; json["playing"] = is_playing(); if (_current_playlist) { JsonObject playlist = json.createNestedObject("playlist"); _current_playlist->json(playlist); } else { json["playlist"] = nullptr; } JsonObject volume = json.createNestedObject("volume"); volume["current"] = _volume; volume["min"] = VOLUME_MIN; volume["max"] = VOLUME_MAX; volume["step"] = VOLUME_STEP; return json.as(); } String Player::position_json() { if (!is_playing()) return "null"; DynamicJsonDocument json(200); json["_type"] = "position"; json["position"] = _current_play_position; json["file_size"] = _file_size; return json.as(); }