initial commit

This commit is contained in:
2026-09-25 10:48:51 +10:00
commit b90beea8ae
1020 changed files with 131665 additions and 0 deletions
@@ -0,0 +1,131 @@
/*
* Text-to-speech example to speak the first n digits of pi.
* The number is stored in flash, each digit is spoken one at a time.
*/
#include <WaveHC.h>
#include <WaveUtil.h>
// put pi in flash memory
const char pi[] PROGMEM = "3.1415926535897932384626433832795028841971693993751058209749";
SdReader card; // This object holds the information for the card
FatVolume vol; // This holds the information for the partition on the card
FatReader root; // This holds the information for the volumes root directory
FatReader file; // This object represent the WAV file for a pi digit or period
WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time
/*
* Define macro to put error messages in flash memory
*/
#define error(msg) error_P(PSTR(msg))
//////////////////////////////////// SETUP
void setup() {
// set up Serial library at 9600 bps
Serial.begin(9600);
PgmPrintln("Pi speaker");
if (!card.init()) {
error("Card init. failed!");
}
if (!vol.init(card)) {
error("No partition!");
}
if (!root.openRoot(vol)) {
error("Couldn't open dir");
}
PgmPrintln("Files found:");
root.ls();
}
/////////////////////////////////// LOOP
unsigned digit = 0;
void loop() {
// get next character from flash memory
char c = pgm_read_byte(&pi[digit++]);
if (c == 0) {
digit = 0;
Serial.println();
return;
}
Serial.write(c);
speaknum(c);
delay(10);
}
/////////////////////////////////// HELPERS
char filename[13];
void speaknum(char c) {
uint8_t i=0;
// copy flash string for 'period' to filename
strcpy_P(filename, PSTR("P.WAV"));
if ('0' <= c && c <= '9') {
// digit - change 'P' to digit
filename[0] = c;
i = 1;
}
else if (c != '.') {
// error if not period
return;
}
playcomplete(filename);
}
/*
* print error message and halt
*/
void error_P(const char *str) {
PgmPrint("Error: ");
SerialPrint_P(str);
sdErrorCheck();
while(1);
}
/*
* print error message and halt if SD I/O error
*/
void sdErrorCheck(void) {
if (!card.errorCode()) return;
PgmPrint("\r\nSD I/O error: ");
Serial.print(card.errorCode(), HEX);
PgmPrint(", ");
Serial.println(card.errorData(), HEX);
while(1);
}
/*
* Play a file and wait for it to complete
*/
void playcomplete(char *name) {
playfile(name);
while (wave.isplaying);
// see if an error occurred while playing
sdErrorCheck();
}
/*
* Open and start playing a WAV file
*/
void playfile(char *name) {
if (wave.isplaying) {// already playing something, so stop it!
wave.stop(); // stop it
}
if (!file.open(root, name)) {
PgmPrint("Couldn't open file ");
Serial.print(name);
return;
}
if (!wave.create(file)) {
PgmPrintln("Not a valid WAV");
return;
}
// ok time to play!
wave.play();
}
@@ -0,0 +1,131 @@
/*
* Adafruit SampleRateMod.pde example modified to use WaveHC.
*
* Play files with sample rate controlled by voltage on analog pin zero.
*/
#include <WaveHC.h>
#include <WaveUtil.h>
SdReader card; // This object holds the information for the card
FatVolume vol; // This holds the information for the partition on the card
FatReader root; // This holds the information for the volumes root directory
FatReader file; // This object represent the WAV file
WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time
/*
* Define macro to put error messages in flash memory
*/
#define error(msg) error_P(PSTR(msg))
//////////////////////////////////// SETUP
void setup() {
Serial.begin(9600);
Serial.println("Wave test!");
// try card.init(true) if errors occur on V1.0 Wave Shield
if (!card.init()) {
error("Card init. failed!");
}
// enable optimize read - some cards may timeout
card.partialBlockRead(true);
if (!vol.init(card)) {
error("No partition!");
}
if (!root.openRoot(vol)) {
error("Couldn't open root");
}
putstring_nl("Files found:");
root.ls();
}
// forward declarition
void playcomplete(FatReader &file);
//////////////////////////////////// LOOP
void loop() {
uint8_t i, r;
char c, name[15];
dir_t dir;
root.rewind();
// scroll through the files in the directory
while (root.readDir(dir) > 0) {
// only play .WAV files
if (strncmp_P((char *)&dir.name[8],PSTR("WAV"), 3)) continue;
if (!file.open(vol, dir)){
putstring("Can't open ");
printEntryName(dir);
Serial.println();
continue;
}
putstring("\n\rPlaying ");
printEntryName(dir);
Serial.println();
playcomplete(file);
file.close();
}
}
/////////////////////////////////// HELPERS
/*
* print error message and halt
*/
void error_P(const char *str) {
PgmPrint("Error: ");
SerialPrint_P(str);
sdErrorCheck();
while(1);
}
/*
* print error message and halt if SD I/O error, great for debugging!
*/
void sdErrorCheck(void) {
if (!card.errorCode()) return;
PgmPrint("\r\nSD I/O error: ");
Serial.print(card.errorCode(), HEX);
PgmPrint(", ");
Serial.println(card.errorData(), HEX);
while(1);
}
int16_t lastpotval = 0;
#define HYSTERESIS 3
/*
* play file with sample rate changes
*/
void playcomplete(FatReader &file) {
int16_t potval;
uint32_t newsamplerate;
if (!wave.create(file)) {
putstring_nl(" Not a valid WAV"); return;
}
// ok time to play!
wave.play();
while (wave.isplaying) {
potval = analogRead(0);
if ( ((potval - lastpotval) > HYSTERESIS) || ((lastpotval - potval) > HYSTERESIS)) {
putstring("pot = ");
Serial.println(potval, DEC);
putstring("tickspersam = ");
Serial.print(wave.dwSamplesPerSec, DEC);
putstring(" -> ");
newsamplerate = wave.dwSamplesPerSec;
newsamplerate *= potval;
newsamplerate /= 512; // we want to 'split' between sped up and slowed down.
if (newsamplerate > 24000) {
newsamplerate = 24000;
}
if (newsamplerate < 1000) {
newsamplerate = 1000;
}
wave.setSampleRate(newsamplerate);
Serial.println(newsamplerate, DEC);
lastpotval = potval;
}
delay(100);
}
sdErrorCheck();
}
@@ -0,0 +1,146 @@
// this sketch wiil do a read stress test on a SD card.
// run time is about 25 seconds
#include <avr/pgmspace.h>
#include <FatReader.h>
#include <WaveUtil.h>
SdReader card;
uint8_t cidDmp(void) {
cid_t cid;
if (!card.readCID(cid)) {
putstring("readCID failed");
sdError();
return 0;
}
putstring("\nManufacturer ID: ");
Serial.println(cid.mid, HEX);
putstring("OEM ID: ");
Serial.write(cid.oid[0]);
Serial.write(cid.oid[1]);
Serial.println();
putstring("Product: ");
for (uint8_t i = 0; i < 5; i++) {
Serial.write(cid.pnm[i]);
}
putstring("\nVersion: ");
Serial.print(cid.prv_n, DEC);
Serial.write('.');
Serial.println(cid.prv_m, DEC);
putstring("Serial number: ");
Serial.println(cid.psn);
putstring("Manufacturing date: ");
Serial.print(cid.mdt_month, DEC);
Serial.write('/');
Serial.println(2000 + cid.mdt_year_low + (cid.mdt_year_high << 4));
Serial.println();
return 1;
}
// print partition table
uint8_t partDmp(void) {
part_t pt;
putstring_nl("partion,boot,type,start,length");
for (uint8_t ip = 1; ip < 5; ip++) {
if (!card.readData(0, PART_OFFSET + 16*(ip-1), (uint8_t *)&pt, 16)) {
putstring("read partition table failed");
sdError();
return 0;
}
Serial.print(ip, DEC);
Serial.write(',');
Serial.print(pt.boot,HEX);
Serial.write(',');
Serial.print(pt.type, HEX);
Serial.write(',');
Serial.print(pt.firstSector);
Serial.write(',');
Serial.println(pt.totalSectors);
}
return true;
}
void sdError(void) {
putstring_nl("SD error");
putstring("errorCode: ");
Serial.println(card.errorCode(), HEX);
putstring("errorData: ");
Serial.println(card.errorData(), HEX);
return;
}
void setup(void) {
Serial.begin(9600);
}
void loop(void) {
while (Serial.read() >= 0) {}
putstring_nl("\ntype any character to start");
while (Serial.read() < 0) {}
uint32_t t0 = millis();
uint8_t r = card.init(0);
uint32_t d = millis()- t0;
if (!r) {
putstring_nl("\ncard.init failed");
sdError();
return;
}
putstring("\ninit time: ");
Serial.println(d);
putstring("\nCard type: ");
switch(card.type()) {
case SD_CARD_TYPE_SD1:
putstring_nl("SD1");
break;
case SD_CARD_TYPE_SD2:
putstring_nl("SD2");
break;
case SD_CARD_TYPE_SDHC:
putstring_nl("SDHC");
break;
default:
putstring_nl("Unknown");
}
if(!cidDmp()) return;
uint32_t size = card.cardSize();
if (size == 0) {
putstring("cardSize failed");
sdError();
return;
}
putstring("card size: ");
Serial.print(size);
putstring(" (512 byte blocks)\n");
if(!partDmp()) return;
uint16_t nTest = 20000;
uint16_t nRead = 0;
uint8_t buf[2];
d = size/nTest;
uint32_t b;
putstring_nl("Read test starting. Please Wait.");
uint32_t m0 = millis();
for (nRead = 0; nRead < nTest; nRead++){
b = nRead*d;
if (!(r = card.readData(b, 510, buf, 2))) break;
if (nRead == 0 && (buf[0] != 0X55 || buf[1] != 0XAA)) {
putstring("Invalid block zero signature: ");
Serial.print(buf[0], HEX);
Serial.write(',');
Serial.println(buf[1], HEX);
}
}
uint32_t m1 = millis();
putstring("\nRead ");
Serial.print(nRead);
putstring_nl(" blocks");
putstring("mills: ");
Serial.println(m1 - m0);
if(r) {
putstring_nl("\nDone");
}
else {
putstring_nl("\nRead Failure");
putstring("lbn: ");
Serial.println(b);
sdError();
}
}
@@ -0,0 +1,117 @@
/*
* DVOLUME must be set nonzero in WaveHC.h to use this example.
*
* Adafruit SoftVolumeChange.pde modified to use WaveHC library.
*
* Play files with software volume control.
*/
#include <WaveHC.h>
#include <WaveUtil.h>
SdReader card; // This object holds the information for the card
FatVolume vol; // This holds the information for the partition on the card
FatReader root; // This holds the information for the volumes root directory
FatReader file; // This object represent the WAV file
WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time
/*
* Define macro to put error messages in flash memory
*/
#define error(msg) error_P(PSTR(msg))
//////////////////////////////////// SETUP
void setup() {
Serial.begin(9600);
Serial.println("Wave test!");
// try card.init(true) if errors occur on V1.0 Wave Shield
if (!card.init()) {
error("Card init. failed!");
}
// enable optimize read - some cards may timeout
card.partialBlockRead(true);
if (!vol.init(card)) {
error("No partition!");
}
if (!root.openRoot(vol)) {
error("Couldn't open root"); return;
}
putstring_nl("Files found:");
root.ls();
}
// forward declarition
void playcomplete(FatReader &file);
//////////////////////////////////// LOOP
void loop() {
uint8_t i, r;
char c, name[15];
dir_t dir;
root.rewind();
// scroll through the files in the directory
while (root.readDir(dir) > 0) {
// only play .WAV files
if (strncmp_P((char *)&dir.name[8],PSTR("WAV"), 3)) continue;
if (!file.open(vol, dir)){
putstring("Can't open ");
printEntryName(dir);
Serial.println();
continue;
}
putstring("\n\rPlaying ");
printEntryName(dir);
Serial.println();
playcomplete(file);
file.close();
}
}
/////////////////////////////////// HELPERS
/*
* print error message and halt
*/
void error_P(const char *str) {
PgmPrint("Error: ");
SerialPrint_P(str);
sdErrorCheck();
while(1);
}
/*
* print error message and halt if SD I/O error, great for debugging!
*/
void sdErrorCheck(void) {
if (!card.errorCode()) return;
PgmPrint("\r\nSD I/O error: ");
Serial.print(card.errorCode(), HEX);
PgmPrint(", ");
Serial.println(card.errorData(), HEX);
while(1);
}
/*
* Play files with software volume control
*/
void playcomplete(FatReader &file) {
if (!wave.create(file)) {
putstring_nl(" Not a valid WAV"); return;
}
// ok time to play!
wave.play();
while (wave.isplaying) {
putstring("Vol: ");
// DVOLUME must be nonzero in WaveHC.h to use volume.
Serial.println(wave.volume, DEC);
delay(2000);
wave.volume++;
if ( wave.volume == 12) {
wave.volume = 0;
}
}
sdErrorCheck();
}
+148
View File
@@ -0,0 +1,148 @@
/*
* This example plays every .WAV file it finds on the SD card in a loop
*/
#include <WaveHC.h>
#include <WaveUtil.h>
SdReader card; // This object holds the information for the card
FatVolume vol; // This holds the information for the partition on the card
FatReader root; // This holds the information for the volumes root directory
WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time
uint8_t dirLevel; // indent level for file/dir names (for prettyprinting)
dir_t dirBuf; // buffer for directory reads
/*
* Define macro to put error messages in flash memory
*/
#define error(msg) error_P(PSTR(msg))
// Function definitions (we define them here, but the code is below)
void play(FatReader &dir);
//////////////////////////////////// SETUP
void setup() {
Serial.begin(9600); // set up Serial library at 9600 bps for debugging
putstring_nl("\nWave test!"); // say we woke up!
putstring("Free RAM: "); // This can help with debugging, running out of RAM is bad
Serial.println(FreeRam());
// if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you
if (!card.init()) { //play with 8 MHz spi (default faster!)
error("Card init. failed!"); // Something went wrong, lets print out why
}
// enable optimize read - some cards may timeout. Disable if you're having problems
card.partialBlockRead(true);
// Now we will look for a FAT partition!
uint8_t part;
for (part = 0; part < 5; part++) { // we have up to 5 slots to look in
if (vol.init(card, part))
break; // we found one, lets bail
}
if (part == 5) { // if we ended up not finding one :(
error("No valid FAT partition!"); // Something went wrong, lets print out why
}
// Lets tell the user about what we found
putstring("Using partition ");
Serial.print(part, DEC);
putstring(", type is FAT");
Serial.println(vol.fatType(), DEC); // FAT16 or FAT32?
// Try to open the root directory
if (!root.openRoot(vol)) {
error("Can't open root dir!"); // Something went wrong,
}
// Whew! We got past the tough parts.
putstring_nl("Files found (* = fragmented):");
// Print out all of the files in all the directories.
root.ls(LS_R | LS_FLAG_FRAGMENTED);
}
//////////////////////////////////// LOOP
void loop() {
root.rewind();
play(root);
}
/////////////////////////////////// HELPERS
/*
* print error message and halt
*/
void error_P(const char *str) {
PgmPrint("Error: ");
SerialPrint_P(str);
sdErrorCheck();
while(1);
}
/*
* print error message and halt if SD I/O error, great for debugging!
*/
void sdErrorCheck(void) {
if (!card.errorCode()) return;
PgmPrint("\r\nSD I/O error: ");
Serial.print(card.errorCode(), HEX);
PgmPrint(", ");
Serial.println(card.errorData(), HEX);
while(1);
}
/*
* play recursively - possible stack overflow if subdirectories too nested
*/
void play(FatReader &dir) {
FatReader file;
while (dir.readDir(dirBuf) > 0) { // Read every file in the directory one at a time
// Skip it if not a subdirectory and not a .WAV file
if (!DIR_IS_SUBDIR(dirBuf)
&& strncmp_P((char *)&dirBuf.name[8], PSTR("WAV"), 3)) {
continue;
}
Serial.println(); // clear out a new line
for (uint8_t i = 0; i < dirLevel; i++) {
Serial.write(' '); // this is for prettyprinting, put spaces in front
}
if (!file.open(vol, dirBuf)) { // open the file in the directory
error("file.open failed"); // something went wrong
}
if (file.isDir()) { // check if we opened a new directory
putstring("Subdir: ");
printEntryName(dirBuf);
Serial.println();
dirLevel += 2; // add more spaces
// play files in subdirectory
play(file); // recursive!
dirLevel -= 2;
}
else {
// Aha! we found a file that isnt a directory
putstring("Playing ");
printEntryName(dirBuf); // print it out
if (!wave.create(file)) { // Figure out, is it a WAV proper?
putstring(" Not a valid WAV"); // ok skip it
} else {
Serial.println(); // Hooray it IS a WAV proper!
wave.play(); // make some noise!
uint8_t n = 0;
while (wave.isplaying) {// playing occurs in interrupts, so we print dots in realtime
putstring(".");
if (!(++n % 32))Serial.println();
delay(100);
}
sdErrorCheck(); // everything OK?
// if (wave.errors)Serial.println(wave.errors); // wave decoding errors
}
}
}
}
@@ -0,0 +1,184 @@
/*
* This sketch illustrates opening files by index
* which can significantly reduce latency.
*
* How to prepare a test SD:
* Start with a clean newly formatted SD.
* First copy the 400 files in the 'fill' folder to the SD.
* Next copy the 16 files in the 'DTMF' folder to the SD.
* There should be 416 files in the SD root directory.
*
* You must copy the files in the above order so the 'fill'
* files occur in the directory before the DTMF files.
*
* Run this sketch using the prepared SD. Notice the
* difference in latency between play by name and
* play by index.
*/
#include <WaveHC.h>
#include <WaveUtil.h>
SdReader card; // This object holds the information for the card
FatVolume vol; // This holds the information for the partition on the card
FatReader root; // This holds the information for the volumes root directory
FatReader file; // This object represent the WAV file
WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time
// time to play each tone in milliseconds
#define PLAY_TIME 200
/*
* Define macro to put error messages in flash memory
*/
#define error(msg) error_P(PSTR(msg))
//////////////////////////////////// SETUP
void setup() {
Serial.begin(9600);
if (!card.init()) error("card.init");
// enable optimized read - some cards may timeout
card.partialBlockRead(true);
if (!vol.init(card)) error("vol.init");
if (!root.openRoot(vol)) error("openRoot");
PgmPrintln("Index files");
indexFiles();
PgmPrintln("Play files by index");
playByIndex();
PgmPrintln("Play files by name");
playByName();
}
//////////////////////////////////// LOOP
void loop() { }
/////////////////////////////////// HELPERS
/*
* print error message and halt
*/
void error_P(const char *str) {
PgmPrint("Error: ");
SerialPrint_P(str);
sdErrorCheck();
while(1);
}
/*
* print error message and halt if SD I/O error, great for debugging!
*/
void sdErrorCheck(void) {
if (!card.errorCode()) return;
PgmPrint("\r\nSD I/O error: ");
Serial.print(card.errorCode(), HEX);
PgmPrint(", ");
Serial.println(card.errorData(), HEX);
while(1);
}
// Number of files.
#define FILE_COUNT 16
// Files are 'touch tone phone' DTMF tones, P = #, S = *
// Most phones don't have A, B, C, and D tones.
// file names are of the form DTMFx.WAV where x is one of
// the letters from fileLetter[]
char fileLetter[] = {'0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', 'A', 'B', 'C', 'D', 'P', 'S'};
// index of DTMF files in the root directory
uint16_t fileIndex[FILE_COUNT];
/*
* Find files and save file index. A file's index is is the
* index of it's directory entry in it's directory file.
*/
void indexFiles(void) {
char name[10];
// copy flash string to RAM
strcpy_P(name, PSTR("DTMFx.WAV"));
for (uint8_t i = 0; i < FILE_COUNT; i++) {
// Make file name
name[4] = fileLetter[i];
// Open file by name
if (!file.open(root, name)) error("open by name");
// Save file's index (byte offset of directory entry divided by entry size)
// Current position is just after entry so subtract one.
fileIndex[i] = root.readPosition()/32 - 1;
}
PgmPrintln("Done");
}
/*
* Play file by index and print latency in ms
*/
void playByIndex(void) {
for (uint8_t i = 0; i < FILE_COUNT; i++) {
// start time
uint32_t t = millis();
// open by index
if (!file.open(root, fileIndex[i])) {
error("open by index");
}
// create and play Wave
if (!wave.create(file)) error("wave.create");
wave.play();
// print time to open file and start play
Serial.println(millis() - t);
// stop after PLAY_TIME ms
while((millis() - t) < PLAY_TIME);
wave.stop();
// check for play errors
sdErrorCheck();
}
PgmPrintln("Done");
}
/*
* Play file by name and print latency in ms
*/
void playByName(void) {
char name[10];
// copy flash string to RAM
strcpy_P(name, PSTR("DTMFx.WAV"));
for (uint8_t i = 0; i < FILE_COUNT; i++) {
// start time
uint32_t t = millis();
// make file name
name[4] = fileLetter[i];
// open file by name
if (!file.open(root, name)) error("open by name");
// create wave and start play
if (!wave.create(file))error("wave.create");
wave.play();
// print time
Serial.println(millis() - t);
// stop after PLAY_TIME ms
while((millis() - t) < PLAY_TIME);
wave.stop();
// check for play errors
sdErrorCheck();
}
PgmPrintln("Done");
}