--- /dev/null
+#include "WProgram.h"\r
+#include "Tacton.h"\r
+\r
+\r
+/*Tacton::Tacton()\r
+:_nbframes(0), _patterns(NULL), _durations(NULL), _frequencies(NULL), _amplitudes(NULL)\r
+{\r
+}*/\r
+\r
+Tacton::Tacton(unsigned int nbframes, byte *desc)\r
+:_nbframes(nbframes), _patterns((byte *)malloc(nbframes * sizeof(byte))), _durations((unsigned int *)malloc(nbframes * sizeof(unsigned int))), _frequencies((unsigned int *)malloc(nbframes * sizeof(unsigned int))), _amplitudes((byte *)malloc(nbframes * sizeof(byte)))\r
+{\r
+ if (isValid())\r
+ {\r
+ for(int i = 0 ; i < nbframes ; i++)\r
+ {\r
+ _patterns[i] = desc[6*i];\r
+ _durations[i] = (((unsigned int)(desc[6*i+1])) << 8) | ((unsigned int)(desc[6*i+2]));\r
+ _frequencies[i] = (((unsigned int)(desc[6*i+3])) << 8) | ((unsigned int)(desc[6*i+4]));\r
+ _amplitudes[i] = desc[6*i+5];\r
+ }\r
+ }\r
+}\r
+\r
+/*Tacton::Tacton(const Tacton &tacton)\r
+:_nbframes(tacton._nbframes), _patterns((byte *)malloc(tacton._nbframes * sizeof(byte))), _durations((unsigned int *)malloc(tacton._nbframes * sizeof(unsigned int))), _frequencies((unsigned int *)malloc(tacton._nbframes * sizeof(unsigned int))), _amplitudes((byte *)malloc(tacton._nbframes * sizeof(byte)))\r
+{\r
+ for(int i = 0 ; i < tacton._nbframes ; i++)\r
+ {\r
+ _patterns[i] = tacton._patterns[i];\r
+ _durations[i] = tacton._durations[i];\r
+ _frequencies[i] = tacton._frequencies[i];\r
+ _amplitudes[i] = tacton._amplitudes[i];\r
+ }\r
+}*/\r
+\r
+Tacton::~Tacton()\r
+{\r
+ free(_patterns);\r
+ free(_durations);\r
+ free(_frequencies);\r
+ free(_amplitudes);\r
+}\r
+ \r
+void Tacton::play(const TactonPlayer &player) const\r
+{ \r
+ if (isValid())\r
+ for (int i = 0 ; i < _nbframes ; i++)\r
+ player.beep(_patterns[i], _durations[i], _frequencies[i], _amplitudes[i]);\r
+}\r
+\r
+/*Tacton& Tacton::operator=(const Tacton &t) \r
+{\r
+ if (this == &t)\r
+ return *this;\r
+ if (_patterns)\r
+ free(_patterns);\r
+ if (_durations)\r
+ free(_durations);\r
+ if (_frequencies)\r
+ free(_frequencies);\r
+ if (_amplitudes)\r
+ free(_amplitudes);\r
+ _nbframes = t._nbframes;\r
+ _patterns = (byte *)malloc(_nbframes * sizeof(byte));\r
+ _durations = (unsigned int *)malloc(_nbframes * sizeof(unsigned int));\r
+ _frequencies = (unsigned int *)malloc(_nbframes * sizeof(unsigned int));\r
+ _amplitudes = (byte *)malloc(_nbframes * sizeof(byte));\r
+ for(int i = 0 ; i < _nbframes ; i++)\r
+ {\r
+ _patterns[i] = t._patterns[i];\r
+ _durations[i] = t._durations[i];\r
+ _frequencies[i] = t._frequencies[i];\r
+ _amplitudes[i] = t._amplitudes[i];\r
+ }\r
+\r
+ return *this;\r
+}*/\r
+
\ No newline at end of file
--- /dev/null
+#ifndef _TACTON_\r
+#define _TACTON_\r
+\r
+#include "WProgram.h"\r
+\r
+#include <TactonPlayer.h>\r
+\r
+class Tacton \r
+{\r
+ public:\r
+// Tacton();\r
+ Tacton(unsigned int nbframes, byte *desc);\r
+// Tacton(const Tacton &tacton);\r
+ ~Tacton();\r
+ \r
+ void play(const TactonPlayer &player) const;\r
+ \r
+// Tacton & operator=(const Tacton &t);\r
+ boolean isValid() const { return _patterns && _durations && _frequencies && _amplitudes; }\r
+\r
+ private:\r
+ unsigned int _nbframes;\r
+ byte *_patterns;\r
+ unsigned int *_durations;\r
+ unsigned int *_frequencies;\r
+ byte *_amplitudes;\r
+};\r
+\r
+#endif\r
--- /dev/null
+Tacton KEYWORD1\r
+play KEYWORD2\r
+isValid KEYWORD2
\ No newline at end of file
--- /dev/null
+#include "WProgram.h"\r
+#include "TactonManager.h"\r
+\r
+TactonManager::TactonManager(TactonPlayer *player)\r
+: _nbplays(0), _nbtactons(0), _player(player)\r
+{\r
+}\r
+\r
+void TactonManager::add(unsigned int nbframes, byte *desc)\r
+{\r
+ if (_nbtactons < MAXTACTONS)\r
+ {\r
+ _tactons[_nbtactons] = new Tacton(nbframes, desc);\r
+ if (_tactons[_nbtactons])\r
+ {\r
+ Serial.println("Tacton added");\r
+ _nbtactons++;\r
+ }\r
+ }\r
+}\r
+\r
+const Tacton *TactonManager::get(byte numtacton) const\r
+{\r
+ if (numtacton < _nbtactons)\r
+ return _tactons[numtacton];\r
+ else\r
+ return NULL;\r
+}\r
+\r
+void TactonManager::clear()\r
+{\r
+ for (int i = 0 ; i < _nbtactons ; i++)\r
+ delete _tactons[i];\r
+ _nbtactons = 0;\r
+ _nbplays = 0;\r
+}\r
+\r
+void TactonManager::addPlay(byte index, unsigned long timestamp)\r
+{\r
+ if (index >= _nbtactons || _nbplays >= MAXPLAYBUFFER)\r
+ return;\r
+ _playindex[_nbplays] = index;\r
+ _playtimestamps[_nbplays] = timestamp;\r
+ _nbplays++; \r
+}\r
+\r
+void TactonManager::play(byte index)\r
+{\r
+ if (index < _nbtactons)\r
+ _tactons[index]->play(*_player);\r
+}\r
+\r
+void TactonManager::play(unsigned int nbframes, byte *desc)\r
+{\r
+ Tacton t(nbframes, desc);\r
+ t.play(*_player);\r
+}\r
+\r
+void TactonManager::setOffset(unsigned long timestamp)\r
+{\r
+ _offset = timestamp;\r
+}\r
+\r
+void TactonManager::checkPlay()\r
+{\r
+ unsigned long now = millis() - _offset;\r
+/* if (_nbplays == 0 || _playtimestamps[0] > now)\r
+ return;\r
+ Serial.print("Play at ");\r
+ Serial.println(now, DEC);\r
+ play(_playindex[0]);\r
+ //shift other plays\r
+ for (int i = 0 ; i < _nbplays ; i++)\r
+ {\r
+ _playindex[i] = _playindex[i + i];\r
+ _playtimestamps[i] = _playtimestamps[i + i]; \r
+ }\r
+ _nbplays--;*/\r
+\r
+ int i = 0, j = 0;\r
+ while (_nbplays > 0 && i < MAXPLAYBUFFER && _playtimestamps[i] < now)\r
+ {\r
+ //TEST\r
+ Serial.print("Play ");\r
+ Serial.println(_playtimestamps[i], DEC);\r
+ Serial.print(" at ");\r
+ Serial.println(now, DEC);\r
+ //\r
+ play(_playindex[i]);\r
+ i++;\r
+ _nbplays--;\r
+ }\r
+ if (i == 0)\r
+ return;\r
+ //shift not played tactons\r
+ for (j = 0 ; i + j < MAXPLAYBUFFER ; j++)\r
+ {\r
+ _playindex[j] = _playindex[j + i];\r
+ _playtimestamps[j] = _playtimestamps[j + i]; \r
+ }\r
+ //erase shifted values\r
+/* for (i = j ; i < MAXPLAYBUFFER ; i++)\r
+ {\r
+ _playindex[i] = 0xff;\r
+ _playtimestamps[i] = 0xffffffff;\r
+ }*/\r
+}\r
+\r
+
\ No newline at end of file
--- /dev/null
+#ifndef _TACTONMANAGER_\r
+#define _TACTONMANAGER_\r
+\r
+#include "WProgram.h"\r
+\r
+#include <Tacton.h>\r
+#include <TactonPlayer.h>\r
+\r
+#define MAXTACTONS 16\r
+#define MAXPLAYBUFFER 10\r
+\r
+class TactonManager\r
+{\r
+ public:\r
+ TactonManager(TactonPlayer *player);\r
+ \r
+// void add(const Tacton &t);\r
+ void add(unsigned int nbframes, byte *desc);\r
+ const Tacton *get(byte numtacton) const;\r
+ \r
+ void play(byte index);\r
+ void play(unsigned int nbframes, byte *desc);\r
+ void addPlay(byte index, unsigned long timestamp);\r
+ void checkPlay();\r
+ void setOffset(unsigned long timestamp);\r
+\r
+ void clear();\r
+ \r
+ private:\r
+ byte _nbplays;\r
+ byte _nbtactons;\r
+ Tacton *_tactons[MAXTACTONS];\r
+ byte _playindex[MAXPLAYBUFFER];\r
+ unsigned long _playtimestamps[MAXPLAYBUFFER];\r
+ TactonPlayer *_player;\r
+ unsigned long _offset;\r
+};\r
+\r
+#endif\r
--- /dev/null
+TactonManager KEYWORD1\r
+get KEYWORD2\r
+add KEYWORD2\r
+clear KEYWORD2\r
+play KEYWORD2\r
+addPlay KEYWORD2\r
+checkPlay KEYWORD2
\ No newline at end of file
--- /dev/null
+#include "WProgram.h"\r
+#include "TactonPlayer.h"\r
+\r
+TactonPlayer::TactonPlayer(byte nbtactors, byte *pins)\r
+:_nbtactors(nbtactors), _pins(pins)\r
+{\r
+ for (int i = 0 ; i < nbtactors ; i++)\r
+ pinMode(pins[i], OUTPUT); \r
+}\r
+\r
+void TactonPlayer::beep(byte pattern, unsigned int duration, unsigned int frequency, byte amplitude) const\r
+{\r
+ int i;\r
+ long del = (long)(1000000 / frequency);\r
+ long looptime = (long)((((long)duration) * 1000) / (del * 2));\r
+ for (i = 0 ; i < looptime ; i++)\r
+ {\r
+ for (int j = 0 ; j < 8 ; j++)\r
+ if (j < _nbtactors && (pattern & (0x01 << j)))\r
+ analogWrite(_pins[j], amplitude);\r
+ delayMicroseconds(del);\r
+ for (int j = 0 ; j < 8 ; j++)\r
+ if (j < _nbtactors && (pattern & (0x01 << j)))\r
+ analogWrite(_pins[j], 0);\r
+ delayMicroseconds(del);\r
+ }\r
+}\r
--- /dev/null
+#ifndef _TACTONPLAYER_\r
+#define _TACTONPLAYER_\r
+\r
+#include "WProgram.h"\r
+\r
+class TactonPlayer \r
+{\r
+ public:\r
+ TactonPlayer(byte nbtactors, byte *pins);\r
+\r
+ //8bits pattern => max 8 tactors, change type if using more\r
+ void beep(byte pattern, unsigned int duration, unsigned int frequency, byte amplitude) const;\r
+ \r
+ void debug1() { analogWrite(_pins[0], 255); delay(200); analogWrite(_pins[0], 0); delay(100);}\r
+ void debug2() { analogWrite(_pins[1], 255); delay(200); analogWrite(_pins[1], 0); delay(100); }\r
+ void debug3() { analogWrite(_pins[2], 255); delay(200); analogWrite(_pins[2], 0); delay(100); }\r
+ void debug4() { analogWrite(_pins[3], 255); delay(200); analogWrite(_pins[3], 0); delay(100); }\r
+ \r
+ private: \r
+ byte _nbtactors;\r
+ byte *_pins;\r
+};\r
+\r
+#endif\r
--- /dev/null
+TactonPlayer KEYWORD1\r
+beep KEYWORD2\r
+debug1 KEYWORD2\r
+debug2 KEYWORD2\r
+debug3 KEYWORD2\r
+debug4 KEYWORD2
\ No newline at end of file
--- /dev/null
+#include <TactonManager.h>
+#include <TactonPlayer.h>
+#include <Tacton.h>
+byte pins[] = {
+ 3, 11, 9, 5};
+TactonPlayer player(4, pins);
+TactonManager manager(&player);
+
+void* operator new(size_t n, void * p) {
+ return p;
+}
+void* operator new(size_t n) {
+ return malloc(n);
+}
+void operator delete (void * p) {
+ free(p);
+};
+
+byte command = 0;
+byte posbuf = 0;
+unsigned int nbf = 0;
+byte buffer[60];
+//unsigned long start = 0;
+boolean active = false;
+
+void setup()
+{
+ Serial.begin(57600);
+ player.debug1();
+ player.debug2();
+ player.debug3();
+ player.debug4();
+}
+
+void loop()
+{
+ byte index;
+ unsigned long timestamp;
+
+ if (Serial.available() > 0)
+ {
+ if (command == 0)
+ command = Serial.read();
+ switch(command)
+ {
+ //set the timestamp to 0, and watch for scheduled tactons
+ case 'S':
+// start = millis();
+ manager.setOffset(millis());
+ command = 0;
+ active = true;
+ break;
+ //stop watching scheduled tactons, and erase registered tactons
+ case 'Q':
+ command = 0;
+ manager.clear();
+ active = false;
+ break;
+ //register a tacton
+ case 'N':
+ if (nbf == 0 && Serial.available() >= 2)
+ nbf = (((unsigned int) Serial.read()) << 8) | ((unsigned int) Serial.read());
+ if (nbf > 0)
+ {
+ //DO NOT OVERFLOW max(nbf): 10
+ while (posbuf < nbf * 6 && Serial.available() > 0)
+ {
+ buffer[posbuf] = Serial.read();
+ posbuf++;
+ }
+ if (posbuf >= nbf*6)
+ {
+ manager.add(nbf, buffer);
+ posbuf = 0;
+ command = 0;
+ nbf = 0;
+ }
+ }
+ break;
+ //play a specified tacton
+ case 'V':
+ if (nbf == 0 && Serial.available() >= 2)
+ nbf = (((unsigned int) Serial.read()) << 8) | ((unsigned int) Serial.read());
+ if (nbf > 0)
+ {
+ //DO NOT OVERFLOW max(nbf): 10
+ while (posbuf < nbf * 6 && Serial.available() > 0)
+ {
+ buffer[posbuf] = Serial.read();
+ posbuf++;
+ }
+ if (posbuf >= nbf*6)
+ {
+ manager.play(nbf, buffer);
+ posbuf = 0;
+ command = 0;
+ nbf = 0;
+ }
+ }
+ break;
+ //play a registered tacton
+ case 'T':
+ if (Serial.available() >= 1)
+ {
+ index = Serial.read();
+ manager.play(index);
+ command = 0;
+ Serial.print("Play");
+ Serial.println(index, DEC);
+ }
+ break;
+ //schedule the play of a registered tacton
+ case 'P':
+ if (Serial.available() >= 5)
+ {
+ index = Serial.read();
+ timestamp = (((unsigned long)Serial.read()) << 24) | \
+ (((unsigned long)Serial.read()) << 16) | \
+ (((unsigned long)Serial.read()) << 8) | \
+ (((unsigned long)Serial.read()));
+ Serial.print("Plan ");
+ Serial.println(timestamp, DEC);
+/* Serial.print(" played at ");
+ Serial.print(timestamp + start, DEC);
+ Serial.print(" shift=");
+ Serial.println(start, DEC);*/
+ manager.addPlay(index, timestamp);
+ command = 0;
+ }
+ break;
+ //unknown command: do nothing
+ default:
+ command = 0;
+ break;
+ }
+ }
+
+ if (active)
+ manager.checkPlay();
+}
+\r