forked from Sneeds-Feed-and-Seed/sneedacity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPlaybackSchedule.h
167 lines (130 loc) · 5.67 KB
/
PlaybackSchedule.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/**********************************************************************
Sneedacity: A Digital Audio Editor
PlaybackSchedule.h
Paul Licameli split from AudioIOBase.h
**********************************************************************/
#ifndef __SNEEDACITY_PLAYBACK_SCHEDULE__
#define __SNEEDACITY_PLAYBACK_SCHEDULE__
#include <atomic>
#include <vector>
struct AudioIOStartStreamOptions;
class BoundedEnvelope;
using PRCrossfadeData = std::vector< std::vector < float > >;
struct RecordingSchedule {
double mPreRoll{};
double mLatencyCorrection{}; // negative value usually
double mDuration{};
PRCrossfadeData mCrossfadeData;
// These are initialized by the main thread, then updated
// only by the thread calling FillBuffers:
double mPosition{};
bool mLatencyCorrected{};
double TotalCorrection() const { return mLatencyCorrection - mPreRoll; }
double ToConsume() const;
double Consumed() const;
double ToDiscard() const;
};
struct SNEEDACITY_DLL_API PlaybackSchedule {
/// Playback starts at offset of mT0, which is measured in seconds.
double mT0;
/// Playback ends at offset of mT1, which is measured in seconds. Note that mT1 may be less than mT0 during scrubbing.
double mT1;
/// Current track time position during playback, in seconds.
/// Initialized by the main thread but updated by worker threads during
/// playback or recording, and periodically reread by the main thread for
/// purposes such as display update.
std::atomic<double> mTime;
/// Accumulated real time (not track position), starting at zero (unlike
/// mTime), and wrapping back to zero each time around looping play.
/// Thus, it is the length in real seconds between mT0 and mTime.
double mWarpedTime;
/// Real length to be played (if looping, for each pass) after warping via a
/// time track, computed just once when starting the stream.
/// Length in real seconds between mT0 and mT1. Always positive.
double mWarpedLength;
// mWarpedTime and mWarpedLength are irrelevant when scrubbing,
// else they are used in updating mTime,
// and when not scrubbing or playing looped, mTime is also used
// in the test for termination of playback.
// with ComputeWarpedLength, it is now possible the calculate the warped length with 100% accuracy
// (ignoring accumulated rounding errors during playback) which fixes the 'missing sound at the end' bug
const BoundedEnvelope *mEnvelope;
volatile enum {
PLAY_STRAIGHT,
PLAY_LOOPED,
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
PLAY_SCRUB,
PLAY_AT_SPEED, // a version of PLAY_SCRUB.
PLAY_KEYBOARD_SCRUB,
#endif
} mPlayMode { PLAY_STRAIGHT };
double mCutPreviewGapStart;
double mCutPreviewGapLen;
void Init(
double t0, double t1,
const AudioIOStartStreamOptions &options,
const RecordingSchedule *pRecordingSchedule );
/** \brief True if the end time is before the start time */
bool ReversedTime() const
{
return mT1 < mT0;
}
/** \brief Get current track time value, unadjusted
*
* Returns a time in seconds.
*/
double GetTrackTime() const
{ return mTime.load(std::memory_order_relaxed); }
/** \brief Set current track time value, unadjusted
*/
void SetTrackTime( double time )
{ mTime.store(time, std::memory_order_relaxed); }
/** \brief Clamps argument to be between mT0 and mT1
*
* Returns the bound if the value is out of bounds; does not wrap.
* Returns a time in seconds.
*/
double ClampTrackTime( double trackTime ) const;
/** \brief Clamps mTime to be between mT0 and mT1
*
* Returns the bound if the value is out of bounds; does not wrap.
* Returns a time in seconds.
*/
double LimitTrackTime() const;
/** \brief Normalizes mTime, clamping it and handling gaps from cut preview.
*
* Clamps the time (unless scrubbing), and skips over the cut section.
* Returns a time in seconds.
*/
double NormalizeTrackTime() const;
void ResetMode() { mPlayMode = PLAY_STRAIGHT; }
bool PlayingStraight() const { return mPlayMode == PLAY_STRAIGHT; }
bool Looping() const { return mPlayMode == PLAY_LOOPED; }
bool Scrubbing() const { return mPlayMode == PLAY_SCRUB || mPlayMode == PLAY_KEYBOARD_SCRUB; }
bool PlayingAtSpeed() const { return mPlayMode == PLAY_AT_SPEED; }
bool Interactive() const { return Scrubbing() || PlayingAtSpeed(); }
// Returns true if a loop pass, or the sole pass of straight play,
// is completed at the current value of mTime
bool PassIsComplete() const;
// Returns true if time equals t1 or is on opposite side of t1, to t0
bool Overruns( double trackTime ) const;
// Compute the NEW track time for the given one and a real duration,
// taking into account whether the schedule is for looping
double AdvancedTrackTime(
double trackTime, double realElapsed, double speed) const;
// Use the function above in the callback after consuming samples from the
// playback ring buffers, during usual straight or looping play
void TrackTimeUpdate(double realElapsed);
// Convert time between mT0 and argument to real duration, according to
// time track if one is given; result is always nonnegative
double RealDuration(double trackTime1) const;
// How much real time left?
double RealTimeRemaining() const;
// Advance the real time position
void RealTimeAdvance( double increment );
// Determine starting duration within the first pass -- sometimes not
// zero
void RealTimeInit( double trackTime );
void RealTimeRestart();
};
#endif