Skip to content

Commit 027793b

Browse files
committed
Compile error availableToWrite
1 parent eb8b1d9 commit 027793b

File tree

5 files changed

+231
-8
lines changed

5 files changed

+231
-8
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
# Stream Input from an AudioKit to CSV Output
3+
4+
## General Description:
5+
6+
We implement a AudioKit source: We stream the sound input which we read in from the I2S interface and display it on the Arduino Serial Plotter.
7+
8+
<img src="https://pschatzmann.github.io/arduino-audio-tools/resources/audio-toolkit.png" alt="Audio Kit" />
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* @file streams-i2s-csv.ino
3+
* @author Phil Schatzmann
4+
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-stream/stream-i2s-csv/README.md
5+
*
6+
* @author Phil Schatzmann
7+
* @copyright GPLv3
8+
*/
9+
10+
11+
#include "AudioTools.h"
12+
13+
using namespace audio_tools;
14+
15+
I2SStream i2sStream; // Access I2S as stream
16+
CsvStream<int32_t> csvStream(Serial);
17+
StreamCopy copier(csvStream, i2sStream); // copy i2sStream to csvStream
18+
19+
// Arduino Setup
20+
void setup(void) {
21+
Serial.begin(115200);
22+
AudioLogger::instance().begin(Serial, AudioLogger::Info);
23+
24+
auto cfg = i2sStream.defaultConfig(RX_MODE);
25+
cfg.bits_per_sample = 32;
26+
cfg.channels = 2;
27+
cfg.sample_rate = 44100;
28+
cfg.is_master = true;
29+
cfg.i2s_format = I2S_MSB_FORMAT; // or try with I2S_LSB_FORMAT
30+
i2sStream.begin(cfg);
31+
32+
// make sure that we have the correct channels set up
33+
csvStream.begin(cfg);
34+
35+
}
36+
37+
// Arduino loop - copy data
38+
void loop() {
39+
copier.copy();
40+
}

