Big Mouth Billy Bass automation library
song.cpp
- Committer:
- bikeNomad
- Date:
- 2013-06-17
- Revision:
- 0:84aaade0de8f
- Child:
- 1:9b1f3eb204ac
File content as of revision 0:84aaade0de8f:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <algorithm>
#include "billybass.hpp"
#include "song.hpp"
// class static
char const Song::directoryName[ BASS_DIRECTORY_LENGTH + 1 ] = BASS_DIRECTORY;
// class static
char const *Song::textExtension = "txt";
// class static
char const *Song::sampleExtension = "raw";
// class static
unsigned const Song::NO_FISH = MAX_FISH + 1;
// class static
std::list<Song*> Song::songs;
// _name is relative to BASS_DIRECTORY
// class static
Song *Song::newSong(char const *_name)
{
Song *s = new Song;
if (!s) {
pc.printf("new Song == 0\r\n");
return 0;
}
if (! s->parseFilename(_name)) {
pc.printf("parseFilename(%s) failed\r\n", _name);
goto on_error;
}
if (! s->readActions()) {
pc.printf("readActions(%s) failed\r\n", _name);
goto on_error;
}
songs.push_back(s);
return s;
on_error:
delete s;
return 0;
}
// class static
void Song::clearAllSongs()
{
for (std::list<Song *>::const_iterator song = songs.begin(); song != songs.end(); song++)
delete *song;
songs.clear();
}
// class static
unsigned Song::readAllSongs(DIR *bassDir)
{
if (!bassDir) return 0;
clearAllSongs();
while (dirent *dir = bassDir->readdir()) {
pc.printf("Reading %s\r\n", dir->d_name);
unsigned namelen = strlen(dir->d_name);
if (namelen > 9 && !strcasecmp(dir->d_name + namelen - 3, sampleExtension)) {
Song *song = Song::newSong(dir->d_name);
if (!song) {
pc.printf("ERROR reading %s\r\n", dir->d_name);
} else {
song->print(pc);
}
}
}
return songs.size();
}
bool Song::parseFilename(char const *_name)
{
if (strlen(_name) > MAX_BASENAME_LENGTH)
goto on_error;
strcpy(fullname, directoryName);
basename = fullname + BASS_DIRECTORY_LENGTH;
*basename++ = '/';
strcpy(basename, _name);
char *p;
long n = strtol(_name, &p, 10);
if (*p != '_' || n <= 0)
goto on_error;
sequenceNumber = (unsigned)(n - 1);
p++; // skip underscore
n = strtol(p, &p, 10);
if (*p != '_' || n <= 0 || n > MAX_FISH)
goto on_error;
whichFish = (unsigned)(n - 1);
p = strrchr(basename, '.');
if (!p)
goto on_error;
extension = p+1;
if (strcasecmp(extension, sampleExtension))
goto on_error;
return true;
on_error:
whichFish = NO_FISH;
basename = 0;
return false;
}
bool Song::readActions()
{
FILE *txtfile = fopen(getTextFileName(), "r");
if (!txtfile) {
pc.printf("can't open %s\r\n", getTextFileName());
return false;
}
bool retval = false;
BillyBass *bass = BillyBass::bassNumber(whichFish);
if (!bass) {
pc.printf("No bass!\r\n");
goto done;
}
// read actions from file
unsigned line = 1;
char actionLine[ MAX_ACTION_LINE_LENGTH + 1 ];
while (true) {
if (!fgets(actionLine, sizeof(actionLine), txtfile))
break;
// delete trailing whitespace
char *p = actionLine + strlen(actionLine) - 1;
while (isspace(*p)) *p-- = 0;
float startTime = strtof(actionLine, &p);
if (p == actionLine)
goto done;
char *q;
float endTime = strtof(p, &q);
if (q == p)
goto done;
while (isspace(*q)) q++;
char const *outName;
DigitalOut *out = bass->outputNamed(q, &outName);
if (!out) {
pc.printf("%s line %d: bad outname \"%s\"\r\n", getTextFileName(), line, q);
goto done;
}
pc.printf("%d add %f %f %s\r\n", line, startTime, endTime, outName);
actions.push_back(Action(startTime, true, out, outName));
actions.push_back(Action(endTime, false, out, outName));
line++;
}
std::sort(actions.begin(), actions.end()); // sort actions by time
retval = true;
done:
if (!retval) {
pc.printf("Error reading action from \"%s\"\r\n", actionLine);
}
fclose(txtfile);
return retval;
}
Ned Konz