Big Mouth Billy Bass automation library

Dependents:   BillyBass_with_SD

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers song.cpp Source File

song.cpp

00001 #include <stdlib.h>
00002 #include <string.h>
00003 #include <stdio.h>
00004 #include <ctype.h>
00005 #include <algorithm>
00006 #include <math.h>
00007 
00008 #include "billybass.hpp"
00009 #include "song.hpp"
00010 
00011 // class static
00012 char const Song::directoryName[ BASS_DIRECTORY_LENGTH + 1 ] = BASS_DIRECTORY;
00013 // class static
00014 char const *Song::textExtension = "txt";
00015 // class static
00016 char const *Song::sampleExtension = "raw";
00017 // class static
00018 unsigned const Song::NO_FISH = MAX_FISH + 1;
00019 // one song, re-used
00020 Song Song::theSong;
00021 
00022 // _name is relative to BASS_DIRECTORY
00023 // class static
00024 Song *Song::newSong(char const *_name)
00025 {
00026     Song *s = &theSong;
00027     s->reset();
00028     if (! s->parseFilename(_name)) {
00029         fprintf(stderr, "parseFilename(%s) failed\r\n", _name);
00030         goto on_error;
00031     }
00032     fprintf(stderr, "parsed filename OK\r\n");
00033     if (! s->readActions()) {
00034         fprintf(stderr, "readActions(%s) failed\r\n", _name);
00035         goto on_error;
00036     }
00037 
00038     return s;
00039 
00040 on_error:
00041     return 0;
00042 }
00043 
00044 bool Song::parseFilename(char const *_name)
00045 {
00046     if (strlen(_name) > MAX_BASENAME_LENGTH)
00047         goto on_error;
00048 
00049     strcpy(fullname, directoryName);
00050     basename = fullname + BASS_DIRECTORY_LENGTH;
00051     *basename++ = '/';
00052     strcpy(basename, _name);
00053 
00054     char *p;
00055     long n = strtol(_name, &p, 10);
00056     if (*p != '_' || n <= 0)
00057         goto on_error;
00058 
00059     sequenceNumber = (unsigned)(n - 1);
00060 
00061     p++;    // skip underscore
00062     n = strtol(p, &p, 10);
00063     if (*p != '_' || n <= 0 || n > MAX_FISH)
00064         goto on_error;
00065 
00066     whichFish = (unsigned)(n - 1);
00067 
00068     p = strrchr(basename, '.');
00069     if (!p)
00070         goto on_error;
00071 
00072     extension = p+1;
00073 
00074     if (strcasecmp(extension, sampleExtension))
00075         goto on_error;
00076 
00077     return true;
00078 
00079 on_error:
00080     whichFish = NO_FISH;
00081     basename = 0;
00082     return false;
00083 }
00084 
00085 bool Song::addAction(float _time, int _state, DigitalOut* _out, char _code)
00086 {
00087     if (numActions >= MAX_ACTIONS_PER_SONG) return false;
00088     actions[numActions++].set(_time, _state, _out, _code);
00089     return true;
00090 }
00091 
00092 bool Song::readActions()
00093 {
00094     fprintf(stderr, "reading actions of %s\r\n", getTextFileName());
00095 
00096     FILE *txtfile = fopen(getTextFileName(), "r");
00097     if (!txtfile)  {
00098         fprintf(stderr, "can't open %s\r\n", getTextFileName());
00099         return false;
00100     } else
00101         fprintf(stderr, "opened %s OK\r\n", getTextFileName());
00102     bool retval = false;
00103 
00104     BillyBass *bass = BillyBass::bassNumber(whichFish);
00105     if (!bass) {
00106         fprintf(stderr, "No bass!\r\n");
00107         goto done;
00108     }
00109 
00110     // read actions from file
00111     static char textFileBuffer[ MAX_TEXT_FILE_LENGTH ];
00112     memset(textFileBuffer, 0, sizeof(textFileBuffer));
00113     int nread = fread(textFileBuffer, 1, sizeof(textFileBuffer), txtfile);
00114     // fprintf(stderr, "Read %d bytes\r\n", nread);
00115     if (nread <= 0 || nread == sizeof(textFileBuffer)) {
00116         goto done;
00117     }
00118     unsigned line = 1;
00119     for (char *actionLine = strtok(textFileBuffer, "\r\n");
00120             actionLine;
00121             actionLine = strtok(0, "\r\n"), line++) {
00122         char *p;
00123         float startTime = strtof(actionLine, &p);
00124         if (p == actionLine)
00125             goto done;
00126 
00127         char *q;
00128         float endTime = strtof(p, &q);
00129         if (q == p)
00130             goto done;
00131 
00132         char const *outName;
00133         float onDelay, offDelay, minOnTime;
00134         DigitalOut *out = bass->outputNamed(++q, &outName, &onDelay, &offDelay, &minOnTime);
00135         if (!out) {
00136             fprintf(stderr, "%s line %d: bad outname \"%s\"\r\n", getTextFileName(), line, q);
00137             goto done;
00138         }
00139 
00140 #if FIX_TIMES
00141         startTime -= onDelay;
00142         if (startTime < 0.0) startTime = 0.0;
00143 
00144         if (endTime < startTime + minOnTime)
00145             endTime = startTime + minOnTime;
00146 #endif
00147 
00148         startTime -= remainder(startTime, SECONDS_PER_CHUNK);
00149         endTime += remainder(endTime, SECONDS_PER_CHUNK);
00150 
00151         fprintf(stderr, "%d %f %f %s\r\n", line, startTime, endTime, outName);
00152 
00153         addAction(startTime, bass->onState(), out, toupper(outName[0]));
00154         addAction(endTime, bass->offState(), out, outName[0]);
00155     }
00156     fprintf(stderr, "Added %d actions\r\n", numActions);
00157     qsort(actions, numActions, sizeof(Action), &Action::compare);
00158 #if 0
00159     for (int i = 0; i < numActions; i++ ) {
00160         fprintf(stderr, "%f %c\r\n", actions[i].actionTime, actions[i].code);
00161     }
00162 #endif
00163     retval = true;
00164 
00165 done:
00166 
00167     fclose(txtfile);
00168     return retval;
00169 }
00170