andrewm@11: /*
andrewm@11: TouchKeys: multi-touch musical keyboard control software
andrewm@11: Copyright (c) 2013 Andrew McPherson
andrewm@11:
andrewm@11: This program is free software: you can redistribute it and/or modify
andrewm@11: it under the terms of the GNU General Public License as published by
andrewm@11: the Free Software Foundation, either version 3 of the License, or
andrewm@11: (at your option) any later version.
andrewm@11:
andrewm@11: This program is distributed in the hope that it will be useful,
andrewm@11: but WITHOUT ANY WARRANTY; without even the implied warranty of
andrewm@11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
andrewm@11: GNU General Public License for more details.
andrewm@11:
andrewm@11: You should have received a copy of the GNU General Public License
andrewm@11: along with this program. If not, see .
andrewm@11:
andrewm@11: =====================================================================
andrewm@11:
andrewm@11: TouchkeyEntropyGenerator.cpp: generate random TouchKeys data for testing
andrewm@11: */
andrewm@11:
andrewm@11: #include "TouchkeyEntropyGenerator.h"
andrewm@13: #include
andrewm@11:
andrewm@11: TouchkeyEntropyGenerator::TouchkeyEntropyGenerator(PianoKeyboard& keyboard)
andrewm@11: : Thread("TouchkeyEntropyGenerator"), keyboard_(keyboard),
andrewm@11: waitableEvent_(true), isRunning_(false),
andrewm@11: keyboardRangeLow_(36), keyboardRangeHigh_(60),
andrewm@11: dataInterval_(milliseconds_to_timestamp(5.0))
andrewm@11: {
andrewm@13: srand(time(NULL));
andrewm@11: }
andrewm@11:
andrewm@11: // Start the thread handling the scheduling.
andrewm@11: void TouchkeyEntropyGenerator::start() {
andrewm@11: if(isRunning_)
andrewm@11: return;
andrewm@11: // Initialize the touch data before starting
andrewm@11: for(int i = 0; i <= 127; i++) {
andrewm@11: clearTouchData(i);
andrewm@11: nextOnOffFrameCount_[i] = abs(rand()) % 8192;
andrewm@11: }
andrewm@11: isRunning_ = true;
andrewm@11: startThread();
andrewm@11: }
andrewm@11:
andrewm@11: // Stop the scheduler thread if it is currently running.
andrewm@11: void TouchkeyEntropyGenerator::stop() {
andrewm@11: if(!isRunning_)
andrewm@11: return;
andrewm@11:
andrewm@11: // Tell the thread to quit and signal the event it waits on
andrewm@11: signalThreadShouldExit();
andrewm@11: stopThread(-1);
andrewm@11:
andrewm@11: isRunning_ = false;
andrewm@11: }
andrewm@11:
andrewm@11: // Run the entropy generator in its own thread
andrewm@11: void TouchkeyEntropyGenerator::run() {
andrewm@11: timestamp_type lastDataTime = keyboard_.schedulerCurrentTimestamp();
andrewm@11: timestamp_type currentTime;
andrewm@11:
andrewm@11: while(!threadShouldExit()) {
andrewm@11: // Generate random data at regular intervals
andrewm@11: currentTime = keyboard_.schedulerCurrentTimestamp();
andrewm@11: while(currentTime - lastDataTime < dataInterval_ && !threadShouldExit()) {
andrewm@11: waitableEvent_.wait(1);
andrewm@11: currentTime = keyboard_.schedulerCurrentTimestamp();
andrewm@11: }
andrewm@11:
andrewm@11: for(int i = keyboardRangeLow_; i <= keyboardRangeHigh_; i++) {
andrewm@11: if(touchFrames_[i].count != 0) {
andrewm@11: // This key is on. Check if it should go off; otherwise generate new data
andrewm@11: if(--nextOnOffFrameCount_[i] <= 0) {
andrewm@11: clearTouchData(i);
andrewm@11: if(keyboard_.key(i) != 0)
andrewm@11: keyboard_.key(i)->touchOff(currentTime);
andrewm@11: nextOnOffFrameCount_[i] = abs(rand()) % 8192;
andrewm@11: }
andrewm@11: else {
andrewm@11: generateRandomFrame(i);
andrewm@11: if(keyboard_.key(i) != 0) {
andrewm@11: KeyTouchFrame copyFrame(touchFrames_[i]);
andrewm@11: keyboard_.key(i)->touchInsertFrame(copyFrame, currentTime);
andrewm@11: }
andrewm@11: }
andrewm@11: }
andrewm@11: else {
andrewm@11: // This key is off. Check if it should go on
andrewm@11: if(--nextOnOffFrameCount_[i] <= 0) {
andrewm@11: generateRandomFrame(i);
andrewm@11: if(keyboard_.key(i) != 0) {
andrewm@11: KeyTouchFrame copyFrame(touchFrames_[i]);
andrewm@11: keyboard_.key(i)->touchInsertFrame(copyFrame, currentTime);
andrewm@11: }
andrewm@11: nextOnOffFrameCount_[i] = abs(rand()) % 8192;
andrewm@11: }
andrewm@11: }
andrewm@11: }
andrewm@11: }
andrewm@11:
andrewm@11: // Tell all currently enabled notes to turn off
andrewm@11: for(int i = 0; i < 128; i++) {
andrewm@11: if(touchFrames_[i].count > 0 && keyboard_.key(i) != 0)
andrewm@11: keyboard_.key(i)->touchOff(currentTime);
andrewm@11: }
andrewm@11: }
andrewm@11:
andrewm@11: // Clear touch data for a particular key
andrewm@11: void TouchkeyEntropyGenerator::clearTouchData(int i) {
andrewm@11: touchFrames_[i].count = 0;
andrewm@11: touchFrames_[i].locH = -1.0;
andrewm@11: touchFrames_[i].nextId = 0;
andrewm@11: for(int j = 0; j < 3; j++) {
andrewm@11: touchFrames_[i].ids[j] = -1;
andrewm@11: touchFrames_[i].locs[j] = -1.0;
andrewm@11: touchFrames_[i].sizes[j] = 0;
andrewm@11: }
andrewm@11: int key = i % 12;
andrewm@11: if(key == 1 || key == 3 || key == 6 || key == 8 || key == 10)
andrewm@11: touchFrames_[i].white = false;
andrewm@11: else
andrewm@11: touchFrames_[i].white = true;
andrewm@11: }
andrewm@11:
andrewm@11: // Generate a random frame of touch data on this key
andrewm@11: void TouchkeyEntropyGenerator::generateRandomFrame(int key) {
andrewm@11: touchFrames_[key].count = 1;
andrewm@11: touchFrames_[key].locH = (float)abs(rand()) / (float)RAND_MAX;
andrewm@11: touchFrames_[key].locs[0] = (float)abs(rand()) / (float)RAND_MAX;
andrewm@11: touchFrames_[key].sizes[0] = (float)abs(rand()) / (float)RAND_MAX;
andrewm@11: }