Big Mouth Billy Bass automation library
song.cpp@7:dba9221acf48, 2013-06-20 (annotated)
- Committer:
- bikeNomad
- Date:
- Thu Jun 20 04:10:22 2013 +0000
- Revision:
- 7:dba9221acf48
- Parent:
- 6:ea8136eb6976
- Child:
- 8:ad0c038ebfc1
try to shift times and enforce minimum times
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
bikeNomad | 0:84aaade0de8f | 1 | #include <stdlib.h> |
bikeNomad | 0:84aaade0de8f | 2 | #include <string.h> |
bikeNomad | 0:84aaade0de8f | 3 | #include <stdio.h> |
bikeNomad | 0:84aaade0de8f | 4 | #include <ctype.h> |
bikeNomad | 0:84aaade0de8f | 5 | #include <algorithm> |
bikeNomad | 7:dba9221acf48 | 6 | #include <math.h> |
bikeNomad | 0:84aaade0de8f | 7 | |
bikeNomad | 0:84aaade0de8f | 8 | #include "billybass.hpp" |
bikeNomad | 0:84aaade0de8f | 9 | #include "song.hpp" |
bikeNomad | 0:84aaade0de8f | 10 | |
bikeNomad | 0:84aaade0de8f | 11 | // class static |
bikeNomad | 0:84aaade0de8f | 12 | char const Song::directoryName[ BASS_DIRECTORY_LENGTH + 1 ] = BASS_DIRECTORY; |
bikeNomad | 0:84aaade0de8f | 13 | // class static |
bikeNomad | 0:84aaade0de8f | 14 | char const *Song::textExtension = "txt"; |
bikeNomad | 0:84aaade0de8f | 15 | // class static |
bikeNomad | 0:84aaade0de8f | 16 | char const *Song::sampleExtension = "raw"; |
bikeNomad | 0:84aaade0de8f | 17 | // class static |
bikeNomad | 0:84aaade0de8f | 18 | unsigned const Song::NO_FISH = MAX_FISH + 1; |
bikeNomad | 4:f009306756b3 | 19 | // one song, re-used |
bikeNomad | 4:f009306756b3 | 20 | Song Song::theSong; |
bikeNomad | 0:84aaade0de8f | 21 | |
bikeNomad | 0:84aaade0de8f | 22 | // _name is relative to BASS_DIRECTORY |
bikeNomad | 0:84aaade0de8f | 23 | // class static |
bikeNomad | 0:84aaade0de8f | 24 | Song *Song::newSong(char const *_name) |
bikeNomad | 0:84aaade0de8f | 25 | { |
bikeNomad | 4:f009306756b3 | 26 | Song *s = &theSong; |
bikeNomad | 4:f009306756b3 | 27 | s->reset(); |
bikeNomad | 0:84aaade0de8f | 28 | if (! s->parseFilename(_name)) { |
bikeNomad | 3:6c91a6232c4a | 29 | fprintf(stderr, "parseFilename(%s) failed\r\n", _name); |
bikeNomad | 0:84aaade0de8f | 30 | goto on_error; |
bikeNomad | 0:84aaade0de8f | 31 | } |
bikeNomad | 3:6c91a6232c4a | 32 | fprintf(stderr, "parsed filename OK\r\n"); |
bikeNomad | 0:84aaade0de8f | 33 | if (! s->readActions()) { |
bikeNomad | 3:6c91a6232c4a | 34 | fprintf(stderr, "readActions(%s) failed\r\n", _name); |
bikeNomad | 0:84aaade0de8f | 35 | goto on_error; |
bikeNomad | 0:84aaade0de8f | 36 | } |
bikeNomad | 0:84aaade0de8f | 37 | |
bikeNomad | 0:84aaade0de8f | 38 | return s; |
bikeNomad | 0:84aaade0de8f | 39 | |
bikeNomad | 0:84aaade0de8f | 40 | on_error: |
bikeNomad | 0:84aaade0de8f | 41 | return 0; |
bikeNomad | 0:84aaade0de8f | 42 | } |
bikeNomad | 0:84aaade0de8f | 43 | |
bikeNomad | 0:84aaade0de8f | 44 | bool Song::parseFilename(char const *_name) |
bikeNomad | 0:84aaade0de8f | 45 | { |
bikeNomad | 0:84aaade0de8f | 46 | if (strlen(_name) > MAX_BASENAME_LENGTH) |
bikeNomad | 0:84aaade0de8f | 47 | goto on_error; |
bikeNomad | 0:84aaade0de8f | 48 | |
bikeNomad | 0:84aaade0de8f | 49 | strcpy(fullname, directoryName); |
bikeNomad | 0:84aaade0de8f | 50 | basename = fullname + BASS_DIRECTORY_LENGTH; |
bikeNomad | 0:84aaade0de8f | 51 | *basename++ = '/'; |
bikeNomad | 0:84aaade0de8f | 52 | strcpy(basename, _name); |
bikeNomad | 0:84aaade0de8f | 53 | |
bikeNomad | 0:84aaade0de8f | 54 | char *p; |
bikeNomad | 0:84aaade0de8f | 55 | long n = strtol(_name, &p, 10); |
bikeNomad | 0:84aaade0de8f | 56 | if (*p != '_' || n <= 0) |
bikeNomad | 0:84aaade0de8f | 57 | goto on_error; |
bikeNomad | 0:84aaade0de8f | 58 | |
bikeNomad | 0:84aaade0de8f | 59 | sequenceNumber = (unsigned)(n - 1); |
bikeNomad | 0:84aaade0de8f | 60 | |
bikeNomad | 0:84aaade0de8f | 61 | p++; // skip underscore |
bikeNomad | 0:84aaade0de8f | 62 | n = strtol(p, &p, 10); |
bikeNomad | 0:84aaade0de8f | 63 | if (*p != '_' || n <= 0 || n > MAX_FISH) |
bikeNomad | 0:84aaade0de8f | 64 | goto on_error; |
bikeNomad | 0:84aaade0de8f | 65 | |
bikeNomad | 0:84aaade0de8f | 66 | whichFish = (unsigned)(n - 1); |
bikeNomad | 0:84aaade0de8f | 67 | |
bikeNomad | 0:84aaade0de8f | 68 | p = strrchr(basename, '.'); |
bikeNomad | 0:84aaade0de8f | 69 | if (!p) |
bikeNomad | 0:84aaade0de8f | 70 | goto on_error; |
bikeNomad | 0:84aaade0de8f | 71 | |
bikeNomad | 0:84aaade0de8f | 72 | extension = p+1; |
bikeNomad | 0:84aaade0de8f | 73 | |
bikeNomad | 0:84aaade0de8f | 74 | if (strcasecmp(extension, sampleExtension)) |
bikeNomad | 0:84aaade0de8f | 75 | goto on_error; |
bikeNomad | 0:84aaade0de8f | 76 | |
bikeNomad | 0:84aaade0de8f | 77 | return true; |
bikeNomad | 0:84aaade0de8f | 78 | |
bikeNomad | 0:84aaade0de8f | 79 | on_error: |
bikeNomad | 0:84aaade0de8f | 80 | whichFish = NO_FISH; |
bikeNomad | 0:84aaade0de8f | 81 | basename = 0; |
bikeNomad | 0:84aaade0de8f | 82 | return false; |
bikeNomad | 0:84aaade0de8f | 83 | } |
bikeNomad | 0:84aaade0de8f | 84 | |
bikeNomad | 7:dba9221acf48 | 85 | bool Song::addAction(float _time, int _state, DigitalOut* _out, char _code) |
bikeNomad | 7:dba9221acf48 | 86 | { |
bikeNomad | 7:dba9221acf48 | 87 | Action *priorAction = (numActions > 0) ? actions + numActions - 1 : 0; |
bikeNomad | 7:dba9221acf48 | 88 | if (priorAction ) { |
bikeNomad | 7:dba9221acf48 | 89 | if (priorAction->output == _out) { |
bikeNomad | 7:dba9221acf48 | 90 | if (priorAction->actionTime >= _time && priorAction->desiredState != _state) |
bikeNomad | 7:dba9221acf48 | 91 | return true; |
bikeNomad | 7:dba9221acf48 | 92 | if (priorAction->actionTime < _time && priorAction->desiredState == _state) { |
bikeNomad | 7:dba9221acf48 | 93 | priorAction->actionTime = _time; |
bikeNomad | 7:dba9221acf48 | 94 | return true; |
bikeNomad | 7:dba9221acf48 | 95 | } |
bikeNomad | 7:dba9221acf48 | 96 | } |
bikeNomad | 7:dba9221acf48 | 97 | } |
bikeNomad | 7:dba9221acf48 | 98 | if (numActions >= MAX_ACTIONS_PER_SONG) return false; |
bikeNomad | 7:dba9221acf48 | 99 | actions[numActions++].set(_time, _state, _out, _code); |
bikeNomad | 7:dba9221acf48 | 100 | return true; |
bikeNomad | 7:dba9221acf48 | 101 | } |
bikeNomad | 7:dba9221acf48 | 102 | |
bikeNomad | 0:84aaade0de8f | 103 | bool Song::readActions() |
bikeNomad | 0:84aaade0de8f | 104 | { |
bikeNomad | 3:6c91a6232c4a | 105 | fprintf(stderr, "reading actions of %s\r\n", getTextFileName()); |
bikeNomad | 1:9b1f3eb204ac | 106 | |
bikeNomad | 0:84aaade0de8f | 107 | FILE *txtfile = fopen(getTextFileName(), "r"); |
bikeNomad | 0:84aaade0de8f | 108 | if (!txtfile) { |
bikeNomad | 3:6c91a6232c4a | 109 | fprintf(stderr, "can't open %s\r\n", getTextFileName()); |
bikeNomad | 0:84aaade0de8f | 110 | return false; |
bikeNomad | 1:9b1f3eb204ac | 111 | } else |
bikeNomad | 3:6c91a6232c4a | 112 | fprintf(stderr, "opened %s OK\r\n", getTextFileName()); |
bikeNomad | 0:84aaade0de8f | 113 | bool retval = false; |
bikeNomad | 0:84aaade0de8f | 114 | |
bikeNomad | 0:84aaade0de8f | 115 | BillyBass *bass = BillyBass::bassNumber(whichFish); |
bikeNomad | 0:84aaade0de8f | 116 | if (!bass) { |
bikeNomad | 3:6c91a6232c4a | 117 | fprintf(stderr, "No bass!\r\n"); |
bikeNomad | 0:84aaade0de8f | 118 | goto done; |
bikeNomad | 0:84aaade0de8f | 119 | } |
bikeNomad | 0:84aaade0de8f | 120 | |
bikeNomad | 0:84aaade0de8f | 121 | // read actions from file |
bikeNomad | 5:869b3711bdb3 | 122 | static char textFileBuffer[ MAX_TEXT_FILE_LENGTH ]; |
bikeNomad | 1:9b1f3eb204ac | 123 | memset(textFileBuffer, 0, sizeof(textFileBuffer)); |
bikeNomad | 1:9b1f3eb204ac | 124 | int nread = fread(textFileBuffer, 1, sizeof(textFileBuffer), txtfile); |
bikeNomad | 3:6c91a6232c4a | 125 | // fprintf(stderr, "Read %d bytes\r\n", nread); |
bikeNomad | 1:9b1f3eb204ac | 126 | if (nread <= 0 || nread == sizeof(textFileBuffer)) { |
bikeNomad | 1:9b1f3eb204ac | 127 | goto done; |
bikeNomad | 1:9b1f3eb204ac | 128 | } |
bikeNomad | 0:84aaade0de8f | 129 | unsigned line = 1; |
bikeNomad | 1:9b1f3eb204ac | 130 | for (char *actionLine = strtok(textFileBuffer, "\r\n"); |
bikeNomad | 1:9b1f3eb204ac | 131 | actionLine; |
bikeNomad | 1:9b1f3eb204ac | 132 | actionLine = strtok(0, "\r\n"), line++) { |
bikeNomad | 1:9b1f3eb204ac | 133 | char *p; |
bikeNomad | 0:84aaade0de8f | 134 | float startTime = strtof(actionLine, &p); |
bikeNomad | 0:84aaade0de8f | 135 | if (p == actionLine) |
bikeNomad | 0:84aaade0de8f | 136 | goto done; |
bikeNomad | 0:84aaade0de8f | 137 | |
bikeNomad | 0:84aaade0de8f | 138 | char *q; |
bikeNomad | 0:84aaade0de8f | 139 | float endTime = strtof(p, &q); |
bikeNomad | 0:84aaade0de8f | 140 | if (q == p) |
bikeNomad | 0:84aaade0de8f | 141 | goto done; |
bikeNomad | 0:84aaade0de8f | 142 | |
bikeNomad | 0:84aaade0de8f | 143 | char const *outName; |
bikeNomad | 7:dba9221acf48 | 144 | float onDelay, offDelay, minOnTime; |
bikeNomad | 7:dba9221acf48 | 145 | DigitalOut *out = bass->outputNamed(++q, &outName, &onDelay, &offDelay, &minOnTime); |
bikeNomad | 0:84aaade0de8f | 146 | if (!out) { |
bikeNomad | 3:6c91a6232c4a | 147 | fprintf(stderr, "%s line %d: bad outname \"%s\"\r\n", getTextFileName(), line, q); |
bikeNomad | 0:84aaade0de8f | 148 | goto done; |
bikeNomad | 0:84aaade0de8f | 149 | } |
bikeNomad | 7:dba9221acf48 | 150 | |
bikeNomad | 7:dba9221acf48 | 151 | startTime -= onDelay; |
bikeNomad | 7:dba9221acf48 | 152 | startTime -= remainder(startTime, SECONDS_PER_CHUNK); |
bikeNomad | 7:dba9221acf48 | 153 | if (startTime < 0.0) startTime = 0.0; |
bikeNomad | 7:dba9221acf48 | 154 | |
bikeNomad | 7:dba9221acf48 | 155 | endTime -= offDelay; |
bikeNomad | 7:dba9221acf48 | 156 | endTime += remainder(endTime, SECONDS_PER_CHUNK); |
bikeNomad | 7:dba9221acf48 | 157 | if (endTime < startTime + minOnTime) |
bikeNomad | 7:dba9221acf48 | 158 | endTime = startTime + minOnTime; |
bikeNomad | 7:dba9221acf48 | 159 | |
bikeNomad | 7:dba9221acf48 | 160 | fprintf(stderr, "%d %f %f %s\r\n", line, startTime, endTime, outName); |
bikeNomad | 0:84aaade0de8f | 161 | |
bikeNomad | 6:ea8136eb6976 | 162 | addAction(startTime, bass->onState(), out, toupper(outName[0])); |
bikeNomad | 6:ea8136eb6976 | 163 | addAction(endTime, bass->offState(), out, outName[0]); |
bikeNomad | 0:84aaade0de8f | 164 | } |
bikeNomad | 4:f009306756b3 | 165 | fprintf(stderr, "Added %d actions\r\n", numActions); |
bikeNomad | 4:f009306756b3 | 166 | qsort(actions, numActions, sizeof(Action), &Action::compare); |
bikeNomad | 7:dba9221acf48 | 167 | for (int i = 0; i < numActions; i++ ) { |
bikeNomad | 7:dba9221acf48 | 168 | fprintf(stderr, "%f %c\r\n", actions[i].actionTime, actions[i].code); |
bikeNomad | 7:dba9221acf48 | 169 | } |
bikeNomad | 0:84aaade0de8f | 170 | retval = true; |
bikeNomad | 0:84aaade0de8f | 171 | |
bikeNomad | 0:84aaade0de8f | 172 | done: |
bikeNomad | 1:9b1f3eb204ac | 173 | |
bikeNomad | 0:84aaade0de8f | 174 | fclose(txtfile); |
bikeNomad | 0:84aaade0de8f | 175 | return retval; |
bikeNomad | 0:84aaade0de8f | 176 | } |
bikeNomad | 4:f009306756b3 | 177 |