src/AudioDevices/ESP32AudioKit/AudioKit.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,8 @@ struct ConfigES8388 : public I2SConfig {
339339
int pin_i2c_sda = I2C_MASTER_SDA_IO;
340340

341341
// Define final input or output device
342-
es_adc_input_t input_config = ADC_INPUT_MIC1; // or ADC_INPUT_MIC2
343-
es_codec_dac_output_t output_config = DAC_OUTPUT_ALL;
342+
es_adc_input_t input_device = ADC_INPUT_MIC1; // or ADC_INPUT_MIC2
343+
es_codec_dac_output_t output_device = DAC_OUTPUT_ALL;
344344
es_i2s_clock_t *clock_config = nullptr;
345345

346346
bool is_headphone_detection = false;
@@ -429,11 +429,11 @@ class AudioKitStream : public AudioStream {
429429
LOGE("Error: setFormat failed");
430430
}
431431
if (cfg.rx_tx_mode == RX_MODE) {
432-
if (!configAdcInput(cfg.input_config)) {
432+
if (!configAdcInput(cfg.input_device)) {
433433
LOGE("Error: configAdcInput failed");
434434
}
435435
} else {
436-
if (!configDacOutput(cfg.output_config)) {
436+
if (!configDacOutput(cfg.output_device)) {
437437
LOGE("Error: configDacOutput failed");
438438
}
439439
}

src/AudioExperiments/AudioSPDIF.h

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
#pragma once
2+
3+
#include "AudioConfig.h"
4+
#include "AudioI2S/I2SConfig.h"
5+
#include "AudioI2S/I2SStream.h"
6+
#include "AudioTools/AudioStreams.h"
7+
8+
#define LEFTCHANNEL 0
9+
#define RIGHTCHANNEL 1
10+
11+
typedef int16_t frame[2];
12+
13+
// BMC (Biphase Mark Coded) values (bit order reversed, i.e. LSB first)
14+
static const uint16_t spdif_bmclookup[256] PROGMEM = {
15+
0xcccc, 0x4ccc, 0x2ccc, 0xaccc, 0x34cc, 0xb4cc, 0xd4cc, 0x54cc, 0x32cc,
16+
0xb2cc, 0xd2cc, 0x52cc, 0xcacc, 0x4acc, 0x2acc, 0xaacc, 0x334c, 0xb34c,
17+
0xd34c, 0x534c, 0xcb4c, 0x4b4c, 0x2b4c, 0xab4c, 0xcd4c, 0x4d4c, 0x2d4c,
18+
0xad4c, 0x354c, 0xb54c, 0xd54c, 0x554c, 0x332c, 0xb32c, 0xd32c, 0x532c,
19+
0xcb2c, 0x4b2c, 0x2b2c, 0xab2c, 0xcd2c, 0x4d2c, 0x2d2c, 0xad2c, 0x352c,
20+
0xb52c, 0xd52c, 0x552c, 0xccac, 0x4cac, 0x2cac, 0xacac, 0x34ac, 0xb4ac,
21+
0xd4ac, 0x54ac, 0x32ac, 0xb2ac, 0xd2ac, 0x52ac, 0xcaac, 0x4aac, 0x2aac,
22+
0xaaac, 0x3334, 0xb334, 0xd334, 0x5334, 0xcb34, 0x4b34, 0x2b34, 0xab34,
23+
0xcd34, 0x4d34, 0x2d34, 0xad34, 0x3534, 0xb534, 0xd534, 0x5534, 0xccb4,
24+
0x4cb4, 0x2cb4, 0xacb4, 0x34b4, 0xb4b4, 0xd4b4, 0x54b4, 0x32b4, 0xb2b4,
25+
0xd2b4, 0x52b4, 0xcab4, 0x4ab4, 0x2ab4, 0xaab4, 0xccd4, 0x4cd4, 0x2cd4,
26+
0xacd4, 0x34d4, 0xb4d4, 0xd4d4, 0x54d4, 0x32d4, 0xb2d4, 0xd2d4, 0x52d4,
27+
0xcad4, 0x4ad4, 0x2ad4, 0xaad4, 0x3354, 0xb354, 0xd354, 0x5354, 0xcb54,
28+
0x4b54, 0x2b54, 0xab54, 0xcd54, 0x4d54, 0x2d54, 0xad54, 0x3554, 0xb554,
29+
0xd554, 0x5554, 0x3332, 0xb332, 0xd332, 0x5332, 0xcb32, 0x4b32, 0x2b32,
30+
0xab32, 0xcd32, 0x4d32, 0x2d32, 0xad32, 0x3532, 0xb532, 0xd532, 0x5532,
31+
0xccb2, 0x4cb2, 0x2cb2, 0xacb2, 0x34b2, 0xb4b2, 0xd4b2, 0x54b2, 0x32b2,
32+
0xb2b2, 0xd2b2, 0x52b2, 0xcab2, 0x4ab2, 0x2ab2, 0xaab2, 0xccd2, 0x4cd2,
33+
0x2cd2, 0xacd2, 0x34d2, 0xb4d2, 0xd4d2, 0x54d2, 0x32d2, 0xb2d2, 0xd2d2,
34+
0x52d2, 0xcad2, 0x4ad2, 0x2ad2, 0xaad2, 0x3352, 0xb352, 0xd352, 0x5352,
35+
0xcb52, 0x4b52, 0x2b52, 0xab52, 0xcd52, 0x4d52, 0x2d52, 0xad52, 0x3552,
36+
0xb552, 0xd552, 0x5552, 0xccca, 0x4cca, 0x2cca, 0xacca, 0x34ca, 0xb4ca,
37+
0xd4ca, 0x54ca, 0x32ca, 0xb2ca, 0xd2ca, 0x52ca, 0xcaca, 0x4aca, 0x2aca,
38+
0xaaca, 0x334a, 0xb34a, 0xd34a, 0x534a, 0xcb4a, 0x4b4a, 0x2b4a, 0xab4a,
39+
0xcd4a, 0x4d4a, 0x2d4a, 0xad4a, 0x354a, 0xb54a, 0xd54a, 0x554a, 0x332a,
40+
0xb32a, 0xd32a, 0x532a, 0xcb2a, 0x4b2a, 0x2b2a, 0xab2a, 0xcd2a, 0x4d2a,
41+
0x2d2a, 0xad2a, 0x352a, 0xb52a, 0xd52a, 0x552a, 0xccaa, 0x4caa, 0x2caa,
42+
0xacaa, 0x34aa, 0xb4aa, 0xd4aa, 0x54aa, 0x32aa, 0xb2aa, 0xd2aa, 0x52aa,
43+
0xcaaa, 0x4aaa, 0x2aaa, 0xaaaa};
44+
45+
const uint32_t VUCP_PREAMBLE_B = 0xCCE80000; // 11001100 11101000
46+
const uint32_t VUCP_PREAMBLE_M = 0xCCE20000; // 11001100 11100010
47+
const uint32_t VUCP_PREAMBLE_W = 0xCCE40000; // 11001100 11100100
48+
49+
/**
50+
* @brief SPDIF configuration
51+
* We only support 16 bits per sample
52+
*/
53+
struct SPDIFConfig {
54+
int port_no = 0; // processor dependent port
55+
int pin_data = PIN_I2S_DATA_OUT;
56+
int sample_rate = 44100;
57+
int channels = 2;
58+
};
59+
60+
/**
61+
* @brief Output as SPDIF on the data output pin
62+
*
63+
*/
64+
class SPDIFStream : public AudioStream {
65+
public:
66+
SPDIFStream() = default;
67+
68+
bool begin(SPDIFConfig cfg) {
69+
this->cfg = cfg;
70+
i2s_cfg.sample_rate = cfg.sample_rate * 2; // 2 x sampling_rate
71+
i2s_cfg.bits_per_sample = 32;
72+
i2s_cfg.use_apll = true;
73+
i2s_cfg.channels = 2;
74+
i2s_cfg.pin_ws = -1;
75+
i2s_cfg.pin_bck = -1;
76+
i2s_cfg.pin_data = cfg.pin_data;
77+
78+
i2s.begin(i2s_cfg);
79+
i2sOn = true;
80+
frame_num = 0;
81+
}
82+
83+
bool end() {
84+
i2s.end();
85+
frame_num = 0;
86+
i2sOn = false;
87+
return true;
88+
}
89+
90+
size_t write(uint8_t *values, size_t len) {
91+
size_t result = 0;
92+
int16_t *v = (int16_t *)values;
93+
if (cfg.channels == 2) {
94+
for (int j = 0; j < len / 32; j++) {
95+
// provide the 2 channels from the data
96+
result += processFrame(v[j], v[j + 1]);
97+
}
98+
} else if (cfg.channels == 1) {
99+
for (int j = 0; j < len / 16; j++) {
100+
// generate 2 channels
101+
result += processFrame(v[j], v[j]);
102+
}
103+
}
104+
return result;
105+
}
106+
107+
protected:
108+
SPDIFConfig cfg;
109+
I2SStream i2s;
110+
I2SConfig i2s_cfg;
111+
bool i2sOn;
112+
uint8_t frame_num = 0;
113+
114+
// process a single frame
115+
int processFrame(int16_t left, int16_t right) {
116+
if (!i2sOn) return true; // Sink the data
117+
int16_t ms[2];
118+
uint16_t hi, lo, aux;
119+
uint32_t buf[4];
120+
121+
ms[0] = left;
122+
ms[1] = right;
123+
124+
// S/PDIF encoding:
125+
// http://www.hardwarebook.info/S/PDIF
126+
// Original sources: Teensy Audio Library
127+
// https://github.com/PaulStoffregen/Audio/blob/master/output_spdif2.cpp
128+
//
129+
// Order of bits, before BMC encoding, from the definition of SPDIF format
130+
// PPPP AAAA SSSS SSSS SSSS SSSS SSSS VUCP
131+
// are sent rearanged as
132+
// VUCP PPPP AAAA 0000 SSSS SSSS SSSS SSSS
133+
// This requires a bit less shifting as 16 sample bits align and can be
134+
// BMC encoded with two table lookups (and at the same time flipped to LSB
135+
// first). There is no separate word-clock, so hopefully the receiver won't
136+
// notice.
137+
138+
uint16_t sample_left = ms[LEFTCHANNEL];
139+
// BMC encode and flip left channel bits
140+
hi = spdif_bmclookup[(uint8_t)(sample_left >> 8)];
141+
lo = spdif_bmclookup[(uint8_t)sample_left];
142+
// Low word is inverted depending on first bit of high word
143+
lo ^= (~((int16_t)hi) >> 16);
144+
buf[0] = ((uint32_t)lo << 16) | hi;
145+
// Fixed 4 bits auxillary-audio-databits, the first used as parity
146+
// Depending on first bit of low word, invert the bits
147+
aux = 0xb333 ^ (((uint32_t)((int16_t)lo)) >> 17);
148+
// Send 'B' preamble only for the first frame of data-block
149+
if (frame_num == 0) {
150+
buf[1] = VUCP_PREAMBLE_B | aux;
151+
} else {
152+
buf[1] = VUCP_PREAMBLE_M | aux;
153+
}
154+
155+
uint16_t sample_right = ms[RIGHTCHANNEL];
156+
// BMC encode right channel, similar as above
157+
hi = spdif_bmclookup[(uint8_t)(sample_right >> 8)];
158+
lo = spdif_bmclookup[(uint8_t)sample_right];
159+
lo ^= (~((int16_t)hi) >> 16);
160+
buf[2] = ((uint32_t)lo << 16) | hi;
161+
aux = 0xb333 ^ (((uint32_t)((int16_t)lo)) >> 17);
162+
buf[3] = VUCP_PREAMBLE_W | aux;
163+
164+
// Assume DMA buffers are multiples of 16 bytes. Either we write all bytes
165+
// or none.
166+
int len = 8 * cfg.channels;
167+
size_t bytes_written = i2s.write((const uint8_t *)&buf, len);
168+
// If we didn't write all bytes, return false early and do not increment
169+
// frame_num
170+
if (bytes_written != len) return 0;
171+
// Increment and rotate frame number
172+
if (++frame_num > 191) frame_num = 0;
173+
return len;
174+
}
175+
};

src/AudioLibs/AudioA2DP.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ class A2DPStream : public AudioStream, public AudioBaseInfoSource {
190190
bool isBufferFull = true;
191191
while(isBufferFull){
192192
lockSemaphore(true);
193-
isBufferFull = a2dp_buffer->availableToWrite()<len;
193+
isBufferFull = a2dp_buffer->availableForWrite()<len;
194194
lockSemaphore(false);
195195

196196
// we wait until the buffer is full
@@ -251,8 +251,8 @@ class A2DPStream : public AudioStream, public AudioBaseInfoSource {
251251
return a2dp_buffer==nullptr ? 0 : a2dp_buffer->available();
252252
}
253253

254-
virtual int availableToWrite() {
255-
return a2dp_buffer==nullptr ? 0 : a2dp_buffer->availableToWrite();
254+
virtual int availableForWrite() {
255+
return a2dp_buffer==nullptr ? 0 : a2dp_buffer->availableForWrite();
256256
}
257257

258258
virtual void setVolume(float volume){
@@ -311,7 +311,7 @@ class A2DPStream : public AudioStream, public AudioBaseInfoSource {
311311
if (is_a2dp_active) {
312312
if (A2DPStream_self->lockSemaphore(true)) {
313313
isAvailable = a2dp_buffer->available()>0;
314-
LOGD("buffer: %d, free %d",a2dp_buffer->available(), a2dp_buffer->availableToWrite() )
314+
LOGD("buffer: %d, free %d",a2dp_buffer->available(), a2dp_buffer->availableForWrite() )
315315
isLocked = true;
316316
} else {
317317
LOGE("lock failed");

0 commit comments

Comments
 (0)