forked from W4D/soundcube-firmware
streaming max 4 stereo wave files at the same time
This commit is contained in:
@ -3,21 +3,53 @@
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
class RingBuffer{
|
class RingBuffer{
|
||||||
public:
|
public:
|
||||||
|
RingBuffer() {}
|
||||||
RingBuffer(size_t size) : bufferSize(size) {}
|
RingBuffer(size_t size) : bufferSize(size) {}
|
||||||
|
|
||||||
|
void setSize(size_t size) {
|
||||||
|
bufferSize = size;
|
||||||
|
}
|
||||||
|
|
||||||
void begin(){
|
void begin(){
|
||||||
buffer = new T[bufferSize];
|
buffer = new T[bufferSize];
|
||||||
};
|
}
|
||||||
|
|
||||||
bool push(T data){
|
bool push(T data){
|
||||||
|
if(counter < bufferSize){
|
||||||
|
buffer[write] = data;
|
||||||
|
write = (write+1) % bufferSize;
|
||||||
counter++;
|
counter++;
|
||||||
};
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
T pop(){
|
T pop(){
|
||||||
|
T retval;
|
||||||
|
if(counter > 0) {
|
||||||
counter--;
|
counter--;
|
||||||
};
|
retval = buffer[read];
|
||||||
|
read = (read+1) % bufferSize;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEmpty(){
|
||||||
|
return counter == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isFull(){
|
||||||
|
return counter == bufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
int size(){
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t bufferSize = 0;
|
size_t bufferSize = 0;
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
bool
|
int write = 0;
|
||||||
T buffer[];
|
int read = 0;
|
||||||
}
|
T *buffer;
|
||||||
|
};
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
#include <RingBuf.h>
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <ArduinoJson.hpp>
|
#include <ArduinoJson.hpp>
|
||||||
|
|
||||||
@ -10,20 +9,24 @@
|
|||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
#include <SD.h>
|
#include <SD.h>
|
||||||
#include "codec.h"
|
#include "codec.h"
|
||||||
|
#include "ringbuffer.h"
|
||||||
|
|
||||||
#define HAPTIC 1
|
#define HAPTIC 1
|
||||||
#define AURAL 1
|
#define AURAL 1
|
||||||
#define UI_SAMPLERATE 22050
|
#define UI_SAMPLERATE 22050
|
||||||
|
|
||||||
#define SIZE 256
|
#define SIZE 1024
|
||||||
#define RINGBUFFER 1024
|
#define RINGBUFFER 16384
|
||||||
#define ECHO 96000
|
#define ECHO 24000
|
||||||
|
|
||||||
|
#define NSTREAMS 4
|
||||||
|
|
||||||
int16_t buffer[SIZE];
|
int16_t buffer[SIZE];
|
||||||
int16_t buffer2[ECHO];
|
int16_t buffer2[ECHO];
|
||||||
|
|
||||||
RingBuf<int16_t, RINGBUFFER> ringbuffer;
|
RingBuffer<int16_t> ringbuffer[NSTREAMS];
|
||||||
|
|
||||||
File stream1;
|
File streams[NSTREAMS];
|
||||||
|
|
||||||
I2S i2s(INPUT_PULLUP);
|
I2S i2s(INPUT_PULLUP);
|
||||||
|
|
||||||
@ -40,6 +43,12 @@ int lut_ring_cw[48] = {39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,
|
|||||||
int lut_ring_ccw[48] = {40,41,42,43,44,45,46,47,48,49,50,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39};
|
int lut_ring_ccw[48] = {40,41,42,43,44,45,46,47,48,49,50,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39};
|
||||||
int lut_matrix[13] = {56,55,57,58,59,62,61,60,63,64,65,67,66};
|
int lut_matrix[13] = {56,55,57,58,59,62,61,60,63,64,65,67,66};
|
||||||
|
|
||||||
|
int active = 0;
|
||||||
|
int active_led_ring = 0;
|
||||||
|
|
||||||
|
uint32_t lastTime = 0;
|
||||||
|
int32_t position = 0;
|
||||||
|
|
||||||
CRGB ui_leds[74];
|
CRGB ui_leds[74];
|
||||||
CRGB edge_leds[11];
|
CRGB edge_leds[11];
|
||||||
|
|
||||||
@ -95,7 +104,11 @@ void codec_transmit() {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
for(int i = 0; i < count; i++){
|
for(int i = 0; i < count; i++){
|
||||||
buffer[i] += ringbuffer.pop();
|
int16_t sample = 0;
|
||||||
|
for(int j = 0; j < NSTREAMS; j++){
|
||||||
|
if(!ringbuffer[j].isEmpty()) sample = ringbuffer[j].pop();
|
||||||
|
buffer[i] += (sample / 4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i2s.write((const uint8_t *)&buffer, count * sizeof(int16_t));
|
i2s.write((const uint8_t *)&buffer, count * sizeof(int16_t));
|
||||||
@ -131,7 +144,13 @@ void tca_irq() {
|
|||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
//Serial.begin();
|
//Serial.begin();
|
||||||
//delay(2000);
|
//delay(1000);
|
||||||
|
|
||||||
|
i2s.setFrequency(48000);
|
||||||
|
|
||||||
|
for(int i = 0; i < NSTREAMS; i++){
|
||||||
|
ringbuffer[i].setSize(RINGBUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
FastLED.addLeds<NEOPIXEL, 4>(edge_leds, 11);
|
FastLED.addLeds<NEOPIXEL, 4>(edge_leds, 11);
|
||||||
FastLED.addLeds<NEOPIXEL, 5>(ui_leds, 74);
|
FastLED.addLeds<NEOPIXEL, 5>(ui_leds, 74);
|
||||||
@ -229,26 +248,49 @@ void setup() {
|
|||||||
|
|
||||||
i2s.setBuffers(6, SIZE * sizeof(int16_t) / sizeof(uint32_t));
|
i2s.setBuffers(6, SIZE * sizeof(int16_t) / sizeof(uint32_t));
|
||||||
|
|
||||||
|
for(int i = 0; i < NSTREAMS; i++){
|
||||||
|
ringbuffer[i].begin();
|
||||||
|
}
|
||||||
|
|
||||||
if(!i2s.begin(48000)){
|
if(!i2s.begin(48000)){
|
||||||
Serial.println("I2S error!");
|
Serial.println("I2S error!");
|
||||||
while(100);
|
while(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sdInitialized && SD.exists("/piano.wav")) {
|
if(sdInitialized) {
|
||||||
stream1 = SD.open("/piano.wav");
|
for(int i = 0; i < NSTREAMS; i++){
|
||||||
|
char filename[40];
|
||||||
|
sprintf(filename, "/sound/%d.wav", i+1);
|
||||||
|
if(SD.exists(filename)){
|
||||||
|
streams[i] = SD.open(filename);
|
||||||
|
streams[i].seek(44, SeekSet);
|
||||||
|
} else {
|
||||||
|
for(int k = 0; k < 3; k++){
|
||||||
|
digitalWrite(6, HIGH);
|
||||||
|
delay(20);
|
||||||
|
digitalWrite(6, LOW);
|
||||||
|
delay(50);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if(!ringbuffer.isFull()){
|
||||||
|
// int cnt = 0;
|
||||||
|
// while (!ringbuffer.isFull() && cnt < RINGBUFFER) {
|
||||||
|
// int16_t sample = stream1.read();
|
||||||
|
// ringbuffer.push(sample);
|
||||||
|
// if(!stream1.available()) stream1.seek(48000*6, SeekSet);
|
||||||
|
// cnt++;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
digitalWrite(6, HIGH);
|
digitalWrite(6, HIGH);
|
||||||
delay(50);
|
delay(50);
|
||||||
digitalWrite(6, LOW);
|
digitalWrite(6, LOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
int active = 0;
|
|
||||||
int active_led_ring = 0;
|
|
||||||
|
|
||||||
uint32_t lastTime = 0;
|
|
||||||
int32_t position = 0;
|
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
position = ENC.getCumulativePosition();
|
position = ENC.getCumulativePosition();
|
||||||
|
|
||||||
@ -256,11 +298,18 @@ void loop() {
|
|||||||
if(sd_card_detected) edge_leds[8] = CRGB(0,10,0);
|
if(sd_card_detected) edge_leds[8] = CRGB(0,10,0);
|
||||||
if(!sd_card_detected) edge_leds[8] = CRGB(10,0,0);
|
if(!sd_card_detected) edge_leds[8] = CRGB(10,0,0);
|
||||||
|
|
||||||
if(!ringbuffer.isFull()){
|
for (int i = 0; i < NSTREAMS; i++) {
|
||||||
while (!ringbuffer.isFull()) {
|
if(!ringbuffer[i].isFull()){
|
||||||
int16_t sample = stream1.read();
|
int cnt = 0;
|
||||||
ringbuffer.push(sample);
|
while (!ringbuffer[i].isFull() && cnt < 10000) {
|
||||||
if(!stream1.available()) stream1.seek(0, SeekSet);
|
uint8_t samplebyte[2];
|
||||||
|
streams[i].read(samplebyte, 2);
|
||||||
|
if(!streams[i].available()) streams[i].seek(44, SeekSet);
|
||||||
|
|
||||||
|
int16_t sample = (samplebyte[1] << 8) + samplebyte[0];
|
||||||
|
ringbuffer[i].push(sample);
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,7 +387,7 @@ void loop() {
|
|||||||
ui_leds[lut_ring_ccw[i]] = CRGB(50, 0, 25);
|
ui_leds[lut_ring_ccw[i]] = CRGB(50, 0, 25);
|
||||||
}
|
}
|
||||||
|
|
||||||
FastLED.show();
|
//FastLED.show();
|
||||||
//delay(1); // wait 1ms
|
//delay(1); // wait 1ms
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
18
tools/ringbuffer-test.cpp
Normal file
18
tools/ringbuffer-test.cpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include "ringbuffer.h"
|
||||||
|
|
||||||
|
RingBuffer<int16_t> ringbuffer(25);
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
ringbuffer.begin();
|
||||||
|
|
||||||
|
for(int j = 0; j < 3; j++){
|
||||||
|
for(int i = 0; i < 15; i++){
|
||||||
|
if(!ringbuffer.isFull()) ringbuffer.push(i);
|
||||||
|
}
|
||||||
|
std::cout << "---" << std::endl;
|
||||||
|
for(int i = 0; i < 25; i++){
|
||||||
|
if(!ringbuffer.isEmpty()) ringbuffer.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
49
tools/ringbuffer.h
Normal file
49
tools/ringbuffer.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class RingBuffer{
|
||||||
|
public:
|
||||||
|
RingBuffer(size_t size) : bufferSize(size) {}
|
||||||
|
|
||||||
|
void begin(){
|
||||||
|
buffer = new T[bufferSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool push(T data){
|
||||||
|
std::cout << "write: " << data << std::endl;
|
||||||
|
if(counter < bufferSize){
|
||||||
|
buffer[write] = data;
|
||||||
|
write = (write+1) % bufferSize;
|
||||||
|
counter++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
T pop(){
|
||||||
|
T retval;
|
||||||
|
if(counter > 0) {
|
||||||
|
counter--;
|
||||||
|
retval = buffer[read];
|
||||||
|
read = (read+1) % bufferSize;
|
||||||
|
}
|
||||||
|
std::cout << "read: " << retval << std::endl;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEmpty(){
|
||||||
|
return counter == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isFull(){
|
||||||
|
return counter == bufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t bufferSize = 0;
|
||||||
|
int counter = 0;
|
||||||
|
int write = 0;
|
||||||
|
int read = 0;
|
||||||
|
T *buffer;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user