1 /* Copyright 2016, Ableton AG, Berlin. All rights reserved. 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 2 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 * 16 * If you would like to incorporate Link into a proprietary software application, 17 * please contact <link-devs@ableton.com>. 18 */ 19 20 #pragma once 21 22 #include <ableton/discovery/NetworkByteStreamSerializable.hpp> 23 #include <ableton/link/Beats.hpp> 24 #include <ableton/link/Tempo.hpp> 25 #include <cmath> 26 #include <cstdint> 27 #include <tuple> 28 29 namespace ableton 30 { 31 namespace link 32 { 33 34 // A tuple of (tempo, beats, time), with integral units 35 // based on microseconds. This type establishes a bijection between 36 // beats and wall time, given a valid tempo. It also serves as a 37 // payload entry. 38 39 struct Timeline 40 { 41 static const std::int32_t key = 'tmln'; 42 static_assert(key == 0x746d6c6e, "Unexpected byte order"); 43 toBeatsableton::link::Timeline44 Beats toBeats(const std::chrono::microseconds time) const 45 { 46 return beatOrigin + tempo.microsToBeats(time - timeOrigin); 47 } 48 fromBeatsableton::link::Timeline49 std::chrono::microseconds fromBeats(const Beats beats) const 50 { 51 return timeOrigin + tempo.beatsToMicros(beats - beatOrigin); 52 } 53 operator ==(const Timeline & lhs,const Timeline & rhs)54 friend bool operator==(const Timeline& lhs, const Timeline& rhs) 55 { 56 return std::tie(lhs.tempo, lhs.beatOrigin, lhs.timeOrigin) 57 == std::tie(rhs.tempo, rhs.beatOrigin, rhs.timeOrigin); 58 } 59 operator !=(const Timeline & lhs,const Timeline & rhs)60 friend bool operator!=(const Timeline& lhs, const Timeline& rhs) 61 { 62 return !(lhs == rhs); 63 } 64 65 // Model the NetworkByteStreamSerializable concept sizeInByteStream(const Timeline & tl)66 friend std::uint32_t sizeInByteStream(const Timeline& tl) 67 { 68 return discovery::sizeInByteStream(std::tie(tl.tempo, tl.beatOrigin, tl.timeOrigin)); 69 } 70 71 template <typename It> toNetworkByteStream(const Timeline & tl,It out)72 friend It toNetworkByteStream(const Timeline& tl, It out) 73 { 74 return discovery::toNetworkByteStream( 75 std::tie(tl.tempo, tl.beatOrigin, tl.timeOrigin), std::move(out)); 76 } 77 78 template <typename It> fromNetworkByteStreamableton::link::Timeline79 static std::pair<Timeline, It> fromNetworkByteStream(It begin, It end) 80 { 81 using namespace std; 82 using namespace discovery; 83 Timeline timeline; 84 auto result = 85 Deserialize<tuple<Tempo, Beats, chrono::microseconds>>::fromNetworkByteStream( 86 move(begin), move(end)); 87 tie(timeline.tempo, timeline.beatOrigin, timeline.timeOrigin) = move(result.first); 88 return make_pair(move(timeline), move(result.second)); 89 } 90 91 Tempo tempo; 92 Beats beatOrigin; 93 std::chrono::microseconds timeOrigin; 94 }; 95 96 } // namespace link 97 } // namespace ableton 98