Big Mouth Billy Bass automation library
Embed:
(wiki syntax)
Show/hide line numbers
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
Generated on Sun Jul 17 2022 08:00:04 by 1.7.2