Skip to content

Commit 3dc6dcf

Browse files
committed
Resample experiments
1 parent a8cfd27 commit 3dc6dcf

File tree

7 files changed

+235
-5
lines changed

7 files changed

+235
-5
lines changed

AudioOutputCC3200I2S.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ bool AudioOutputCC3200I2S::ConsumeSample(int16_t sample[2])
101101

102102
writeBuffer->buffer[writeBuffer->position++] = ms[LEFTCHANNEL];
103103
writeBuffer->buffer[writeBuffer->position++] = ms[RIGHTCHANNEL];
104+
return true;
104105
}
105106

106107
void AudioOutputCC3200I2S::flush() {

AudioOutputCC3200I2S.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ class AudioOutputCC3200I2S : public AudioOutput
4545

4646
int GetRate();
4747

48+
bool resample;
49+
uint32_t resampleMaxRate;
50+
4851
protected:
4952
virtual int AdjustI2SRate(int hz) { return hz; }
5053
uint8_t portNo;
@@ -59,6 +62,8 @@ class AudioOutputCC3200I2S : public AudioOutput
5962
BoxAudioBufferTriple* audioBuffer;
6063

6164
bool writeEmptyBuffer();
65+
66+
uint8_t resampleRate = 1;
6267
};
6368

6469
#endif

AudioOutputResample.cpp

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
AudioOutputResample
3+
Adds additional bufferspace to the output chain
4+
5+
Copyright (C) 2017 Earle F. Philhower, III
6+
7+
This program is free software: you can redistribute it and/or modify
8+
it under the terms of the GNU General Public License as published by
9+
the Free Software Foundation, either version 3 of the License, or
10+
(at your option) any later version.
11+
12+
This program is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
GNU General Public License for more details.
16+
17+
You should have received a copy of the GNU General Public License
18+
along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
21+
#include "BaseHeader.h"
22+
#include <Arduino.h>
23+
#include "AudioOutputResample.h"
24+
25+
AudioOutputResample::AudioOutputResample(uint32_t maxRate, AudioOutputCC3200I2S *dest)
26+
{
27+
this->sink = dest;
28+
this->leftSample = 0;
29+
this->rightSample = 0;
30+
31+
this->resampleFactor = 1;
32+
this->resampleCount = 0;
33+
34+
originalSampleRate = this->sink->GetRate();
35+
36+
SetMaxRate(maxRate);
37+
}
38+
39+
AudioOutputResample::~AudioOutputResample() { }
40+
41+
bool AudioOutputResample::SetRate(int hz) {
42+
this->originalSampleRate = hz;
43+
if (this->maxSampleRate >= hz) {
44+
this->resampleFactor = 1;
45+
Log.info("AudioOutputResample SetRate=%i", hz);
46+
return this->sink->SetRate(hz);
47+
}
48+
49+
for (this->resampleFactor = 2; this->resampleFactor < 7; this->resampleFactor++) { // 48000/8000
50+
if (this->maxSampleRate >= (hz / this->resampleFactor))
51+
break;
52+
}
53+
Log.info("AudioOutputResample limited SetRate=%i, hz=%i, resampleFactor=%i", hz / this->resampleFactor, hz, this->resampleFactor);
54+
return sink->SetRate(hz / this->resampleFactor);
55+
}
56+
void AudioOutputResample::SetMaxRate(uint32_t hz) {
57+
switch (hz)
58+
{
59+
case 48000:
60+
case 44100:
61+
case 32000:
62+
case 24000:
63+
case 22050:
64+
case 16000:
65+
case 11025:
66+
case 8000:
67+
this->maxSampleRate = hz;
68+
break;
69+
default:
70+
this->maxSampleRate = 48000;
71+
}
72+
SetRate(this->originalSampleRate);
73+
}
74+
uint32_t AudioOutputResample::GetMaxRate() {
75+
return this->maxSampleRate;
76+
}
77+
int AudioOutputResample::GetRate() {
78+
return this->sink->GetRate();
79+
}
80+
81+
bool AudioOutputResample::SetBitsPerSample(int bits)
82+
{
83+
return this->sink->SetBitsPerSample(bits);
84+
}
85+
86+
bool AudioOutputResample::SetChannels(int channels)
87+
{
88+
return this->sink->SetChannels(channels);
89+
}
90+
91+
bool AudioOutputResample::begin()
92+
{
93+
return this->sink->begin();
94+
}
95+
96+
bool AudioOutputResample::ConsumeSample(int16_t sample[2])
97+
{
98+
if (1==0) { //Slow
99+
this->leftSample += sample[0];
100+
this->rightSample += sample[1];
101+
this->resampleCount++;
102+
if (this->resampleCount >= this->resampleFactor) {
103+
int16_t s[2] = {(int16_t)(leftSample/this->resampleFactor), (int16_t)(rightSample/this->resampleFactor)};
104+
if (!sink->ConsumeSample(s)) {
105+
return false;
106+
} else {
107+
this->leftSample = 0;
108+
this->rightSample = 0;
109+
this->resampleCount = 0;
110+
}
111+
}
112+
} else { //Fast
113+
this->resampleCount++;
114+
if (this->resampleCount >= this->resampleFactor) {
115+
if (!sink->ConsumeSample(sample)) {
116+
return false;
117+
} else {
118+
this->resampleCount = 0;
119+
}
120+
}
121+
}
122+
return true;
123+
}
124+
125+
bool AudioOutputResample::stop()
126+
{
127+
return this->sink->stop();
128+
}
129+
130+

