mirror of
https://github.com/JorjBauer/aiie.git
synced 2025-01-13 22:32:00 +00:00
removed threads; bones for audio in place
This commit is contained in:
parent
fb7a64a22f
commit
1dcbee91ba
5
bios.cpp
5
bios.cpp
@ -8,7 +8,6 @@
|
|||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
|
||||||
#ifdef TEENSYDUINO
|
#ifdef TEENSYDUINO
|
||||||
#include <TeensyThreads.h>
|
|
||||||
#include <Bounce2.h>
|
#include <Bounce2.h>
|
||||||
#include "teensy-paddles.h"
|
#include "teensy-paddles.h"
|
||||||
extern Bounce resetButtonDebouncer;
|
extern Bounce resetButtonDebouncer;
|
||||||
@ -303,7 +302,7 @@ uint8_t BIOS::GetAction(int8_t selection)
|
|||||||
#endif
|
#endif
|
||||||
) {
|
) {
|
||||||
#ifdef TEENSYDUINO
|
#ifdef TEENSYDUINO
|
||||||
threads.delay(10);
|
delay(10);
|
||||||
#else
|
#else
|
||||||
usleep(100);
|
usleep(100);
|
||||||
#endif
|
#endif
|
||||||
@ -315,7 +314,7 @@ uint8_t BIOS::GetAction(int8_t selection)
|
|||||||
// wait until it's no longer pressed
|
// wait until it's no longer pressed
|
||||||
while (resetButtonDebouncer.read() == HIGH)
|
while (resetButtonDebouncer.read() == HIGH)
|
||||||
;
|
;
|
||||||
threads.delay(100); // wait long enough for it to debounce
|
delay(100); // wait long enough for it to debounce
|
||||||
// then return an exit code
|
// then return an exit code
|
||||||
return ACT_EXIT;
|
return ACT_EXIT;
|
||||||
}
|
}
|
||||||
|
@ -55,9 +55,4 @@ extern bool g_invertPaddleY;
|
|||||||
|
|
||||||
extern char debugBuf[255];
|
extern char debugBuf[255];
|
||||||
|
|
||||||
#ifdef TEENSYDUINO
|
|
||||||
#include <TeensyThreads.h>
|
|
||||||
extern Threads::Mutex spi_lock;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <TeensyThreads.h>
|
|
||||||
|
|
||||||
#define open(path, flags, perms) g_filemanager->openFile(path)
|
#define open(path, flags, perms) g_filemanager->openFile(path)
|
||||||
#define close(filedes) g_filemanager->closeFile(filedes)
|
#define close(filedes) g_filemanager->closeFile(filedes)
|
||||||
@ -17,9 +16,8 @@
|
|||||||
#define read(filedes,buf,nbyte) g_filemanager->read(filedes,buf,nbyte)
|
#define read(filedes,buf,nbyte) g_filemanager->read(filedes,buf,nbyte)
|
||||||
#define lseek(filedes,offset,whence) g_filemanager->lseek(filedes,offset,whence)
|
#define lseek(filedes,offset,whence) g_filemanager->lseek(filedes,offset,whence)
|
||||||
|
|
||||||
Threads::Mutex serlock;
|
|
||||||
static char fsbuf[200];
|
static char fsbuf[200];
|
||||||
#define printf(x, ...) {sprintf(fsbuf, x, ##__VA_ARGS__); serlock.lock(); Serial.println(fsbuf); Serial.flush(); Serial.send_now(); serlock.unlock();}
|
#define printf(x, ...) {sprintf(fsbuf, x, ##__VA_ARGS__); Serial.println(fsbuf); Serial.flush(); Serial.send_now();}
|
||||||
#define fprintf(f, x, ...) {sprintf(fsbuf, x, ##__VA_ARGS__); serlock.lock(); Serial.println(fsbuf); Serial.flush(); Serial.send_now(); serlock.lock();}
|
#define fprintf(f, x, ...) {sprintf(fsbuf, x, ##__VA_ARGS__); Serial.println(fsbuf); Serial.flush(); Serial.send_now();}
|
||||||
#define perror(x) {serlock.lock();Serial.println(x);Serial.flush(); Serial.send_now(); serlock.unlock();}
|
#define perror(x) {Serial.println(x);Serial.flush(); Serial.send_now();}
|
||||||
|
|
||||||
|
@ -2,11 +2,8 @@
|
|||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include "teensy-filemanager.h"
|
#include "teensy-filemanager.h"
|
||||||
#include <string.h> // strcpy
|
#include <string.h> // strcpy
|
||||||
#include <TeensyThreads.h>
|
|
||||||
#include "teensy-println.h"
|
#include "teensy-println.h"
|
||||||
|
|
||||||
Threads::Mutex fslock;
|
|
||||||
|
|
||||||
TeensyFileManager::TeensyFileManager()
|
TeensyFileManager::TeensyFileManager()
|
||||||
{
|
{
|
||||||
numCached = 0;
|
numCached = 0;
|
||||||
@ -23,8 +20,6 @@ TeensyFileManager::~TeensyFileManager()
|
|||||||
|
|
||||||
int8_t TeensyFileManager::openFile(const char *name)
|
int8_t TeensyFileManager::openFile(const char *name)
|
||||||
{
|
{
|
||||||
Threads::Scope locker(fslock);
|
|
||||||
|
|
||||||
if (cacheFd != -1) {
|
if (cacheFd != -1) {
|
||||||
cacheFile.close();
|
cacheFile.close();
|
||||||
cacheFd = -1;
|
cacheFd = -1;
|
||||||
@ -56,7 +51,6 @@ int8_t TeensyFileManager::openFile(const char *name)
|
|||||||
|
|
||||||
void TeensyFileManager::closeFile(int8_t fd)
|
void TeensyFileManager::closeFile(int8_t fd)
|
||||||
{
|
{
|
||||||
Threads::Scope locker(fslock);
|
|
||||||
if (cacheFd != -1) {
|
if (cacheFd != -1) {
|
||||||
cacheFile.close();
|
cacheFile.close();
|
||||||
cacheFd = -1;
|
cacheFd = -1;
|
||||||
@ -92,8 +86,6 @@ void TeensyFileManager::closeDir()
|
|||||||
// suffix may be comma-separated
|
// suffix may be comma-separated
|
||||||
int16_t TeensyFileManager::readDir(const char *where, const char *suffix, char *outputFN, int16_t startIdx, uint16_t maxlen)
|
int16_t TeensyFileManager::readDir(const char *where, const char *suffix, char *outputFN, int16_t startIdx, uint16_t maxlen)
|
||||||
{
|
{
|
||||||
Threads::Scope locker(fslock);
|
|
||||||
|
|
||||||
// First entry is always "../" if we're in a subdir of the root
|
// First entry is always "../" if we're in a subdir of the root
|
||||||
if (startIdx == 0 || !outerDir) {
|
if (startIdx == 0 || !outerDir) {
|
||||||
if (outerDir)
|
if (outerDir)
|
||||||
@ -220,7 +212,6 @@ void TeensyFileManager::seekToEnd(int8_t fd)
|
|||||||
|
|
||||||
int TeensyFileManager::write(int8_t fd, const void *buf, int nbyte)
|
int TeensyFileManager::write(int8_t fd, const void *buf, int nbyte)
|
||||||
{
|
{
|
||||||
Threads::Scope locker(fslock);
|
|
||||||
// open, seek, write, close.
|
// open, seek, write, close.
|
||||||
if (fd < 0 || fd >= numCached) {
|
if (fd < 0 || fd >= numCached) {
|
||||||
return -1;
|
return -1;
|
||||||
@ -249,7 +240,6 @@ int TeensyFileManager::write(int8_t fd, const void *buf, int nbyte)
|
|||||||
|
|
||||||
int TeensyFileManager::read(int8_t fd, void *buf, int nbyte)
|
int TeensyFileManager::read(int8_t fd, void *buf, int nbyte)
|
||||||
{
|
{
|
||||||
Threads::Scope locker(fslock);
|
|
||||||
// open, seek, read, close.
|
// open, seek, read, close.
|
||||||
if (fd < 0 || fd >= numCached) {
|
if (fd < 0 || fd >= numCached) {
|
||||||
return -1;
|
return -1;
|
||||||
@ -276,7 +266,6 @@ int TeensyFileManager::read(int8_t fd, void *buf, int nbyte)
|
|||||||
|
|
||||||
int TeensyFileManager::lseek(int8_t fd, int offset, int whence)
|
int TeensyFileManager::lseek(int8_t fd, int offset, int whence)
|
||||||
{
|
{
|
||||||
Threads::Scope locker(fslock);
|
|
||||||
if (whence == SEEK_CUR && offset == 0) {
|
if (whence == SEEK_CUR && offset == 0) {
|
||||||
return fileSeekPositions[fd];
|
return fileSeekPositions[fd];
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
namespace arduino_preprocessor_is_buggy {
|
namespace arduino_preprocessor_is_buggy {
|
||||||
|
|
||||||
bool serialavailable() {
|
bool serialavailable() {
|
||||||
Threads::Scope locker(getSerialLock());
|
// Threads::Scope locker(getSerialLock());
|
||||||
return Serial.available();
|
return Serial.available();
|
||||||
}
|
}
|
||||||
|
|
||||||
char serialgetch() {
|
char serialgetch() {
|
||||||
Threads::Scope locker(getSerialLock());
|
// Threads::Scope locker(getSerialLock());
|
||||||
return Serial.read();
|
return Serial.read();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <TeensyThreads.h>
|
|
||||||
|
|
||||||
// cf. https://forum.pjrc.com/threads/41504-Teensy-3-x-multithreading-library-first-release/page6
|
// cf. https://forum.pjrc.com/threads/41504-Teensy-3-x-multithreading-library-first-release/page6
|
||||||
|
|
||||||
@ -12,10 +11,12 @@ namespace arduino_preprocessor_is_buggy {
|
|||||||
// used for suppressing compiler warnings
|
// used for suppressing compiler warnings
|
||||||
template<class T> void silence(T&&) {};
|
template<class T> void silence(T&&) {};
|
||||||
|
|
||||||
|
/*
|
||||||
inline Threads::Mutex& getSerialLock() {
|
inline Threads::Mutex& getSerialLock() {
|
||||||
static Threads::Mutex serial_lock;
|
static Threads::Mutex serial_lock;
|
||||||
return serial_lock;
|
return serial_lock;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
bool serialavailable();
|
bool serialavailable();
|
||||||
char serialgetch();
|
char serialgetch();
|
||||||
@ -29,12 +30,12 @@ namespace arduino_preprocessor_is_buggy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class... args_t> void print(args_t... params) {
|
template<class... args_t> void print(args_t... params) {
|
||||||
Threads::Scope locker(getSerialLock());
|
// Threads::Scope locker(getSerialLock());
|
||||||
silence(expand{ (print_fwd(params), 42)... });
|
silence(expand{ (print_fwd(params), 42)... });
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class... args_t> void println(args_t... params) {
|
template<class... args_t> void println(args_t... params) {
|
||||||
Threads::Scope locker(getSerialLock());
|
// Threads::Scope locker(getSerialLock());
|
||||||
silence(expand{ (print_fwd(params), 42)... });
|
silence(expand{ (print_fwd(params), 42)... });
|
||||||
Serial.println();
|
Serial.println();
|
||||||
Serial.flush();
|
Serial.flush();
|
||||||
|
@ -1,28 +1,49 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <TeensyThreads.h>
|
|
||||||
#include "teensy-speaker.h"
|
#include "teensy-speaker.h"
|
||||||
#include "teensy-println.h"
|
#include "teensy-println.h"
|
||||||
#include <i2c_device.h>
|
#include <Audio.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
|
||||||
|
TeensyAudio audioDriver;
|
||||||
|
//AudioMixer4 mixer2; //xy=280,253
|
||||||
|
AudioMixer4 mixer1; //xy=280,175
|
||||||
|
AudioOutputI2S i2s; //xy=452,189
|
||||||
|
|
||||||
|
AudioConnection patchCord1(audioDriver, 0, mixer1, 0);
|
||||||
|
//AudioConnection patchCord2(audioDriver, 0, mixer2, 0);
|
||||||
|
//AudioConnection patchCord3(mixer2, 0, i2s, 1);
|
||||||
|
AudioConnection patchCord4(mixer1, 0, i2s, 0);
|
||||||
|
//const float t_ampx = 0.8;
|
||||||
|
//const int t_lox = 10;
|
||||||
|
//const int t_hix = 22000;
|
||||||
|
//const float t_timex = 10; // Length of time for the sweep in seconds
|
||||||
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
|
||||||
I2CDevice dac = I2CDevice(Master, 0x60, _BIG_ENDIAN);
|
//#define BUFSIZE 4096
|
||||||
|
//EXTMEM uint32_t toggleBuffer[BUFSIZE]; // cycle counts at which state toggles
|
||||||
|
//uint16_t headptr, tailptr;
|
||||||
|
|
||||||
Threads::Mutex togmutex;
|
// Ring buffer that we fill with 44.1kHz data
|
||||||
#define BUFSIZE 4096
|
#define RINGBUFSIZE 4096
|
||||||
EXTMEM uint32_t toggleBuffer[BUFSIZE]; // cycle counts at which state toggles
|
EXTMEM short sampleRingBuffer[RINGBUFSIZE];
|
||||||
uint16_t headptr, tailptr;
|
volatile uint16_t sampleHeadPtr = 0;
|
||||||
uint32_t lastCycleCount, toggleAtCycle;
|
volatile uint16_t sampleTailPtr = 0;
|
||||||
|
volatile uint32_t lastFilledTime = 0;
|
||||||
|
|
||||||
|
volatile uint32_t lastSampleNum = 0;
|
||||||
|
|
||||||
|
bool toggleState = false;
|
||||||
|
|
||||||
// How many cycles do we run the audio behind? Needs to be more than our bulk
|
// How many cycles do we run the audio behind? Needs to be more than our bulk
|
||||||
// cycle count.
|
// cycle count.
|
||||||
#define CYCLEDELAY 100
|
//#define CYCLEDELAY 100
|
||||||
|
|
||||||
TeensySpeaker::TeensySpeaker(uint8_t sda, uint8_t scl) : PhysicalSpeaker()
|
TeensySpeaker::TeensySpeaker(uint8_t sda, uint8_t scl) : PhysicalSpeaker()
|
||||||
{
|
{
|
||||||
toggleState = false;
|
toggleState = false;
|
||||||
mixerValue = numMixed = 0;
|
mixerValue = numMixed = 0;
|
||||||
Master.begin(1000000); // 100000 or 400000 or 1000000
|
AudioMemory(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
TeensySpeaker::~TeensySpeaker()
|
TeensySpeaker::~TeensySpeaker()
|
||||||
@ -31,18 +52,40 @@ TeensySpeaker::~TeensySpeaker()
|
|||||||
|
|
||||||
void TeensySpeaker::begin()
|
void TeensySpeaker::begin()
|
||||||
{
|
{
|
||||||
lastCycleCount = g_cpu->cycles;
|
mixer1.gain(0, 0.5f); // left channel
|
||||||
|
|
||||||
|
lastFilledTime = g_cpu->cycles;
|
||||||
|
sampleHeadPtr = sampleTailPtr = 0;
|
||||||
toggleState = false;
|
toggleState = false;
|
||||||
memset(toggleBuffer, 0, sizeof(toggleBuffer));
|
// memset(toggleBuffer, 0, sizeof(toggleBuffer));
|
||||||
headptr = tailptr = 0;
|
// headptr = tailptr = 0;
|
||||||
|
lastSampleNum = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TeensySpeaker::toggle(uint32_t c)
|
void TeensySpeaker::toggle(uint32_t c)
|
||||||
{
|
{
|
||||||
Threads::Scope lock(togmutex);
|
// Figure out when the last time was that we put data in the audio buffer;
|
||||||
// Queue the speaker toggle time; maintainSpeaker will pick it up
|
// then figure out how many audio buffer cycles we have to fill from that
|
||||||
toggleBuffer[tailptr++] = c; tailptr %= BUFSIZE;
|
// CPU time to this one.
|
||||||
|
#if 1
|
||||||
|
__disable_irq();
|
||||||
|
|
||||||
|
// We expect to have filled to this cycle number...
|
||||||
|
uint32_t expectedCycleNumber = (float)c * (float)AUDIO_SAMPLE_RATE_EXACT / (float)g_speed;
|
||||||
|
|
||||||
|
// and we have filled to cycle number lastFilledTime. So how many do we need?
|
||||||
|
uint32_t audioBufferSamples = expectedCycleNumber - lastFilledTime;
|
||||||
|
|
||||||
|
if (audioBufferSamples > RINGBUFSIZE)
|
||||||
|
audioBufferSamples = RINGBUFSIZE;
|
||||||
|
for (int i=0; i<audioBufferSamples; i++) {
|
||||||
|
sampleRingBuffer[sampleTailPtr++] = toggleState ? (32767/2) : (-32767/2); // FIXME: appropriate value?
|
||||||
|
sampleTailPtr %= RINGBUFSIZE;
|
||||||
|
}
|
||||||
|
toggleState = !toggleState;
|
||||||
|
lastFilledTime = expectedCycleNumber;
|
||||||
|
__enable_irq();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void TeensySpeaker::maintainSpeaker(uint32_t c, uint64_t microseconds)
|
void TeensySpeaker::maintainSpeaker(uint32_t c, uint64_t microseconds)
|
||||||
@ -52,25 +95,13 @@ void TeensySpeaker::maintainSpeaker(uint32_t c, uint64_t microseconds)
|
|||||||
|
|
||||||
void TeensySpeaker::maintainSpeaker()
|
void TeensySpeaker::maintainSpeaker()
|
||||||
{
|
{
|
||||||
// This is called @ SAMPLERATE (8k, as of this writing) and looks for
|
// This is called @ 44100Hz, which is the sample rate for the
|
||||||
// any transitions that have passed before sending data to the DAC.
|
// Teensy4 (#define AUDIO_SAMPLE_RATE_EXACT 44100.0f). We fill a FIFO
|
||||||
// The idea is that this will be called fast enough for the given number
|
// that is then drained by update(). In theory, as long as we don't fall
|
||||||
// of cycles that we run behind, so that the buffer can't overflow.
|
// 128 cycles behind, it should be okay, I think (b/c AUDIO_BLOCK_SAMPLES
|
||||||
//
|
// is 128 on the Teensy 4).
|
||||||
// at 8kHz, that means that .000125 seconds have passed since our last
|
#if 0
|
||||||
// call; where the CPU has executed about 128 instructions in the same
|
|
||||||
// time. Therefore, it can't have toggled more than 128 times. We're
|
|
||||||
// also trying to stay 100 cycles "behind", so it's possible that we have
|
|
||||||
// 228 cycles difference between an event that just fired-and-queued,
|
|
||||||
// and where we need to catch up to in this loop.
|
|
||||||
|
|
||||||
// First, reconcile the "correct" toggleState. We pretend it's currently
|
|
||||||
// some time in the past, based on our cycle delay. In theory (as above),
|
|
||||||
// this shouldn't be more than about 228 cycles off (maybe slightly more,
|
|
||||||
// since we actually run cycles in batches).
|
|
||||||
uint32_t curTime = g_cpu->cycles - CYCLEDELAY;
|
uint32_t curTime = g_cpu->cycles - CYCLEDELAY;
|
||||||
// And then find any events that should have happened, accounting for them:
|
|
||||||
togmutex.lock();
|
|
||||||
while (headptr != tailptr) {
|
while (headptr != tailptr) {
|
||||||
if (curTime >= toggleBuffer[headptr]) {
|
if (curTime >= toggleBuffer[headptr]) {
|
||||||
toggleState = !toggleState;
|
toggleState = !toggleState;
|
||||||
@ -80,11 +111,7 @@ void TeensySpeaker::maintainSpeaker()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
togmutex.unlock();
|
#endif
|
||||||
|
|
||||||
// Now we can safely update the DAC based on the current toggleState
|
|
||||||
uint16_t v = (toggleState ? 0xFFF : 0x000);
|
|
||||||
// dac.write((uint8_t) ((v >> 8) & 0xFF), (uint8_t) (v & 0xFF), true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TeensySpeaker::beginMixing()
|
void TeensySpeaker::beginMixing()
|
||||||
@ -97,3 +124,54 @@ void TeensySpeaker::mixOutput(uint8_t v)
|
|||||||
// unused
|
// unused
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TeensyAudio::update(void)
|
||||||
|
{
|
||||||
|
audio_block_t *block;
|
||||||
|
short *bp;
|
||||||
|
|
||||||
|
// Grab a block and we'll fill it up. It needs AUDIO_BLOCK_SAMPLES short values
|
||||||
|
// (which is 128 on the Teensy 4).
|
||||||
|
block = allocate();
|
||||||
|
if (block) {
|
||||||
|
bp = block->data;
|
||||||
|
#if 1
|
||||||
|
uint32_t underflow = 0;
|
||||||
|
for (int i=0; i<AUDIO_BLOCK_SAMPLES; i++) {
|
||||||
|
static short lastValue = 0;
|
||||||
|
|
||||||
|
if (sampleHeadPtr == sampleTailPtr) {
|
||||||
|
// bp[i] = lastValue; // underflow: just repeat whatever old data we have
|
||||||
|
// FIXME: trend toward zero, maybe?
|
||||||
|
bp[i] = lastValue;
|
||||||
|
underflow++;
|
||||||
|
} else {
|
||||||
|
lastValue = sampleRingBuffer[sampleHeadPtr++];
|
||||||
|
bp[i] = lastValue;
|
||||||
|
sampleHeadPtr %= RINGBUFSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// Fill in the AUDIO_BLOCK_SAMPLES samples of data, pull them from the FIFO
|
||||||
|
memset(bp, 0, AUDIO_BLOCK_SAMPLES * sizeof(short));
|
||||||
|
#endif
|
||||||
|
if (underflow) {
|
||||||
|
println("U ", underflow);
|
||||||
|
}
|
||||||
|
transmit(block, 0);
|
||||||
|
release(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (sampleHeadPtr == sampleTailPtr) {
|
||||||
|
// The FIFO is empty, so reset...
|
||||||
|
if (g_cpu) {
|
||||||
|
lastFilledTime = g_cpu->cycles;
|
||||||
|
} else {
|
||||||
|
lastFilledTime = 0;
|
||||||
|
}
|
||||||
|
// FIXME:
|
||||||
|
// lastSampleNum = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@ -1,11 +1,19 @@
|
|||||||
#ifndef __TEENSY_SPEAKER_H
|
#ifndef __TEENSY_SPEAKER_H
|
||||||
#define __TEENSY_SPEAKER_H
|
#define __TEENSY_SPEAKER_H
|
||||||
|
|
||||||
|
#include <AudioStream.h>
|
||||||
#include "physicalspeaker.h"
|
#include "physicalspeaker.h"
|
||||||
#include <MCP492X.h>
|
#include <MCP492X.h>
|
||||||
|
|
||||||
#define SAMPLERATE 44100
|
#define SAMPLERATE 44100
|
||||||
|
|
||||||
|
class TeensyAudio : public AudioStream {
|
||||||
|
public:
|
||||||
|
TeensyAudio(void) : AudioStream(0, NULL) {}
|
||||||
|
|
||||||
|
virtual void update(void);
|
||||||
|
};
|
||||||
|
|
||||||
class TeensySpeaker : public PhysicalSpeaker {
|
class TeensySpeaker : public PhysicalSpeaker {
|
||||||
public:
|
public:
|
||||||
TeensySpeaker(uint8_t sda, uint8_t scl);
|
TeensySpeaker(uint8_t sda, uint8_t scl);
|
||||||
@ -21,7 +29,7 @@ class TeensySpeaker : public PhysicalSpeaker {
|
|||||||
virtual void mixOutput(uint8_t v);
|
virtual void mixOutput(uint8_t v);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool toggleState;
|
// bool toggleState;
|
||||||
|
|
||||||
uint32_t mixerValue;
|
uint32_t mixerValue;
|
||||||
uint8_t numMixed;
|
uint8_t numMixed;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include <Audio.h>
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
#include <TimeLib.h>
|
#include <TimeLib.h>
|
||||||
#include <TeensyThreads.h>
|
|
||||||
#include <Bounce2.h>
|
#include <Bounce2.h>
|
||||||
#include "bios.h"
|
#include "bios.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
@ -16,7 +16,7 @@
|
|||||||
#include "teensy-prefs.h"
|
#include "teensy-prefs.h"
|
||||||
#include "teensy-println.h"
|
#include "teensy-println.h"
|
||||||
|
|
||||||
#define DEBUG_TIMING
|
//#define DEBUG_TIMING
|
||||||
|
|
||||||
#define THREADED if (1)
|
#define THREADED if (1)
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ void onKeyrelease(int unicode)
|
|||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
Serial.begin(230400);
|
Serial.begin(230400);
|
||||||
#if 0
|
#if 1
|
||||||
// Wait for USB serial connection before booting while debugging
|
// Wait for USB serial connection before booting while debugging
|
||||||
while (!Serial) {
|
while (!Serial) {
|
||||||
yield();
|
yield();
|
||||||
@ -165,9 +165,9 @@ void setup()
|
|||||||
println("free-running");
|
println("free-running");
|
||||||
Serial.flush();
|
Serial.flush();
|
||||||
|
|
||||||
threads.setMicroTimer(); // use a 100uS timer instead of a 1mS timer
|
// threads.setMicroTimer(); // use a 100uS timer instead of a 1mS timer
|
||||||
// threads.setSliceMicros(5);
|
// threads.setSliceMicros(5);
|
||||||
threads.addThread(runDebouncer);
|
// threads.addThread(runDebouncer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: move these memory-related functions elsewhere...
|
// FIXME: move these memory-related functions elsewhere...
|
||||||
@ -228,43 +228,13 @@ void biosInterrupt()
|
|||||||
g_keyboard->maintainKeyboard();
|
g_keyboard->maintainKeyboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
void runSpeaker(uint32_t now)
|
|
||||||
{
|
|
||||||
static uint32_t spk_nextResetMicros = 0;
|
|
||||||
static uint32_t spk_refreshCount = 0;
|
|
||||||
static uint32_t spk_microsAtStart = micros();
|
|
||||||
static uint32_t spk_microsForNext = 0;
|
|
||||||
|
|
||||||
THREADED {
|
|
||||||
if (now >= spk_microsForNext) {
|
|
||||||
spk_refreshCount++;
|
|
||||||
spk_microsForNext = spk_microsAtStart + ((float)1000000.0*((float)spk_refreshCount/(float)SAMPLERATE));
|
|
||||||
((TeensySpeaker *)g_speaker)->maintainSpeaker();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (now >= spk_nextResetMicros) {
|
|
||||||
#ifdef DEBUG_TIMING
|
|
||||||
float pct = (100.0 * (float)spk_refreshCount) / (float)SAMPLERATE;
|
|
||||||
sprintf(debugBuf, "Speaker running at %f%% [%lu]", pct, spk_refreshCount);
|
|
||||||
println(debugBuf);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
spk_microsAtStart = now;
|
|
||||||
spk_refreshCount = 0;
|
|
||||||
spk_nextResetMicros = spk_microsAtStart + 1000000;
|
|
||||||
spk_microsForNext = spk_microsAtStart + ((float)1000000.0*((float)spk_refreshCount/(float)SAMPLERATE));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void runMaintenance(uint32_t now)
|
void runMaintenance(uint32_t now)
|
||||||
{
|
{
|
||||||
static uint32_t nextRuntime = 0;
|
static uint32_t nextRuntime = 0;
|
||||||
|
|
||||||
THREADED {
|
THREADED {
|
||||||
if (now >= nextRuntime) {
|
if (now >= nextRuntime) {
|
||||||
nextRuntime = now + 100000000; // FIXME: what's a good time here
|
nextRuntime = now + 100000; // FIXME: what's a good time here? 1/10 sec?
|
||||||
|
|
||||||
if (!resetButtonDebouncer.read()) {
|
if (!resetButtonDebouncer.read()) {
|
||||||
// This is the BIOS interrupt. We immediately act on it.
|
// This is the BIOS interrupt. We immediately act on it.
|
||||||
@ -334,7 +304,8 @@ void runDebouncer()
|
|||||||
nextRuntime = millis() + 10;
|
nextRuntime = millis() + 10;
|
||||||
resetButtonDebouncer.update();
|
resetButtonDebouncer.update();
|
||||||
} else {
|
} else {
|
||||||
threads.yield();
|
yield();
|
||||||
|
// threads.yield();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -373,7 +344,6 @@ void loop()
|
|||||||
uint32_t now = micros();
|
uint32_t now = micros();
|
||||||
runCPU(now);
|
runCPU(now);
|
||||||
runDisplay(now);
|
runDisplay(now);
|
||||||
runSpeaker(now);
|
|
||||||
runMaintenance(now);
|
runMaintenance(now);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user