Added Loop Point support to sf::Music
This commit is contained in:
parent
6b3061d9c2
commit
93a2e9502d
4 changed files with 302 additions and 41 deletions
|
@ -49,6 +49,43 @@ class SFML_AUDIO_API Music : public SoundStream
|
|||
{
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Structure defining a time range using the template type
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
struct Span
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Default constructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
Span()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Initialization constructor
|
||||
///
|
||||
/// \param off Initial Offset
|
||||
/// \param len Initial Length
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
Span(T off, T len):
|
||||
offset(off),
|
||||
length(len)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
T offset; ///< The beginning offset of the time range
|
||||
T length; ///< The length of the time range
|
||||
};
|
||||
|
||||
// Define the relevant Span types
|
||||
typedef Span<Time> TimeSpan;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Default constructor
|
||||
///
|
||||
|
@ -134,6 +171,45 @@ public:
|
|||
////////////////////////////////////////////////////////////
|
||||
Time getDuration() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the positions of the of the sound's looping sequence
|
||||
///
|
||||
/// \return Loop Time position class.
|
||||
///
|
||||
/// \warning Since setLoopPoints() performs some adjustments on the
|
||||
/// provided values and rounds them to internal samples, a call to
|
||||
/// getLoopPoints() is not guaranteed to return the same times passed
|
||||
/// into a previous call to setLoopPoints(). However, it is guaranteed
|
||||
/// to return times that will map to the valid internal samples of
|
||||
/// this Music if they are later passed to setLoopPoints().
|
||||
///
|
||||
/// \see setLoopPoints
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
TimeSpan getLoopPoints() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Sets the beginning and end of the sound's looping sequence using sf::Time
|
||||
///
|
||||
/// Loop points allow one to specify a pair of positions such that, when the music
|
||||
/// is enabled for looping, it will seamlessly seek to the beginning whenever it
|
||||
/// encounters the end. Valid ranges for timePoints.offset and timePoints.length are
|
||||
/// [0, Dur) and (0, Dur-offset] respectively, where Dur is the value returned by getDuration().
|
||||
/// Note that the EOF "loop point" from the end to the beginning of the stream is still honored,
|
||||
/// in case the caller seeks to a point after the end of the loop range. This function can be
|
||||
/// safely called at any point after a stream is opened, and will be applied to a playing sound
|
||||
/// without affecting the current playing offset.
|
||||
///
|
||||
/// \warning Setting the loop points while the stream's status is Paused
|
||||
/// will set its status to Stopped. The playing offset will be unaffected.
|
||||
///
|
||||
/// \param timePoints The definition of the loop. Can be any time points within the sound's length
|
||||
///
|
||||
/// \see getLoopPoints
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void setLoopPoints(TimeSpan timePoints);
|
||||
|
||||
protected:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
@ -157,6 +233,18 @@ protected:
|
|||
////////////////////////////////////////////////////////////
|
||||
virtual void onSeek(Time timeOffset);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Change the current playing position in the stream source to the loop offset
|
||||
///
|
||||
/// This is called by the underlying SoundStream whenever it needs us to reset
|
||||
/// the seek position for a loop. We then determine whether we are looping on a
|
||||
/// loop point or the end-of-file, perform the seek, and return the new position.
|
||||
///
|
||||
/// \return The seek position after looping (or -1 if there's no loop)
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual Int64 onLoop();
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
@ -165,12 +253,33 @@ private:
|
|||
////////////////////////////////////////////////////////////
|
||||
void initialize();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Helper to convert an sf::Time to a sample position
|
||||
///
|
||||
/// \param position Time to convert to samples
|
||||
///
|
||||
/// \return The number of samples elapsed at the given time
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
Uint64 timeToSamples(Time position) const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Helper to convert a sample position to an sf::Time
|
||||
///
|
||||
/// \param position Sample count to convert to Time
|
||||
///
|
||||
/// \return The Time position of the given sample
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
Time samplesToTime(Uint64 samples) const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
InputSoundFile m_file; ///< The streamed music file
|
||||
std::vector<Int16> m_samples; ///< Temporary buffer of samples
|
||||
Mutex m_mutex; ///< Mutex protecting the data
|
||||
InputSoundFile m_file; ///< The streamed music file
|
||||
std::vector<Int16> m_samples; ///< Temporary buffer of samples
|
||||
Mutex m_mutex; ///< Mutex protecting the data
|
||||
Span<Uint64> m_loopSpan; ///< Loop Range Specifier
|
||||
};
|
||||
|
||||
} // namespace sf
|
||||
|
|
|
@ -180,6 +180,11 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
enum
|
||||
{
|
||||
NoLoop = -1 ///< "Invalid" endSeeks value, telling us to continue uninterrupted
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Default constructor
|
||||
///
|
||||
|
@ -234,6 +239,18 @@ protected:
|
|||
////////////////////////////////////////////////////////////
|
||||
virtual void onSeek(Time timeOffset) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Change the current playing position in the stream source to the beginning of the loop
|
||||
///
|
||||
/// This function can be overridden by derived classes to
|
||||
/// allow implementation of custom loop points. Otherwise,
|
||||
/// it just calls onSeek(Time::Zero) and returns 0.
|
||||
///
|
||||
/// \return The seek position after looping (or -1 if there's no loop)
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual Int64 onLoop();
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
@ -289,17 +306,17 @@ private:
|
|||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
Thread m_thread; ///< Thread running the background tasks
|
||||
mutable Mutex m_threadMutex; ///< Thread mutex
|
||||
Status m_threadStartState; ///< State the thread starts in (Playing, Paused, Stopped)
|
||||
bool m_isStreaming; ///< Streaming state (true = playing, false = stopped)
|
||||
unsigned int m_buffers[BufferCount]; ///< Sound buffers used to store temporary audio data
|
||||
unsigned int m_channelCount; ///< Number of channels (1 = mono, 2 = stereo, ...)
|
||||
unsigned int m_sampleRate; ///< Frequency (samples / second)
|
||||
Uint32 m_format; ///< Format of the internal sound buffers
|
||||
bool m_loop; ///< Loop flag (true to loop, false to play once)
|
||||
Uint64 m_samplesProcessed; ///< Number of buffers processed since beginning of the stream
|
||||
bool m_endBuffers[BufferCount]; ///< Each buffer is marked as "end buffer" or not, for proper duration calculation
|
||||
Thread m_thread; ///< Thread running the background tasks
|
||||
mutable Mutex m_threadMutex; ///< Thread mutex
|
||||
Status m_threadStartState; ///< State the thread starts in (Playing, Paused, Stopped)
|
||||
bool m_isStreaming; ///< Streaming state (true = playing, false = stopped)
|
||||
unsigned int m_buffers[BufferCount]; ///< Sound buffers used to store temporary audio data
|
||||
unsigned int m_channelCount; ///< Number of channels (1 = mono, 2 = stereo, ...)
|
||||
unsigned int m_sampleRate; ///< Frequency (samples / second)
|
||||
Uint32 m_format; ///< Format of the internal sound buffers
|
||||
bool m_loop; ///< Loop flag (true to loop, false to play once)
|
||||
Uint64 m_samplesProcessed; ///< Number of buffers processed since beginning of the stream
|
||||
Int64 m_bufferSeeks[BufferCount]; ///< If buffer is an "end buffer", holds next seek position, else NoLoop. For play offset calculation.
|
||||
};
|
||||
|
||||
} // namespace sf
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue