Big Mouth Billy Bass automation library
Diff: song.cpp
- Revision:
- 0:84aaade0de8f
- Child:
- 1:9b1f3eb204ac
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/song.cpp Mon Jun 17 22:17:59 2013 +0000
@@ -0,0 +1,178 @@
+#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