Skip to content

Commit b38d611

Browse files
Add fizzgig tab to M4_Eyes (remove servo tab), WIP not finished
1 parent e023c8b commit b38d611

3 files changed

Lines changed: 195 additions & 22 deletions

File tree

M4_Eyes/M4_Eyes.ino

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,17 +137,19 @@ uint32_t availableRAM(void) {
137137

138138
void setup() {
139139
if(!arcada.arcadaBegin()) fatal("Arcada init fail!", 100);
140-
140+
#if defined(USE_TINYUSB)
141141
if(!arcada.filesysBeginMSD()) fatal("No filesystem found!", 250);
142-
142+
#else
143+
if(!arcada.filesysBegin()) fatal("No filesystem found!", 250);
144+
#endif
143145
arcada.displayBegin();
144146

145-
DISPLAY_SIZE = min(ARCADA_TFT_WIDTH, ARCADA_TFT_HEIGHT);
146-
DISPLAY_X_OFFSET = (ARCADA_TFT_WIDTH - DISPLAY_SIZE) / 2;
147+
DISPLAY_SIZE = min(ARCADA_TFT_WIDTH, ARCADA_TFT_HEIGHT);
148+
DISPLAY_X_OFFSET = (ARCADA_TFT_WIDTH - DISPLAY_SIZE) / 2;
147149
DISPLAY_Y_OFFSET = (ARCADA_TFT_HEIGHT - DISPLAY_SIZE) / 2;
148150

149151
Serial.begin(115200);
150-
// while(!Serial) delay(10);
152+
//while(!Serial) yield();
151153

152154
Serial.printf("Available RAM at start: %d\n", availableRAM());
153155
Serial.printf("Available flash at start: %d\n", arcada.availableFlash());

M4_Eyes/user_fizzgig.cpp

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
#if 0 // Change to 1 to enable this code (must enable ONE user*.cpp only!)
2+
3+
// WIP DO NOT USE
4+
5+
#include "globals.h"
6+
#include <Servo.h>
7+
8+
// Servo stuff
9+
Servo myservo;
10+
#define SERVO_MOUTH_OPEN 0
11+
#define SERVO_MOUTH_CLOSED 180
12+
// TO DO: move servo when sound is playing.
13+
// At end of WAV, move mouth to closed position.
14+
15+
// WAV player stuff
16+
#define WAV_BUFFER_SIZE 256
17+
static uint8_t wavBuf[2][WAV_BUFFER_SIZE];
18+
static File wavFile;
19+
static bool playing = false;
20+
static int remainingBytesInChunk;
21+
static uint8_t activeBuf;
22+
static uint16_t bufIdx, bufEnd, nextBufEnd;
23+
static bool startWav(char *filename);
24+
static void wavOutCallback(void);
25+
static const char *wav_path = "fizzgig";
26+
static struct wavlist { // Linked list of WAV filenames
27+
char *filename;
28+
struct wavlist *next;
29+
} *wavListStart = NULL, *wavListPtr = NULL;
30+
#define MAX_WAV_FILES 20
31+
32+
void user_setup(void) {
33+
File entry;
34+
struct wavlist *wptr;
35+
char filename[SD_MAX_FILENAME_SIZE+1];
36+
// Scan wav_path for .wav files:
37+
for(int i=0; i<MAX_WAV_FILES; i++) {
38+
entry = arcada.openFileByIndex(wav_path, i, O_READ, "wav");
39+
if(!entry) break;
40+
// Found one, alloc new wavlist struct, try duplicating filename
41+
if((wptr = (struct wavlist *)malloc(sizeof(struct wavlist)))) {
42+
entry.getName(filename, SD_MAX_FILENAME_SIZE);
43+
if((wptr->filename = strdup(filename))) {
44+
// Alloc'd OK, add to linked list...
45+
if(wavListPtr) { // List already started?
46+
wavListPtr->next = wptr; // Point prior last item to new one
47+
} else {
48+
wavListStart = wptr; // Point list head to new item
49+
}
50+
wavListPtr = wptr; // Update last item to new one
51+
} else {
52+
free(wptr); // Alloc failed, delete interim stuff
53+
}
54+
}
55+
entry.close();
56+
}
57+
if(wavListPtr) { // Any items in WAV list?
58+
wavListPtr->next = wavListStart; // Point last item's next to list head (list is looped)
59+
wavListPtr = wavListStart; // Update list pointer to head
60+
}
61+
myservo.attach(3);
62+
}
63+
64+
void user_loop(void) {
65+
if(!playing && wavListPtr) {
66+
pinMode(2, INPUT_PULLUP);
67+
delayMicroseconds(20); // Avoid boop code interference
68+
if(!digitalRead(2)) {
69+
arcada.chdir(wav_path);
70+
startWav(wavListPtr->filename);
71+
wavListPtr = wavListPtr->next; // Will loop around from end to start of list
72+
}
73+
}
74+
75+
// 'pos' will be determined periodically, maybe not every frame. TBD.
76+
// needs to go to a closed position when WAV is finished.
77+
// myservo.write(pos);
78+
}
79+
80+
static uint16_t readWaveData(uint8_t *dst) {
81+
if(remainingBytesInChunk <= 0) {
82+
// Read next chunk
83+
struct {
84+
char id[4];
85+
uint32_t size;
86+
} header;
87+
for(;;) {
88+
if(wavFile.read(&header, 8) != 8) return 0;
89+
if(!strncmp(header.id, "data", 4)) {
90+
remainingBytesInChunk = header.size;
91+
break;
92+
}
93+
if(!wavFile.seekCur(header.size)) { // If not "data" then skip
94+
return 0; // Seek failed, return invalid count
95+
}
96+
}
97+
}
98+
99+
int16_t bytesRead = wavFile.read(dst, min(WAV_BUFFER_SIZE, remainingBytesInChunk));
100+
if(bytesRead > 0) remainingBytesInChunk -= bytesRead;
101+
return bytesRead;
102+
}
103+
104+
// Partially swiped from Wave Shield code.
105+
// Is pared-down, handles 8-bit mono only to keep it simple.
106+
static bool startWav(char *filename) {
107+
wavFile = arcada.open(filename);
108+
if(!wavFile) {
109+
Serial.println("Failed to open WAV file");
110+
return false;
111+
}
112+
113+
union {
114+
struct {
115+
char id[4];
116+
uint32_t size;
117+
char data[4];
118+
} riff; // riff chunk
119+
struct {
120+
uint16_t compress;
121+
uint16_t channels;
122+
uint32_t sampleRate;
123+
uint32_t bytesPerSecond;
124+
uint16_t blockAlign;
125+
uint16_t bitsPerSample;
126+
uint16_t extraBytes;
127+
} fmt; // fmt data
128+
} buf;
129+
130+
uint16_t size;
131+
if((wavFile.read(&buf, 12) == 12)
132+
&& !strncmp(buf.riff.id, "RIFF", 4)
133+
&& !strncmp(buf.riff.data, "WAVE", 4)) {
134+
// next chunk must be fmt, fmt chunk size must be 16 or 18
135+
if((wavFile.read(&buf, 8) == 8)
136+
&& !strncmp(buf.riff.id, "fmt ", 4)
137+
&& (((size = buf.riff.size) == 16) || (size == 18))
138+
&& (wavFile.read(&buf, size) == size)
139+
&& ((size != 18) || (buf.fmt.extraBytes == 0))) {
140+
if((buf.fmt.channels == 1) && (buf.fmt.bitsPerSample == 8)) {
141+
Serial.printf("Samples/sec: %d\n", buf.fmt.sampleRate);
142+
bufEnd = readWaveData(wavBuf[0]);
143+
if(bufEnd > 0) {
144+
// Initialize A/D, speaker and start timer
145+
analogWriteResolution(8);
146+
analogWrite(A0, 128);
147+
analogWrite(A1, 128);
148+
arcada.enableSpeaker(true);
149+
bufIdx = 0;
150+
playing = true;
151+
arcada.timerCallback(buf.fmt.sampleRate, wavOutCallback);
152+
nextBufEnd = readWaveData(wavBuf[1]);
153+
}
154+
return true;
155+
} else {
156+
Serial.println("Only 8-bit mono WAVs are supported");
157+
}
158+
} else {
159+
Serial.println("WAV uses compression or other unrecognized setting");
160+
}
161+
} else {
162+
Serial.println("Not WAV file");
163+
}
164+
165+
wavFile.close();
166+
return false;
167+
}
168+
169+
static void wavOutCallback(void) {
170+
uint8_t n = wavBuf[activeBuf][bufIdx];
171+
analogWrite(A0, n);
172+
analogWrite(A1, n);
173+
174+
if(++bufIdx >= bufEnd) {
175+
if(nextBufEnd <= 0) {
176+
arcada.timerStop();
177+
arcada.enableSpeaker(false);
178+
playing = false;
179+
return;
180+
}
181+
bufIdx = 0;
182+
bufEnd = nextBufEnd;
183+
nextBufEnd = readWaveData(wavBuf[activeBuf]);
184+
activeBuf = 1 - activeBuf;
185+
}
186+
}
187+
188+
#endif // 0

M4_Eyes/user_servo.cpp

Lines changed: 0 additions & 17 deletions
This file was deleted.

0 commit comments

Comments
 (0)