Skip to content

Commit

Permalink
Resample experiments
Browse files Browse the repository at this point in the history
  • Loading branch information
SciLor committed Jan 27, 2021
1 parent a8cfd27 commit 3dc6dcf
Show file tree
Hide file tree
Showing 7 changed files with 235 additions and 5 deletions.
1 change: 1 addition & 0 deletions AudioOutputCC3200I2S.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ bool AudioOutputCC3200I2S::ConsumeSample(int16_t sample[2])

writeBuffer->buffer[writeBuffer->position++] = ms[LEFTCHANNEL];
writeBuffer->buffer[writeBuffer->position++] = ms[RIGHTCHANNEL];
return true;
}

void AudioOutputCC3200I2S::flush() {
Expand Down
5 changes: 5 additions & 0 deletions AudioOutputCC3200I2S.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ class AudioOutputCC3200I2S : public AudioOutput

int GetRate();

bool resample;
uint32_t resampleMaxRate;

protected:
virtual int AdjustI2SRate(int hz) { return hz; }
uint8_t portNo;
Expand All @@ -59,6 +62,8 @@ class AudioOutputCC3200I2S : public AudioOutput
BoxAudioBufferTriple* audioBuffer;

bool writeEmptyBuffer();

uint8_t resampleRate = 1;
};

#endif
Expand Down
130 changes: 130 additions & 0 deletions AudioOutputResample.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
AudioOutputResample
Adds additional bufferspace to the output chain
Copyright (C) 2017 Earle F. Philhower, III
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "BaseHeader.h"
#include <Arduino.h>
#include "AudioOutputResample.h"

AudioOutputResample::AudioOutputResample(uint32_t maxRate, AudioOutputCC3200I2S *dest)
{
this->sink = dest;
this->leftSample = 0;
this->rightSample = 0;

this->resampleFactor = 1;
this->resampleCount = 0;

originalSampleRate = this->sink->GetRate();

SetMaxRate(maxRate);
}

AudioOutputResample::~AudioOutputResample() { }

bool AudioOutputResample::SetRate(int hz) {
this->originalSampleRate = hz;
if (this->maxSampleRate >= hz) {
this->resampleFactor = 1;
Log.info("AudioOutputResample SetRate=%i", hz);
return this->sink->SetRate(hz);
}

for (this->resampleFactor = 2; this->resampleFactor < 7; this->resampleFactor++) { // 48000/8000
if (this->maxSampleRate >= (hz / this->resampleFactor))
break;
}
Log.info("AudioOutputResample limited SetRate=%i, hz=%i, resampleFactor=%i", hz / this->resampleFactor, hz, this->resampleFactor);
return sink->SetRate(hz / this->resampleFactor);
}
void AudioOutputResample::SetMaxRate(uint32_t hz) {
switch (hz)
{
case 48000:
case 44100:
case 32000:
case 24000:
case 22050:
case 16000:
case 11025:
case 8000:
this->maxSampleRate = hz;
break;
default:
this->maxSampleRate = 48000;
}
SetRate(this->originalSampleRate);
}
uint32_t AudioOutputResample::GetMaxRate() {
return this->maxSampleRate;
}
int AudioOutputResample::GetRate() {
return this->sink->GetRate();
}

bool AudioOutputResample::SetBitsPerSample(int bits)
{
return this->sink->SetBitsPerSample(bits);
}

bool AudioOutputResample::SetChannels(int channels)
{
return this->sink->SetChannels(channels);
}

bool AudioOutputResample::begin()
{
return this->sink->begin();
}

bool AudioOutputResample::ConsumeSample(int16_t sample[2])
{
if (1==0) { //Slow
this->leftSample += sample[0];
this->rightSample += sample[1];
this->resampleCount++;
if (this->resampleCount >= this->resampleFactor) {
int16_t s[2] = {(int16_t)(leftSample/this->resampleFactor), (int16_t)(rightSample/this->resampleFactor)};
if (!sink->ConsumeSample(s)) {
return false;
} else {
this->leftSample = 0;
this->rightSample = 0;
this->resampleCount = 0;
}
}
} else { //Fast
this->resampleCount++;
if (this->resampleCount >= this->resampleFactor) {
if (!sink->ConsumeSample(sample)) {
return false;
} else {
this->resampleCount = 0;
}
}
}
return true;
}

bool AudioOutputResample::stop()
{
return this->sink->stop();
}


55 changes: 55 additions & 0 deletions AudioOutputResample.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
AudioOutputResample
Adds additional bufferspace to the output chain
Copyright (C) 2017 Earle F. Philhower, III
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _AUDIOOUTPUTRESAMPLE_H
#define _AUDIOOUTPUTRESAMPLE_H

#include <AudioOutput.h>
#include "AudioOutputCC3200I2S.h"

