Bluetooth Controlled Audio Player for nRF52x devices
Control playback and volume of an audio player over Bluetooth
Components and supplies
1
Seeeduino Xiao BLE Sense
1
Stereo Enclosed Speaker - 3W 8Ω
1
SD card module
1
I2S 3W Class D Amplifier Breakout - MAX98357A
1
iPhone
Apps and platforms
1
nrf Conect
Project description
Code
Auto Analog Audio library
BLE Audio Controller - Mbed
cpp
1/* Arduino BLE controlled Audio Player for nRF52 2 * 3 * This is an example of me playing around with BLE control and different 4 * services/characteristics to test the AutoAnalogAudio library. 5 * 6 * Requirements: 7 * 1. nRF52 Device (Tested on nRF52840) 8* 2. SD Card with WAV files: 8-bit, 16-24kHz, Mono 9 * 3. I2S or Analog Amplifier + Speaker connected 10 * 4. Mobile device or 'other' with nRF Connect installed 11 * 12 * Connect via nRF Connect App: 13 * 1. Device should come up as BLE Audio Player 14 * 2. You should see: 15 * a: Common Audio 16* b: Audio Input Type: 17 Send a UTF-8 String to play a file: myfileDirectory/myfilename.wav 18 * c: Audio Input Control Point: 19 Send an Unsigned value between 0-10 to set the volume low-high 20 */ 21 22 23#include <SPI.h> 24#include <SD.h> 25#include <ArduinoBLE.h> 26#include <AutoAnalogAudio.h> 27 28AutoAnalog aaAudio; 29 30/************** USER CONFIG ***********/ 31// File to play on startup 32const char* audioFilename = "far8b16k.wav"; // 8-bit @ 24kHz audio is the max over SD card while BLE is running 33uint8_t SD_CS_PIN = 2; // Set this to your CS pin for the SD card/module 34#define USE_I2S 1 // Set this to 0 for analog (PWM) audio output instead of I2S 35 36/*********************************************************/ 37/* Tested with MAX98357A I2S breakout 38/* BCLK connected to Arduino D1 (p0.03) 39/* LRCK connected to Arduino D3 (p0.29) 40/* DIN connected to Arduino D5 (p0.05) 41/* SD connected to Arduino D6 (p1.11) 42/*********************************************************/ 43 44#define FILENAME_BUFFER_LENGTH 64 45char songName[FILENAME_BUFFER_LENGTH]; 46float volumeControl = 0.2; 47#define AUDIO_BUFFER_SIZE 1600 48 49BLEService audioService("1853"); // BLE LED Service 50 51// BLE Audio Charactaristic 52BLECharacteristic audioDataCharacteristic("2b79", BLERead | BLEWrite, FILENAME_BUFFER_LENGTH); 53BLEByteCharacteristic audioVolumeCharactaristic("2b7b", BLERead | BLEWrite); 54 55void setup() { 56 Serial.begin(115200); 57 while (!Serial) delay(10); 58 59 aaAudio.begin(0, 1, USE_I2S); //Setup aaAudio using DAC and I2S or PWM 60 61 // BLE initialization 62 if (!BLE.begin()) { 63 Serial.println("Starting BLE failed!"); 64 while (1) {}; 65 } 66 67 BLE.setLocalName("BLE Audio Player"); 68 BLE.setAdvertisedService(audioService); 69 70 audioService.addCharacteristic(audioDataCharacteristic); 71 audioService.addCharacteristic(audioVolumeCharactaristic); 72 BLE.addService(audioService); 73 74 BLE.advertise(); 75 Serial.println("BLE Peripheral is now advertising"); 76 77 Serial.print("Init SD card..."); 78 if (!SD.begin(SD_CS_PIN)) { 79 Serial.println("init failed!"); 80 return; 81 } 82 Serial.println("SD init ok"); 83 pinMode(6, OUTPUT); //Connected to SD pin of MAX98357A 84 digitalWrite(6, HIGH); 85 86 playAudio(audioFilename); 87} 88 89void loop() { 90 91 BLEDevice central = BLE.central(); 92 93 if (central) { 94 95 if (central.connected()) { 96 if (audioDataCharacteristic.written()) { 97 memset(songName, 0, sizeof(songName)); 98 audioDataCharacteristic.readValue((uint8_t*)songName, FILENAME_BUFFER_LENGTH); 99 playAudio(songName); 100 Serial.println(songName); 101 } 102 if (audioVolumeCharactaristic.written()) { 103 uint8_t vol; 104 audioVolumeCharactaristic.readValue(vol); 105 volumeControl = vol / 10.0; 106 Serial.print("BLE Set Volume: "); 107 Serial.println(volumeControl); 108 } 109 } 110 } 111 112 loadBuffer(); 113 114 // Control via Serial for testing 115 if (Serial.available()) { 116 char c = Serial.read(); 117 if (c == '=') { 118 volumeControl += 0.1; 119 } else if (c == '-') { 120 volumeControl -= 0.1; 121 volumeControl = max(0.0, volumeControl); 122 } else if (c == 'p') { 123 playAudio("brick/brick24.wav"); 124 } 125 Serial.println(volumeControl); 126 } 127} 128 129/*********************************************************/ 130/* A simple function to handle playing audio files 131/*********************************************************/ 132 133File myFile; 134 135void playAudio(const char* audioFile) { 136 137 if (myFile) { 138 myFile.close(); 139 } 140 //Open the designated file 141 myFile = SD.open(audioFile); 142 143 myFile.seek(22); 144 uint16_t var; 145 uint32_t var2; 146 myFile.read(&var, 2); // Get channels (Stereo or Mono) 147 myFile.read(&var2, 4); // Get Sample Rate 148 aaAudio.setSampleRate(var2, var - 1); 149 150 myFile.seek(34); 151 myFile.read(&var, 2); // Get Bits Per Sample 152 aaAudio.dacBitsPerSample = var; 153 154 myFile.seek(44); //Skip past the WAV header 155} 156 157void loadBuffer() { 158 159 if (myFile.available()) { 160 161 if (aaAudio.dacBitsPerSample == 8) { 162 myFile.read(aaAudio.dacBuffer, AUDIO_BUFFER_SIZE); 163 for (uint32_t i = 0; i < AUDIO_BUFFER_SIZE; i++) { 164 aaAudio.dacBuffer[i] *= volumeControl; 165 } 166 aaAudio.feedDAC(0, AUDIO_BUFFER_SIZE); 167 } else { 168 myFile.read(aaAudio.dacBuffer16, AUDIO_BUFFER_SIZE); 169 for (uint32_t i = 0; i < AUDIO_BUFFER_SIZE / 2; i++) { 170 int16_t sample = aaAudio.dacBuffer16[i]; 171 sample *= volumeControl; 172 aaAudio.dacBuffer16[i] = (uint16_t)sample; 173 } 174 aaAudio.feedDAC(0, AUDIO_BUFFER_SIZE / 2); 175 } 176 177 } else { 178 myFile.seek(44); 179 } 180}
BLE Audio Controller - nRF52
cpp
1/* Arduino BLE controlled Audio Player for nRF52 2 * 3 * This is an example of me playing around with BLE control and different 4 * services/characteristics to test the AutoAnalogAudio library. 5 * 6 * Requirements: 7 * 1. nRF52 Device (Tested on nRF52840) 8* 2. SD Card with WAV files: 8-bit, 16-24kHz, Mono 9 * 3. I2S or Analog Amplifier + Speaker connected 10 * 4. Mobile device or 'other' with nRF Connect installed 11 * 12 * Connect via nRF Connect App: 13 * 1. Device should come up as BLE Audio Player 14 * 2. You should see: 15 * a: Common Audio 16* b: Audio Input Type: 17 Send a UTF-8 String to play a file: myfileDirectory/myfilename.wav 18 * c: Audio Input Control Point: 19 Send an Unsigned value between 0-10 to set the volume low-high 20 */ 21 22 23#include <SPI.h> 24#include <SD.h> 25#include <bluefruit.h> 26#include <AutoAnalogAudio.h> 27 28AutoAnalog aaAudio; 29 30/************** USER CONFIG ***********/ 31// File to play on startup 32const char* audioFilename = "calibrat.wav"; // 8-bit @ 24kHz audio is the max over SD card while BLE is running 33uint8_t SD_CS_PIN = 2; // Set this to your CS pin for the SD card/module 34#define USE_I2S 1 35 36/*********************************************************/ 37/* Tested with MAX98357A I2S breakout 38/* BCLK connected to Arduino D1 (p0.03) 39/* LRCK connected to Arduino D3 (p0.29) 40/* DIN connected to Arduino D5 (p0.05) 41/* SD connected to Arduino D6 (p1.11) 42/*********************************************************/ 43 44char songName[64]; 45float volumeControl = 0.2; 46#define AUDIO_BUFFER_SIZE 1600 47 48BLEService audioService = BLEService(0x1853); 49 50BLECharacteristic audioDataCharacteristic = BLECharacteristic(0x2b79); 51BLECharacteristic audioVolumeCharacteristic = BLECharacteristic(0x2b7b); 52 53uint8_t beaconUuid[16] = { 54 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 55 0x89, 0x9a, 0xab, 0xbc, 0xcd, 0xde, 0xef, 0xf0 56}; 57BLEBeacon beacon(beaconUuid, 1, 2, -54); 58 59 60void setup() { 61 62 Serial.begin(115200); 63 while (!Serial) delay(10); 64 65 Serial.print("Init SD card..."); 66 if (!SD.begin(SD_CS_PIN)) { 67 Serial.println("init failed!"); 68 return; 69 } 70 Serial.println("SD init ok"); 71 72 Bluefruit.begin(); 73 Bluefruit.setName("BLE Audio Player"); 74 audioService.begin(); 75 76 audioDataCharacteristic.setProperties(CHR_PROPS_READ | CHR_PROPS_WRITE); 77 audioDataCharacteristic.setPermission(SECMODE_OPEN, SECMODE_OPEN); 78 audioDataCharacteristic.setMaxLen(64); 79 audioDataCharacteristic.setWriteCallback(playBack); 80 audioDataCharacteristic.begin(); 81 82 audioVolumeCharacteristic.setProperties(CHR_PROPS_READ | CHR_PROPS_WRITE); 83 audioVolumeCharacteristic.setPermission(SECMODE_OPEN, SECMODE_OPEN); 84 audioVolumeCharacteristic.setMaxLen(1); 85 audioVolumeCharacteristic.setWriteCallback(volume); 86 audioVolumeCharacteristic.begin(); 87 88 Bluefruit.Advertising.setBeacon(beacon); 89 Bluefruit.ScanResponse.addName(); 90 Bluefruit.Advertising.restartOnDisconnect(true); 91 Bluefruit.Advertising.setInterval(160, 160); // in unit of 0.625 ms 92 Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode 93 Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds 94 95 pinMode(6, OUTPUT); //Connected to SD pin of MAX98357A 96 digitalWrite(6, HIGH); 97 98 aaAudio.begin(0, 1, USE_I2S); 99 playAudio(audioFilename); 100} 101 102void loop() { 103 104 loadBuffer(); 105 106 // Control via Serial for testing 107 if (Serial.available()) { 108 char c = Serial.read(); 109 if (c == '=') { 110 volumeControl += 0.1; 111 } else if (c == '-') { 112 volumeControl -= 0.1; 113 volumeControl = max(0.0, volumeControl); 114 } else if (c == 'p') { 115 playAudio("brick/brick24.wav"); 116 } 117 Serial.println(volumeControl); 118 } 119 120} 121 122void playBack(uint16_t conn_hdl, BLECharacteristic* chr, uint8_t* data, uint16_t len) { 123 memset(songName, 0, sizeof(songName)); 124 memcpy(songName,data,len); 125 playAudio(songName); 126 Serial.println(songName); 127} 128 129void volume(uint16_t conn_hdl, BLECharacteristic* chr, uint8_t* data, uint16_t len) { 130 volumeControl = data[0] / 10.0; 131 Serial.print("BLE Set Volume: "); 132 Serial.println(volumeControl); 133} 134 135 136/*********************************************************/ 137/* A simple function to handle playing audio files 138/*********************************************************/ 139 140File myFile; 141 142void playAudio(const char* audioFile) { 143 144 if (myFile) { 145 myFile.close(); 146 } 147 //Open the designated file 148 myFile = SD.open(audioFile); 149 150 myFile.seek(22); 151 uint16_t var; 152 uint32_t var2; 153 myFile.read(&var, 2); // Get channels (Stereo or Mono) 154 myFile.read(&var2, 4); // Get Sample Rate 155 aaAudio.setSampleRate(var2, var - 1); 156 157 myFile.seek(34); 158 myFile.read(&var, 2); // Get Bits Per Sample 159 aaAudio.dacBitsPerSample = var; 160 161 myFile.seek(44); //Skip past the WAV header 162} 163 164void loadBuffer() { 165 166 if (myFile.available() > AUDIO_BUFFER_SIZE) { 167 168 if (aaAudio.dacBitsPerSample == 8) { 169 myFile.read(aaAudio.dacBuffer, AUDIO_BUFFER_SIZE); 170 for (uint32_t i = 0; i < AUDIO_BUFFER_SIZE; i++) { 171 aaAudio.dacBuffer[i] *= volumeControl; 172 } 173 aaAudio.feedDAC(0, AUDIO_BUFFER_SIZE); 174 } else { 175 myFile.read(aaAudio.dacBuffer16, AUDIO_BUFFER_SIZE); 176 for (uint32_t i = 0; i < AUDIO_BUFFER_SIZE / 2; i++) { 177 int16_t sample = aaAudio.dacBuffer16[i]; 178 sample *= volumeControl; 179 aaAudio.dacBuffer16[i] = (uint16_t)sample; 180 } 181 aaAudio.feedDAC(0, AUDIO_BUFFER_SIZE / 2); 182 } 183 184 } else { 185 myFile.seek(44); 186 } 187}
Comments
Only logged in users can leave comments