/* Copyright 2016, Ableton AG, Berlin. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * If you would like to incorporate Link into a proprietary software application, * please contact . */ #include "AudioPlatform.hpp" #include #include #include #include #include #include #if defined(LINK_PLATFORM_UNIX) #include #endif namespace { struct State { std::atomic running; ableton::Link link; ableton::linkaudio::AudioPlatform audioPlatform; State() : running(true) , link(120.) , audioPlatform(link) { } }; void disableBufferedInput() { #if defined(LINK_PLATFORM_UNIX) termios t; tcgetattr(STDIN_FILENO, &t); t.c_lflag &= static_cast(~ICANON); tcsetattr(STDIN_FILENO, TCSANOW, &t); #endif } void enableBufferedInput() { #if defined(LINK_PLATFORM_UNIX) termios t; tcgetattr(STDIN_FILENO, &t); t.c_lflag |= ICANON; tcsetattr(STDIN_FILENO, TCSANOW, &t); #endif } void clearLine() { std::cout << " \r" << std::flush; std::cout.fill(' '); } void printHelp() { std::cout << std::endl << " < L I N K H U T >" << std::endl << std::endl; std::cout << "usage:" << std::endl; std::cout << " enable / disable Link: a" << std::endl; std::cout << " start / stop: space" << std::endl; std::cout << " decrease / increase tempo: w / e" << std::endl; std::cout << " decrease / increase quantum: r / t" << std::endl; std::cout << " enable / disable start stop sync: s" << std::endl; std::cout << " quit: q" << std::endl << std::endl; } void printStateHeader() { std::cout << "enabled | num peers | quantum | start stop sync | tempo | beats | metro" << std::endl; } void printState(const std::chrono::microseconds time, const ableton::Link::SessionState sessionState, const bool linkEnabled, const std::size_t numPeers, const double quantum, const bool startStopSyncOn) { using namespace std; const auto enabled = linkEnabled ? "yes" : "no"; const auto beats = sessionState.beatAtTime(time, quantum); const auto phase = sessionState.phaseAtTime(time, quantum); const auto startStop = startStopSyncOn ? "yes" : "no"; const auto isPlaying = sessionState.isPlaying() ? "[playing]" : "[stopped]"; cout << defaultfloat << left << setw(7) << enabled << " | " << setw(9) << numPeers << " | " << setw(7) << quantum << " | " << setw(3) << startStop << " " << setw(11) << isPlaying << " | " << fixed << setw(7) << sessionState.tempo() << " | " << fixed << setprecision(2) << setw(7) << beats << " | "; for (int i = 0; i < ceil(quantum); ++i) { if (i < phase) { std::cout << 'X'; } else { std::cout << 'O'; } } clearLine(); } void input(State& state) { char in; for (;;) { #if defined(LINK_PLATFORM_WINDOWS) HANDLE stdinHandle = GetStdHandle(STD_INPUT_HANDLE); DWORD numCharsRead; INPUT_RECORD inputRecord; do { ReadConsoleInput(stdinHandle, &inputRecord, 1, &numCharsRead); } while ((inputRecord.EventType != KEY_EVENT) || inputRecord.Event.KeyEvent.bKeyDown); in = inputRecord.Event.KeyEvent.uChar.AsciiChar; #elif defined(LINK_PLATFORM_UNIX) in = static_cast(std::cin.get()); #endif const auto tempo = state.link.captureAppSessionState().tempo(); auto& engine = state.audioPlatform.mEngine; switch (in) { case 'q': state.running = false; clearLine(); return; case 'a': state.link.enable(!state.link.isEnabled()); break; case 'w': engine.setTempo(tempo - 1); break; case 'e': engine.setTempo(tempo + 1); break; case 'r': engine.setQuantum(engine.quantum() - 1); break; case 't': engine.setQuantum(std::max(1., engine.quantum() + 1)); break; case 's': engine.setStartStopSyncEnabled(!engine.isStartStopSyncEnabled()); break; case ' ': if (engine.isPlaying()) { engine.stopPlaying(); } else { engine.startPlaying(); } break; } } } } // namespace int main(int, char**) { State state; printHelp(); printStateHeader(); std::thread thread(input, std::ref(state)); disableBufferedInput(); while (state.running) { const auto time = state.link.clock().micros(); auto sessionState = state.link.captureAppSessionState(); printState(time, sessionState, state.link.isEnabled(), state.link.numPeers(), state.audioPlatform.mEngine.quantum(), state.audioPlatform.mEngine.isStartStopSyncEnabled()); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } enableBufferedInput(); thread.join(); return 0; }