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