3 |
* LinuxSampler - modular, streaming capable sampler * |
* LinuxSampler - modular, streaming capable sampler * |
4 |
* * |
* * |
5 |
* Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * |
* Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * |
6 |
* Copyright (C) 2005 Christian Schoenebeck * |
* Copyright (C) 2005 - 2007 Christian Schoenebeck * |
7 |
* * |
* * |
8 |
* This program is free software; you can redistribute it and/or modify * |
* This program is free software; you can redistribute it and/or modify * |
9 |
* it under the terms of the GNU General Public License as published by * |
* it under the terms of the GNU General Public License as published by * |
26 |
|
|
27 |
#include "../../common/global.h" |
#include "../../common/global.h" |
28 |
|
|
|
#if DEBUG_HEADERS |
|
|
# warning Stream.h included |
|
|
#endif // DEBUG_HEADERS |
|
|
|
|
29 |
#include <gig.h> |
#include <gig.h> |
30 |
|
|
31 |
#include "../../common/RingBuffer.h" |
#include "../../common/RingBuffer.h" |
32 |
|
|
33 |
namespace LinuxSampler { namespace gig { |
namespace LinuxSampler { namespace gig { |
34 |
|
|
35 |
|
/** @brief Buffered Disk Stream |
36 |
|
* |
37 |
|
* This encapsulation of a disk stream uses a ring buffer to allow |
38 |
|
* thread safe refilling the stream's buffer with one thread (disk |
39 |
|
* thread) and actual use / extraction of the audio data from the |
40 |
|
* stream's buffer with another thread (audio thread). |
41 |
|
*/ |
42 |
class Stream { |
class Stream { |
43 |
public: |
public: |
44 |
// Member Types |
// Member Types |
45 |
typedef uint32_t OrderID_t; |
typedef uint32_t OrderID_t; |
46 |
typedef uint32_t Handle; ///< unique identifier of a relationship between one stream and a consumer (Voice) |
typedef uint32_t Handle; ///< unique identifier of a relationship between one stream and a consumer (Voice) |
47 |
|
enum { INVALID_HANDLE = 0 }; |
48 |
enum state_t { ///< streams go through severe cyclic state transition (unused->active->end->unused->...) |
enum state_t { ///< streams go through severe cyclic state transition (unused->active->end->unused->...) |
49 |
state_unused, ///< stream is not in use, thus can still be launched |
state_unused, ///< stream is not in use, thus can still be launched |
50 |
state_active, ///< stream provides data in it's buffer to be read and hasn't reached the end yet (this is the usual case) |
state_active, ///< stream provides data in it's buffer to be read and hasn't reached the end yet (this is the usual case) |
64 |
void WriteSilence(unsigned long SilenceSampleWords); |
void WriteSilence(unsigned long SilenceSampleWords); |
65 |
|
|
66 |
inline int GetReadSpace() { |
inline int GetReadSpace() { |
67 |
return (pRingBuffer && State != state_unused) ? pRingBuffer->read_space() : 0; |
return (pRingBuffer && State != state_unused) ? pRingBuffer->read_space() / BytesPerSample : 0; |
68 |
} |
} |
69 |
|
|
70 |
inline int GetWriteSpace() { |
inline int GetWriteSpace() { |
72 |
} |
} |
73 |
|
|
74 |
inline int GetWriteSpaceToEnd() { |
inline int GetWriteSpaceToEnd() { |
75 |
return (pRingBuffer && State == state_active) ? pRingBuffer->write_space_to_end_with_wrap() : 0; |
return (pRingBuffer && State == state_active) ? pRingBuffer->write_space_to_end_with_wrap() / BytesPerSample : 0; |
76 |
} |
} |
77 |
|
|
78 |
// adjusts the write space to avoid buffer boundaries which would lead to the wrap space |
// adjusts the write space to avoid buffer boundaries which would lead to the wrap space |
79 |
// within the buffer (needed for interpolation) getting filled only partially |
// within the buffer (needed for interpolation) getting filled only partially |
80 |
// for more infos see the docs in ringbuffer.h at adjust_write_space_to_avoid_boundary() |
// for more infos see the docs in ringbuffer.h at adjust_write_space_to_avoid_boundary() |
81 |
inline int AdjustWriteSpaceToAvoidBoundary(int cnt, int capped_cnt) { |
inline int AdjustWriteSpaceToAvoidBoundary(int cnt, int capped_cnt) { |
82 |
return pRingBuffer->adjust_write_space_to_avoid_boundary(cnt, capped_cnt); |
return pRingBuffer->adjust_write_space_to_avoid_boundary(cnt * BytesPerSample, capped_cnt * BytesPerSample) / BytesPerSample; |
|
} |
|
|
|
|
|
inline sample_t* GetReadPointer() { |
|
|
return pRingBuffer->get_read_ptr(); |
|
83 |
} |
} |
84 |
|
|
85 |
// gets the current read_ptr within the ringbuffer |
// gets the current read_ptr within the ringbuffer |
86 |
inline sample_t* GetReadPtr(void) { |
inline uint8_t* GetReadPtr(void) { |
87 |
return pRingBuffer->get_read_ptr(); |
return pRingBuffer->get_read_ptr(); |
88 |
} |
} |
89 |
|
|
90 |
inline void IncrementReadPos(uint Count) { |
inline void IncrementReadPos(uint Count) { |
91 |
|
Count *= BytesPerSample; |
92 |
uint leftspace = pRingBuffer->read_space(); |
uint leftspace = pRingBuffer->read_space(); |
93 |
pRingBuffer->increment_read_ptr(Min(Count, leftspace)); |
pRingBuffer->increment_read_ptr(Min(Count, leftspace)); |
94 |
if (State == state_end && Count >= leftspace) { |
if (State == state_end && Count >= leftspace) { |
100 |
inline static uint GetUnusedStreams() { return UnusedStreams; } |
inline static uint GetUnusedStreams() { return UnusedStreams; } |
101 |
protected: |
protected: |
102 |
// Methods |
// Methods |
103 |
void Launch(Stream::Handle hStream, reference_t* pExportReference, ::gig::Sample* pSample, unsigned long SampleOffset, bool DoLoop); |
void Launch(Stream::Handle hStream, reference_t* pExportReference, ::gig::DimensionRegion* pDimRgn, unsigned long SampleOffset, bool DoLoop); |
104 |
inline void Kill() { pExportReference = NULL; Reset(); } ///< Will be called by disk thread after a 'deletion' command from the audio thread (within the voice class) |
inline void Kill() { pExportReference = NULL; Reset(); } ///< Will be called by disk thread after a 'deletion' command from the audio thread (within the voice class) |
105 |
inline Stream::Handle GetHandle() { return hThis; } |
inline Stream::Handle GetHandle() { return hThis; } |
106 |
inline Stream::state_t GetState() { return State; } |
inline Stream::state_t GetState() { return State; } |
111 |
state_t State; |
state_t State; |
112 |
Stream::Handle hThis; |
Stream::Handle hThis; |
113 |
unsigned long SampleOffset; |
unsigned long SampleOffset; |
114 |
::gig::Sample* pSample; |
::gig::DimensionRegion* pDimRgn; |
115 |
::gig::playback_state_t PlaybackState; |
::gig::playback_state_t PlaybackState; |
116 |
RingBuffer<sample_t>* pRingBuffer; |
RingBuffer<uint8_t,false>* pRingBuffer; |
117 |
bool DoLoop; |
bool DoLoop; |
118 |
::gig::buffer_t* pDecompressionBuffer; |
::gig::buffer_t* pDecompressionBuffer; |
119 |
|
int BytesPerSample; |
120 |
|
|
121 |
// Static Attributes |
// Static Attributes |
122 |
static uint UnusedStreams; //< Reflects how many stream objects of all stream instances are currently not in use. |
static uint UnusedStreams; //< Reflects how many stream objects of all stream instances are currently not in use. |
125 |
// Methods |
// Methods |
126 |
inline void Reset() { |
inline void Reset() { |
127 |
SampleOffset = 0; |
SampleOffset = 0; |
128 |
pSample = NULL; |
pDimRgn = NULL; |
129 |
PlaybackState.position = 0; |
PlaybackState.position = 0; |
130 |
PlaybackState.reverse = false; |
PlaybackState.reverse = false; |
131 |
hThis = 0; |
hThis = 0; |