1 /* Copyright 2017, 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 <chrono>
25 #include <tuple>
26 
27 namespace ableton
28 {
29 namespace link
30 {
31 
32 // A tuple of (isPlaying, time) that represents the playing state
33 // with an according timestamp in microseconds. It also serves as a
34 // payload entry.
35 
36 struct StartStopState
37 {
38   static const std::int32_t key = 'stst';
39   static_assert(key == 0x73747374, "Unexpected byte order");
40 
41   using StartStopStateTuple = std::tuple<bool, Beats, std::chrono::microseconds>;
42 
43   StartStopState() = default;
44 
StartStopStateableton::link::StartStopState45   StartStopState(
46     const bool aIsPlaying, const Beats aBeats, const std::chrono::microseconds aTimestamp)
47     : isPlaying(aIsPlaying)
48     , beats(aBeats)
49     , timestamp(aTimestamp)
50   {
51   }
52 
operator ==(const StartStopState & lhs,const StartStopState & rhs)53   friend bool operator==(const StartStopState& lhs, const StartStopState& rhs)
54   {
55     return std::tie(lhs.isPlaying, lhs.beats, lhs.timestamp)
56            == std::tie(rhs.isPlaying, rhs.beats, rhs.timestamp);
57   }
58 
operator !=(const StartStopState & lhs,const StartStopState & rhs)59   friend bool operator!=(const StartStopState& lhs, const StartStopState& rhs)
60   {
61     return !(lhs == rhs);
62   }
63 
64   // Model the NetworkByteStreamSerializable concept
sizeInByteStream(const StartStopState & state)65   friend std::uint32_t sizeInByteStream(const StartStopState& state)
66   {
67     return discovery::sizeInByteStream(state.asTuple());
68   }
69 
70   template <typename It>
toNetworkByteStream(const StartStopState & state,It out)71   friend It toNetworkByteStream(const StartStopState& state, It out)
72   {
73     return discovery::toNetworkByteStream(state.asTuple(), std::move(out));
74   }
75 
76   template <typename It>
fromNetworkByteStreamableton::link::StartStopState77   static std::pair<StartStopState, It> fromNetworkByteStream(It begin, It end)
78   {
79     using namespace std;
80     using namespace discovery;
81     auto result =
82       Deserialize<StartStopStateTuple>::fromNetworkByteStream(move(begin), move(end));
83     auto state =
84       StartStopState{get<0>(result.first), get<1>(result.first), get<2>(result.first)};
85     return make_pair(move(state), move(result.second));
86   }
87 
88   bool isPlaying{false};
89   Beats beats{0.};
90   std::chrono::microseconds timestamp{0};
91 
92 private:
asTupleableton::link::StartStopState93   StartStopStateTuple asTuple() const
94   {
95     return std::make_tuple(isPlaying, beats, timestamp);
96   }
97 };
98 
99 struct ApiStartStopState
100 {
101   ApiStartStopState() = default;
102 
ApiStartStopStateableton::link::ApiStartStopState103   ApiStartStopState(const bool aIsPlaying, const std::chrono::microseconds aTime)
104     : isPlaying(aIsPlaying)
105     , time(aTime)
106   {
107   }
108 
operator ==(const ApiStartStopState & lhs,const ApiStartStopState & rhs)109   friend bool operator==(const ApiStartStopState& lhs, const ApiStartStopState& rhs)
110   {
111     return std::tie(lhs.isPlaying, lhs.time) == std::tie(rhs.isPlaying, rhs.time);
112   }
113 
operator !=(const ApiStartStopState & lhs,const ApiStartStopState & rhs)114   friend bool operator!=(const ApiStartStopState& lhs, const ApiStartStopState& rhs)
115   {
116     return !(lhs == rhs);
117   }
118 
119   bool isPlaying{false};
120   std::chrono::microseconds time{0};
121 };
122 } // namespace link
123 } // namespace ableton
124