pianod2
multisource multiuser scriptable networked music player
fundamentals.h
Go to the documentation of this file.
1 
9 #pragma once
10 
11 #include <config.h>
12 
13 #include <ctime>
14 #include <cassert>
15 #include <cstring>
16 
17 #include <string>
18 #include <vector>
19 #include <stdexcept>
20 
25 #ifdef NDEBUG
26 #define kept_assert(x) (x)
27 #else
28 #define kept_assert(x) assert(x)
29 #endif
30 
31 // Works out to 2038 in 4-byte time, surely after the apocolypse for 8-byte
32 #define FAR_FUTURE ((time_t) (((time_t) 0x7fffffff) << ((sizeof (time_t) - 4) * 8)))
33 #define A_LONG_TIME (999999)
34 
35 enum class SearchRange {
36  EXHAUSTIVE,
37  SHALLOW,
38  KNOWN,
39  REQUESTABLE,
40  REQUESTS
41 };
42 inline bool forRequest (SearchRange range) {
43  return (range == SearchRange::REQUESTABLE || range == SearchRange::REQUESTS);
44 }
45 inline bool deepSearch (SearchRange range) {
46  return (range == SearchRange::EXHAUSTIVE ||
47  range == SearchRange::REQUESTABLE);
48 }
49 
50 
52 typedef struct AudioSettings_t {
54  std::string output_library;
56  std::string output_driver;
59  std::string output_device;
61  std::string output_id;
63  std::string output_options;
65  std::string output_server;
67  int volume;
69  float crossfade_level = 6.0f;
71  float crossfade_time = 0.0f;
73  float preroll_time = 5.0f;
75 
76 // This should go home to response once that's refactored
77 typedef enum server_status_t {
78  NO_REPLY = 0,
79  // Informational messages, occur anytime
80  // Playback status
81  V_PLAYING = 1, // 101-109 Playback status
82  V_PAUSED = 2,
83  V_STALLED = 3,
86  V_IDLE = 6,
90  // Selected stuff status
93  // Change notifications
96  V_PLAYLISTRATING_CHANGED = 23, // Also actions changed
100  V_YELL = 31, // Misc
104  // Queue randomization/Selection method stuff
106 
107  // Data fields, may occur spontaneously or in a data response
108  I_WELCOME = 100,
109  I_ID = 111, /* Song ID */ // 111-129 Playlist/artist/track field ids
110  I_ALBUM = 112,
111  I_ARTIST = 113,
112  I_SONG = 114,
113  I_PLAYLIST = 115,
114  I_RATING = 116,
115  I_INFO_URL = 117,
116  I_COVERART = 118,
117  I_GENRE = 119,
120  I_OWNER = 122,
121  I_SOURCE = 123,
122  I_NAME = 124,
123  I_YEAR = 125,
124  I_DURATION = 126,
125  I_ACTIONS = 127,
126  I_INFO = 132,
128  // pianod settings
129  I_VOLUME = 141,
135  I_ROOM = 148,
136  // Pandora communication settings
137  I_PROXY = 161,
139  // 163..169 available for reuse mid 2021.
144  I_PATHNAME = 174,
146 
149  I_OUTPUT_ID = 183,
151 
158 
161 
162  // Success/status messages, exactly one occurs (except for lists, as noted below)
163  // in response to commands.
164  S_OK = 200,
166  S_ANSWER_NO = 202,
167  S_DATA = 203, // For multi line items: Occurs 0 or more times, once before each listed group.
168  // For single line items: occurs once
169  S_DATA_END = 204, // Occurs exactly once after last list item
170  S_SIGNOFF = 205,
171  S_MATCH = 206,
172  S_ROUNDING = 207,
173  S_NOOP = 208,
174  S_PARTIAL = 209,
175  S_PENDING = 210,
176 
177  /* 300-399 are diagnostic messages, paralleling 400-499 error
178  messages. Diagnostics (possibly multiples) are followed by
179  single E_* error message, which concludes the response; the
180  individual diagnostics do not. */
181 
182  /* Errors for user failures, unauthorized actions, bad commands,
183  the connection is down, etc. Always in response to a command,
184  one per command. */
187  E_NAK = 402, // negative acknowledgement
188  E_DUPLICATE = 403,
189  E_NOTFOUND = 404,
192  E_INVALID = 407,
194  E_CONFLICT = 409,
196  E_QUOTA = 411,
198  E_UNSUPPORTED = 413, // Not allowed by media source/media player
199  E_RESOURCE = 414,
200  E_RANGE = 415,
202  E_WRONGTYPE = 417,
203  E_PERSISTENT = 418,
204  E_AMBIGUOUS = 419,
206  E_PARTIAL = 421,
207  E_VARIOUS = 422,
209  E_EXPRESSION = 424,
210  E_TIMEOUT = 425,
212  E_BAD_SCHEMA = 427,
213  /* Server failures, like out of memory, etc.
214  Not a response to a particular command, although a command may initiate what causes them */
220  E_BUG = 498,
222 
223  // Failures: Spontaneous problems, unrelated to a command.
224  F_FAILURE = 500,
227  F_SHUTDOWN = 503,
229  F_RESOURCE = 505,
230  F_PANDORA = 507,
233  F_EXCEPTION = 510,
237 
238  // Action messages. These are used to lookup text, in case we want to internationalize messaging.
239  A_SIGNED_IN = 1000,
240  A_SIGNED_OUT = 1001,
241  A_KICKED = 1002,
242  A_IMBECILE = 1003,
243  A_SKIPPED = 1010,
244  A_STOPPED = 1011,
245  A_PAUSED = 1012,
246  A_RESUMED = 1013,
248  A_MIX_ADDED = 1015,
250  A_REQUESTS = 1017,
251  A_RANDOMPLAY = 1018,
257  A_SOURCE_ADD = 1030,
263  A_SHUTDOWN = 1100,
264  FUTURE_CATEGORY = 3000
266 
267 inline bool isStatusChange (RESPONSE_CODE code) {
268  return code >= 1 && code < 100;
269 }
270 
271 inline bool isDataField (RESPONSE_CODE code) {
272  return code >= 100 && code < 200;
273 }
274 
275 inline bool isSuccess (RESPONSE_CODE code) {
276  return code >= 200 && code < 300;
277 }
278 
279 inline bool isCommandError (RESPONSE_CODE code) {
280  return code >= 400 && code < 500;
281 }
282 
283 inline bool isServerFailure (RESPONSE_CODE code) {
284  return code >= 500 && code < 600;
285 }
286 
287 inline bool isUserAction (RESPONSE_CODE code) {
288  return code >= 1000 && code < 2000;
289 }
290 
293 class CommandError final : public std::exception {
294 private:
296  char *detail = nullptr;
297 public:
299  CommandError (RESPONSE_CODE r, const char *message)
300  : _reason (r), detail (strdup (message)) { };
301  CommandError (RESPONSE_CODE r, const std::string &message)
302  : CommandError (r, message.c_str()) {};
303  CommandError (const CommandError &) = delete;
305  : _reason (from._reason), detail (from.detail) {
306  from.detail = nullptr;
307  }
310  *const_cast<RESPONSE_CODE *> (&_reason) = from._reason;
311  detail = from.detail;
312  from.detail = nullptr;
313  return *this;
314  }
315  inline RESPONSE_CODE reason (void) const { return _reason; };
316  virtual inline const char *what() const throw() override {
317  return detail ? detail : "";
318  };
319 };
320 
321 class InitializationException : public std::exception {
322  std::string _detail;
323  const char *detail = nullptr;
324 public:
326  InitializationException (const char *reason) : detail (reason) { };
327  InitializationException (const char *library, const char *reason) :
328  _detail (std::string (library) + ": " + reason) { detail = _detail.c_str(); };
329  virtual inline const char *what() const throw() override {
330  return detail ? detail : "No explanation";
331  };
332 };
333 
334 #define CMD_RANGE_SERVICE (1000)
335 #define CMD_RANGE_ENGINE (2000)
336 #define CMD_RANGE_USER (3000)
337 #define CMD_RANGE_MEDIA_MANAGER (4000)
338 #define CMD_RANGE_TUNING (5000)
339 #define CMD_RANGE_PANDORA (10000)
340 #define CMD_RANGE_TONEGENERATOR (11000)
341 #define CMD_RANGE_FILESYSTEM (12000)
342 #define CMD_RANGE_SPOTIFY (13000)
343 
344 const int CMD_INVALID = 0;
345 
346 
347 
348 using UserList = std::vector<const class User *>;
349 
351 class Ownership {
352 public:
355  enum class Type {
356  DISOWNED,
357  PRIVATE,
358  SHARED,
359  PUBLISHED,
360  PUBLIC
361  };
364  enum class Action {
365  SEE,
366  USE,
367  READ,
368  ALTER
369  };
370 
371  virtual bool isOwnedBy (const User *user) const = 0;
372  virtual bool hasPermission (const User *user, Action action) const = 0;
373 
374  inline bool isVisibleBy (const User *user) const {
375  return hasPermission (user, Action::SEE);
376  }
377  inline bool isUsableBy (const User *user) const {
378  return hasPermission (user, Action::USE);
379  }
380  inline bool isDecendableBy (const User *user) const {
381  return hasPermission (user, Action::READ);
382  }
383  inline bool isReadableBy (const User *user) const {
384  return hasPermission (user, Action::READ);
385  }
386  inline bool isEditableBy (const User *user) const {
387  return hasPermission (user, Action::ALTER);
388  }
389 };
390 
Exception for command execution problems.
Definition: fundamentals.h:293
const RESPONSE_CODE _reason
Definition: fundamentals.h:295
CommandError(RESPONSE_CODE r, const std::string &message)
Definition: fundamentals.h:301
virtual const char * what() const override
Definition: fundamentals.h:316
CommandError(RESPONSE_CODE r)
Definition: fundamentals.h:298
char * detail
Definition: fundamentals.h:296
RESPONSE_CODE reason(void) const
Definition: fundamentals.h:315
CommandError & operator=(const CommandError &)=delete
CommandError(CommandError &&from)
Definition: fundamentals.h:304
CommandError(const CommandError &)=delete
CommandError(RESPONSE_CODE r, const char *message)
Definition: fundamentals.h:299
Definition: fundamentals.h:321
InitializationException()
Definition: fundamentals.h:325
std::string _detail
Definition: fundamentals.h:322
InitializationException(const char *reason)
Definition: fundamentals.h:326
const char * detail
Definition: fundamentals.h:323
InitializationException(const char *library, const char *reason)
Definition: fundamentals.h:327
virtual const char * what() const override
Definition: fundamentals.h:329
Privilege management for media sources.
Definition: fundamentals.h:351
bool isDecendableBy(const User *user) const
Definition: fundamentals.h:380
bool isUsableBy(const User *user) const
Definition: fundamentals.h:377
virtual bool isOwnedBy(const User *user) const =0
Action
Access actions for an object.
Definition: fundamentals.h:364
@ READ
Read the item's contents/configuration.
@ SEE
View existence of item.
@ USE
Use the item to do something.
@ ALTER
Change the item.
bool isVisibleBy(const User *user) const
Definition: fundamentals.h:374
Type
Access levels for an object.
Definition: fundamentals.h:355
@ SHARED
Others can use this, but not derive from it.
@ PRIVATE
Visible by owner only.
@ PUBLISHED
Use and derive by anyone but only owner can manipulate.
@ PUBLIC
Anyone can manipulate this.
@ DISOWNED
Object has no owner.
bool isEditableBy(const User *user) const
Definition: fundamentals.h:386
virtual bool hasPermission(const User *user, Action action) const =0
bool isReadableBy(const User *user) const
Definition: fundamentals.h:383
Data about each user.
Definition: user.h:53
bool isServerFailure(RESPONSE_CODE code)
Definition: fundamentals.h:283
std::vector< const class User * > UserList
Definition: fundamentals.h:348
bool isDataField(RESPONSE_CODE code)
Definition: fundamentals.h:271
struct AudioSettings_t AudioSettings
Audio output device & driver parameters.
bool isSuccess(RESPONSE_CODE code)
Definition: fundamentals.h:275
enum server_status_t RESPONSE_CODE
SearchRange
Definition: fundamentals.h:35
@ SHALLOW
Get matching things, but not their contents.
@ REQUESTS
Search requestable sources for matches, but not their contents.
@ EXHAUSTIVE
Get everything matching, and all their contents.
@ REQUESTABLE
Search requestable sources for matches; return all items matching.
@ KNOWN
Get whatever we know about; don't perform external searches.
bool forRequest(SearchRange range)
Definition: fundamentals.h:42
bool isUserAction(RESPONSE_CODE code)
Definition: fundamentals.h:287
bool deepSearch(SearchRange range)
Definition: fundamentals.h:45
const int CMD_INVALID
Definition: fundamentals.h:344
server_status_t
Definition: fundamentals.h:77
@ S_PENDING
Request is pending but will succeed eventually.
Definition: fundamentals.h:175
@ E_RESOURCE
Inadequate memory, disk, etc.
Definition: fundamentals.h:199
@ A_SOURCE_ADD
Definition: fundamentals.h:257
@ V_STALLED
Definition: fundamentals.h:83
@ V_QUEUE_STOPPED
Definition: fundamentals.h:87
@ I_COVERART
Definition: fundamentals.h:116
@ A_IMBECILE
Definition: fundamentals.h:242
@ I_CHOICEEXPLANATION
Definition: fundamentals.h:119
@ E_TIMEOUT
Event did not occur within specified duration.
Definition: fundamentals.h:210
@ V_SOURCE_STATUS
Definition: fundamentals.h:103
@ V_PLAYLISTRATING_CHANGED
Definition: fundamentals.h:96
@ I_OUTPUT_DRIVER
Definition: fundamentals.h:147
@ F_PANDORA
Definition: fundamentals.h:230
@ E_TRANSFORM_FAILED
Definition: fundamentals.h:193
@ V_SELECTIONMETHOD
Definition: fundamentals.h:105
@ A_STOPPED
Definition: fundamentals.h:244
@ I_SERVICE_USER
Definition: fundamentals.h:140
@ F_PLAYER_EMPTY
Definition: fundamentals.h:225
@ E_NO_ASSOCIATION
Missing association data, i.e., song has no playlist.
Definition: fundamentals.h:208
@ F_RESOURCE
Definition: fundamentals.h:229
@ A_SIGNED_IN
Definition: fundamentals.h:239
@ I_CONTROLPROXY
Definition: fundamentals.h:138
@ E_BUG
A bug was encountered (likely hit default in a case statement.)
Definition: fundamentals.h:220
@ F_PERMISSION
Definition: fundamentals.h:232
@ E_METAPLAYLIST
Require a real playlist.
Definition: fundamentals.h:201
@ I_SOURCE
Definition: fundamentals.h:121
@ I_RATING
Definition: fundamentals.h:114
@ I_PROXY
Definition: fundamentals.h:137
@ A_CREATED_PLAYLIST
Definition: fundamentals.h:254
@ E_MEDIA_FAILURE
Source failure.
Definition: fundamentals.h:218
@ F_AUDIO_FAILURE
Definition: fundamentals.h:236
@ V_YELL
Definition: fundamentals.h:100
@ A_CHANGED_MIX
Definition: fundamentals.h:247
@ I_STATISTICS_SEQUENTIAL_FAILS
Definition: fundamentals.h:155
@ I_PLAYLIST
Definition: fundamentals.h:113
@ I_PATHNAME
Definition: fundamentals.h:144
@ I_STATISTICS_ATTEMPTS
Definition: fundamentals.h:152
@ E_BAD_COMMAND
Definition: fundamentals.h:185
@ E_DUPLICATE
Definition: fundamentals.h:188
@ E_QUOTA
Quota restriction encountered.
Definition: fundamentals.h:196
@ A_REQUEST_CLEAR
Definition: fundamentals.h:261
@ I_ARTIST
Definition: fundamentals.h:111
@ I_ATTACHED_THING
Transmit the attached thing instead of a response message.
Definition: fundamentals.h:159
@ V_TRACK_COMPLETE
Definition: fundamentals.h:84
@ A_SKIPPED
Definition: fundamentals.h:243
@ A_RANDOMPLAY
Definition: fundamentals.h:251
@ I_CACHE_MINIMUM
Definition: fundamentals.h:142
@ A_PAUSED
Definition: fundamentals.h:245
@ V_QUEUE_RANDOM
Definition: fundamentals.h:89
@ I_SONG
Definition: fundamentals.h:112
@ I_AUTOTUNE_MODE
Definition: fundamentals.h:132
@ A_SOURCE_REMOVE
Definition: fundamentals.h:259
@ I_OUTPUT_DEVICE
Definition: fundamentals.h:148
@ F_NETWORK_TIMEOUT
Definition: fundamentals.h:234
@ I_OUTPUT_SERVER
Definition: fundamentals.h:150
@ I_STATISTICS_DONATIONS
Definition: fundamentals.h:157
@ E_MEDIA_VALUE
Source doesn't accept a certain value.
Definition: fundamentals.h:216
@ A_MIX_ADDED
Definition: fundamentals.h:248
@ A_SELECTED_PLAYLIST
Definition: fundamentals.h:253
@ E_CREDENTIALS
Definition: fundamentals.h:191
@ S_DATA
Definition: fundamentals.h:167
@ F_NETWORK_FAILURE
Definition: fundamentals.h:226
@ I_SELECTION_ALGORITHM
Definition: fundamentals.h:145
@ V_QUEUE_CHANGED
Definition: fundamentals.h:99
@ I_GENRE
Definition: fundamentals.h:117
@ V_QUEUE_REQUEST
Definition: fundamentals.h:88
@ V_IDLE
Definition: fundamentals.h:86
@ A_RENAMED_PLAYLIST
Definition: fundamentals.h:255
@ I_HISTORYSIZE
Definition: fundamentals.h:130
@ E_PLAYLIST_REQUIRED
Song must have a playlist for this action.
Definition: fundamentals.h:211
@ V_BETWEEN_TRACKS
Definition: fundamentals.h:85
@ E_EXPRESSION
Invalid expression.
Definition: fundamentals.h:209
@ A_MIX_REMOVED
Definition: fundamentals.h:249
@ E_INVALID
Definition: fundamentals.h:192
@ F_SHUTDOWN
Definition: fundamentals.h:227
@ V_SONGRATING_CHANGED
Definition: fundamentals.h:98
@ I_AUDIOQUALITY
Definition: fundamentals.h:131
@ I_INFO_URL
Definition: fundamentals.h:115
@ E_VARIOUS
All failures, but a varity of reasons.
Definition: fundamentals.h:207
@ E_MEDIA_MANAGER
Can't do that on media manager.
Definition: fundamentals.h:217
@ S_NOOP
Nothing to do; default success.
Definition: fundamentals.h:173
@ A_REQUEST_ADD
Definition: fundamentals.h:260
@ V_SELECTEDPLAYLIST
Definition: fundamentals.h:92
@ I_OUTPUT_ID
Definition: fundamentals.h:149
@ I_PAUSE_TIMEOUT
Definition: fundamentals.h:133
@ I_PLAYLISTRATING
Definition: fundamentals.h:118
@ E_WRONG_STATE
Definition: fundamentals.h:190
@ I_ID
Definition: fundamentals.h:109
@ I_CACHE_MAXIMUM
Definition: fundamentals.h:143
@ F_CANNOT_OUTPUT
Definition: fundamentals.h:235
@ E_CONFLICT
Definition: fundamentals.h:194
@ I_NAME
Definition: fundamentals.h:122
@ I_STATISTICS_REPLACEMENTS
Definition: fundamentals.h:156
@ F_AUTHENTICATION
Definition: fundamentals.h:228
@ E_NAK
Definition: fundamentals.h:187
@ NO_REPLY
Do not transmit any reply.
Definition: fundamentals.h:78
@ I_USER_PRIVILEGES
Definition: fundamentals.h:127
@ E_UNSUPPORTED
Definition: fundamentals.h:198
@ A_REQUESTS
Definition: fundamentals.h:250
@ E_BAD_SCHEMA
JSON command is structured incorrectly.
Definition: fundamentals.h:212
@ E_WRONGTYPE
Operand was of wrong type.
Definition: fundamentals.h:202
@ I_STATISTICS_PLAYS
Definition: fundamentals.h:153
@ E_NOT_IMPLEMENTED
Definition: fundamentals.h:221
@ S_MATCH
Matches for criteria were found.
Definition: fundamentals.h:171
@ V_PAUSED
Definition: fundamentals.h:82
@ F_EXCEPTION
Definition: fundamentals.h:233
@ V_SERVER_STATUS
Definition: fundamentals.h:102
@ S_SIGNOFF
Definition: fundamentals.h:170
@ E_TYPE_DISALLOWED
Type not allowed with expression.
Definition: fundamentals.h:205
@ S_ANSWER_NO
Definition: fundamentals.h:166
@ E_RANGE
Request puts value out of range.
Definition: fundamentals.h:200
@ I_INFO
Definition: fundamentals.h:126
@ A_SOURCE_BORROW
Definition: fundamentals.h:258
@ S_PARTIAL
Command partially succeeded, but there were failures.
Definition: fundamentals.h:174
@ V_USERACTION
Definition: fundamentals.h:101
@ E_NOTFOUND
Definition: fundamentals.h:189
@ A_RESUMED
Definition: fundamentals.h:246
@ A_KICKED
Definition: fundamentals.h:241
@ V_SELECTEDSOURCE
Definition: fundamentals.h:91
@ I_STATISTICS_FAILURES
Definition: fundamentals.h:154
@ V_PLAYING
Definition: fundamentals.h:81
@ V_MIX_CHANGED
Definition: fundamentals.h:94
@ A_SIGNED_OUT
Definition: fundamentals.h:240
@ I_DURATION
Definition: fundamentals.h:124
@ E_MEDIA_TRANSIENT
Transient playlist.
Definition: fundamentals.h:219
@ S_ROUNDING
Success but with rounding.
Definition: fundamentals.h:172
@ S_ANSWER_YES
Definition: fundamentals.h:165
@ E_LOGINREQUIRED
Command/feature requires user be logged in.
Definition: fundamentals.h:197
@ I_ATTACHED_SONG
Transmit the essentials of the attached song (but not ratings, etc).
Definition: fundamentals.h:160
@ A_REQUEST_CANCEL
Definition: fundamentals.h:262
@ S_OK
Definition: fundamentals.h:164
@ E_UNAUTHORIZED
Definition: fundamentals.h:186
@ I_PLAYLIST_TIMEOUT
Definition: fundamentals.h:134
@ A_DELETED_PLAYLIST
Definition: fundamentals.h:256
@ F_FAILURE
Definition: fundamentals.h:224
@ I_ROOM
Definition: fundamentals.h:135
@ E_MEDIA_ACTION
Source doesn't do that.
Definition: fundamentals.h:215
@ V_SOURCES_CHANGED
Definition: fundamentals.h:97
@ E_REQUESTPENDING
Request couldn't be completed now, we'll try again later.
Definition: fundamentals.h:195
@ E_AMBIGUOUS
Ambiguous expression.
Definition: fundamentals.h:204
@ FUTURE_CATEGORY
Definition: fundamentals.h:264
@ E_PERSISTENT
Require persistent data.
Definition: fundamentals.h:203
@ I_WELCOME
Definition: fundamentals.h:108
@ I_OWNER
Definition: fundamentals.h:120
@ I_VOLUME
Definition: fundamentals.h:129
@ I_YEAR
Definition: fundamentals.h:123
@ A_SHUTDOWN
Definition: fundamentals.h:263
@ S_DATA_END
Definition: fundamentals.h:169
@ E_PARTIAL
Partial failure, but a portion succeeded.
Definition: fundamentals.h:206
@ I_ALBUM
Definition: fundamentals.h:110
@ A_ADJUSTAUDIO
Definition: fundamentals.h:252
@ I_SERVICE_PASSWORD
Definition: fundamentals.h:141
@ V_PLAYLISTS_CHANGED
Definition: fundamentals.h:95
@ I_ACTIONS
Definition: fundamentals.h:125
@ F_INCOMPLETE
Definition: fundamentals.h:231
bool isCommandError(RESPONSE_CODE code)
Definition: fundamentals.h:279
bool isStatusChange(RESPONSE_CODE code)
Definition: fundamentals.h:267
Audio output device & driver parameters.
Definition: fundamentals.h:52
float crossfade_level
Definition: fundamentals.h:69
std::string output_server
For output to network services such as IceCast, the target server info.
Definition: fundamentals.h:65
std::string output_driver
Specify output driver, for use by audio output library.
Definition: fundamentals.h:56
std::string output_id
For use by audio output library. Numeric but stored as string to accommodate unset value.
Definition: fundamentals.h:61
std::string output_device
Specify a specific output device, if there are multiple instances or channels.
Definition: fundamentals.h:59
std::string output_options
For use by audio output library.
Definition: fundamentals.h:63
std::string output_library
Specify which output library for pianod to use. If empty, uses default.
Definition: fundamentals.h:54
float preroll_time
Definition: fundamentals.h:73
float crossfade_time
Definition: fundamentals.h:71
int volume
Initial volume level, managed by pianod.
Definition: fundamentals.h:67