AudioOutputResample.h

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
AudioOutputResample
3+
Adds additional bufferspace to the output chain
4+
5+
Copyright (C) 2017 Earle F. Philhower, III
6+
7+
This program is free software: you can redistribute it and/or modify
8+
it under the terms of the GNU General Public License as published by
9+
the Free Software Foundation, either version 3 of the License, or
10+
(at your option) any later version.
11+
12+
This program is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
GNU General Public License for more details.
16+
17+
You should have received a copy of the GNU General Public License
18+
along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
21+
#ifndef _AUDIOOUTPUTRESAMPLE_H
22+
#define _AUDIOOUTPUTRESAMPLE_H
23+
24+
#include <AudioOutput.h>
25+
#include "AudioOutputCC3200I2S.h"
26+
27+
class AudioOutputResample : public AudioOutput
28+
{
29+
public:
30+
AudioOutputResample(uint32_t maxSampleRate, AudioOutputCC3200I2S *dest);
31+
virtual ~AudioOutputResample() override;
32+
virtual bool SetRate(int hz) override;
33+
virtual bool SetBitsPerSample(int bits) override;
34+
virtual bool SetChannels(int channels) override;
35+
virtual bool begin() override;
36+
virtual bool ConsumeSample(int16_t sample[2]) override;
37+
virtual bool stop() override;
38+
39+
int GetRate();
40+
uint32_t GetMaxRate();
41+
void SetMaxRate(uint32_t hz);
42+
43+
protected:
44+
AudioOutputCC3200I2S *sink;
45+
int32_t leftSample;
46+
int32_t rightSample;
47+
uint32_t maxSampleRate;
48+
uint8_t resampleFactor;
49+
uint8_t resampleCount;
50+
51+
uint32_t originalSampleRate;
52+
};
53+
54+
#endif
55+

BoxCLI.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ void BoxCLI::begin() {
6666
cmdAudio.addFlagArg("p/lay,pause");
6767
cmdAudio.addArg("f/ile/name", "");
6868
cmdAudio.addArg("g/en-limit", "0");
69+
cmdAudio.addArg("b/uffer", "-1");
70+
cmdAudio.addArg("m/axSampleRate", "0");
6971
}
7072

