Big Mouth Billy Bass automation library

Dependents:   BillyBass_with_SD

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;
+}