class AudioOutputResample : public AudioOutput
{
public:
AudioOutputResample(uint32_t maxSampleRate, AudioOutputCC3200I2S *dest);
virtual ~AudioOutputResample() override;
virtual bool SetRate(int hz) override;
virtual bool SetBitsPerSample(int bits) override;
virtual bool SetChannels(int channels) override;
virtual bool begin() override;
virtual bool ConsumeSample(int16_t sample[2]) override;
virtual bool stop() override;

int GetRate();
uint32_t GetMaxRate();
void SetMaxRate(uint32_t hz);

protected:
AudioOutputCC3200I2S *sink;
int32_t leftSample;
int32_t rightSample;
uint32_t maxSampleRate;
uint8_t resampleFactor;
uint8_t resampleCount;

uint32_t originalSampleRate;
};

#endif

30 changes: 30 additions & 0 deletions BoxCLI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ void BoxCLI::begin() {
cmdAudio.addFlagArg("p/lay,pause");
cmdAudio.addArg("f/ile/name", "");
cmdAudio.addArg("g/en-limit", "0");
cmdAudio.addArg("b/uffer", "-1");
cmdAudio.addArg("m/axSampleRate", "0");
}

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

uint32_t resampleRate = (uint16_t)parseNumber(c.getArg("maxSampleRate").getValue());
String bufferStr = c.getArg("buffer").getValue();

int32_t buffer = -1;
if (bufferStr != "-1")
buffer = parseNumber(bufferStr);
if (bufferStr != "0" && buffer == 0)
buffer = -1;

if (c.getArg("file").isSet() && filenameStr != "") {
Box.boxDAC.playFile(filenameStr.c_str());
} else if (c.getArg("play").isSet()) {
Expand All @@ -395,6 +406,25 @@ void BoxCLI::execAudio() {
if (genLimit > 0)
Box.boxDAC.audioTimeoutMs = genLimit;
Log.info("Generator time limit is set to %ims", Box.boxDAC.audioTimeoutMs);

if (resampleRate > 0) {
Box.boxDAC.audioOutputResample->SetMaxRate(resampleRate);
Log.info("Max Samplerate is set to %ihz", Box.boxDAC.audioOutputResample->GetMaxRate());
}
if (buffer == 0) {
Log.info("Additional buffering disabled.");
Box.boxDAC.audioOutput = Box.boxDAC.audioOutputResample;
} else if (buffer > 0) {
if (buffer <= freeHeapMemory() / 2) {
Box.boxDAC.audioOutput = Box.boxDAC.audioOutputBuffer;
free(Box.boxDAC.audioOutputBuffer);
Box.boxDAC.audioOutputBuffer = new AudioOutputBuffer(buffer, Box.boxDAC.audioOutputResample);
Box.boxDAC.audioOutput = Box.boxDAC.audioOutputBuffer;
Log.info("Additional buffer set to %ib", buffer);
} else {
Log.error("Buffer should not use more than half of the HEAP (%ib)", freeHeapMemory());
}
}
}
}

Expand Down
12 changes: 8 additions & 4 deletions BoxDAC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ void BoxDAC::begin() {
MAP_PRCMPeripheralClkEnable(PRCM_I2S, PRCM_RUN_MODE_CLK);
MAP_PRCMPeripheralReset(PRCM_I2S);

audioOutput = new AudioOutputCC3200I2S(&audioBuffer);
Log.info("Output");
audioOutputI2S = new AudioOutputCC3200I2S(&audioBuffer);
//audioOutputResample = new AudioOutputResample(48000, audioOutputI2S);
//audioOutputBuffer = new AudioOutputBuffer(4096, audioOutputResample);
audioOutput = audioOutputI2S;

initDACI2C();

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

void BoxDAC::generateFrequency(uint32_t frequency, uint16_t timeoutMs) {
BoxTimer timeout;
uint32_t halfWavelength = (audioOutput->GetRate() / frequency) / 2;
uint32_t halfWavelength = (audioOutputI2S->GetRate() / frequency) / 2;
timeout.setTimer(timeoutMs);

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

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) {
#ifdef FEATURE_FLAG_TEXT2SPEECH
int samplerate = audioOutput->GetRate();
int samplerate = audioOutputI2S->GetRate();
audioOutput->flush();
ESP8266SAM* sam = new ESP8266SAM();

Expand Down
7 changes: 6 additions & 1 deletion BoxDAC.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#include "BoxAudioBufferTriple.h"
#include "AudioOutputCC3200I2S.h"
#include "AudioOutputResample.h"
#include <AudioOutputBuffer.h>
#include <ESP8266SAM.h>
#include "AudioFileSourceFatFs.h"
#include "AudioGeneratorTonie.h"
Expand Down Expand Up @@ -62,7 +64,10 @@ class BoxDAC : public EnhancedThread {

BoxAudioBufferTriple::BufferStruct* writeBuffer;

AudioOutputCC3200I2S* audioOutput;
AudioOutputCC3200I2S* audioOutputI2S;
AudioOutputBuffer* audioOutputBuffer;
AudioOutputResample* audioOutputResample;
AudioOutput* audioOutput;
AudioFileSource* audioSource;
AudioGenerator* audioGenerator;
bool audioPlaying = false;
Expand Down

0 comments on commit 3dc6dcf

Please sign in to comment.