7173
void BoxCLI::loop() {
@@ -387,6 +389,15 @@ void BoxCLI::execAudio() {
387389
String filenameStr = c.getArg("file").getValue();
388390
uint16_t genLimit = (uint16_t)parseNumber(c.getArg("gen-limit").getValue());
389391

392+
uint32_t resampleRate = (uint16_t)parseNumber(c.getArg("maxSampleRate").getValue());
393+
String bufferStr = c.getArg("buffer").getValue();
394+
395+
int32_t buffer = -1;
396+
if (bufferStr != "-1")
397+
buffer = parseNumber(bufferStr);
398+
if (bufferStr != "0" && buffer == 0)
399+
buffer = -1;
400+
390401
if (c.getArg("file").isSet() && filenameStr != "") {
391402
Box.boxDAC.playFile(filenameStr.c_str());
392403
} else if (c.getArg("play").isSet()) {
@@ -395,6 +406,25 @@ void BoxCLI::execAudio() {
395406
if (genLimit > 0)
396407
Box.boxDAC.audioTimeoutMs = genLimit;
397408
Log.info("Generator time limit is set to %ims", Box.boxDAC.audioTimeoutMs);
409+
410+
if (resampleRate > 0) {
411+
Box.boxDAC.audioOutputResample->SetMaxRate(resampleRate);
412+
Log.info("Max Samplerate is set to %ihz", Box.boxDAC.audioOutputResample->GetMaxRate());
413+
}
414+
if (buffer == 0) {
415+
Log.info("Additional buffering disabled.");
416+
Box.boxDAC.audioOutput = Box.boxDAC.audioOutputResample;
417+
} else if (buffer > 0) {
418+
if (buffer <= freeHeapMemory() / 2) {
419+
Box.boxDAC.audioOutput = Box.boxDAC.audioOutputBuffer;
420+
free(Box.boxDAC.audioOutputBuffer);
421+
Box.boxDAC.audioOutputBuffer = new AudioOutputBuffer(buffer, Box.boxDAC.audioOutputResample);
422+
Box.boxDAC.audioOutput = Box.boxDAC.audioOutputBuffer;
423+
Log.info("Additional buffer set to %ib", buffer);
424+
} else {
425+
Log.error("Buffer should not use more than half of the HEAP (%ib)", freeHeapMemory());
426+
}
427+
}
398428
}
399429
}
400430

BoxDAC.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,11 @@ void BoxDAC::begin() {
5252
MAP_PRCMPeripheralClkEnable(PRCM_I2S, PRCM_RUN_MODE_CLK);
5353
MAP_PRCMPeripheralReset(PRCM_I2S);
5454

55-
audioOutput = new AudioOutputCC3200I2S(&audioBuffer);
55+
Log.info("Output");
56+
audioOutputI2S = new AudioOutputCC3200I2S(&audioBuffer);
57+
//audioOutputResample = new AudioOutputResample(48000, audioOutputI2S);
58+
//audioOutputBuffer = new AudioOutputBuffer(4096, audioOutputResample);
59+
audioOutput = audioOutputI2S;
5660

5761
initDACI2C();
5862

@@ -278,7 +282,7 @@ bool BoxDAC::_playWAV(const char* path) {
278282

279283
void BoxDAC::generateFrequency(uint32_t frequency, uint16_t timeoutMs) {
280284
BoxTimer timeout;
281-
uint32_t halfWavelength = (audioOutput->GetRate() / frequency) / 2;
285+
uint32_t halfWavelength = (audioOutputI2S->GetRate() / frequency) / 2;
282286
timeout.setTimer(timeoutMs);
283287

284288
while (timeout.isRunning()) {
@@ -458,7 +462,7 @@ void BoxDAC::beepRaw(uint16_t sin, uint16_t cos, uint32_t length, uint8_t volume
458462
}
459463
void BoxDAC::beepMidi(uint8_t midiId, uint16_t lengthMs, bool async) {
460464
//TODO Check boundaries!
461-
uint16_t samplerate = audioOutput->GetRate();
465+
uint16_t samplerate = audioOutputI2S->GetRate();
462466
int32_t freq = frequencyTable[midiId]; //fixed point /100
463467
int16_t sin = beepTable16000[midiId][0];
464468
int16_t cos = beepTable16000[midiId][1];
@@ -504,7 +508,7 @@ void BoxDAC::beep() {
504508

505509
void BoxDAC::samSay(const char *text, enum ESP8266SAM::SAMVoice voice, uint8_t speed, uint8_t pitch, uint8_t throat, uint8_t mouth, bool sing, bool phoentic) {
506510
#ifdef FEATURE_FLAG_TEXT2SPEECH
507-
int samplerate = audioOutput->GetRate();
511+
int samplerate = audioOutputI2S->GetRate();
508512
audioOutput->flush();
509513
ESP8266SAM* sam = new ESP8266SAM();
510514

BoxDAC.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#include "BoxAudioBufferTriple.h"
1010
#include "AudioOutputCC3200I2S.h"
11+
#include "AudioOutputResample.h"
12+
#include <AudioOutputBuffer.h>
1113
#include <ESP8266SAM.h>
1214
#include "AudioFileSourceFatFs.h"
1315
#include "AudioGeneratorTonie.h"
@@ -62,7 +64,10 @@ class BoxDAC : public EnhancedThread {
6264

6365
BoxAudioBufferTriple::BufferStruct* writeBuffer;
6466

65-
AudioOutputCC3200I2S* audioOutput;
67+
AudioOutputCC3200I2S* audioOutputI2S;
68+
AudioOutputBuffer* audioOutputBuffer;
69+
AudioOutputResample* audioOutputResample;
70+
AudioOutput* audioOutput;
6671
AudioFileSource* audioSource;
6772
AudioGenerator* audioGenerator;
6873
bool audioPlaying = false;

0 commit comments

Comments
 (0)