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, 2006 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 * |
30 |
# warning Stream.h included |
# warning Stream.h included |
31 |
#endif // DEBUG_HEADERS |
#endif // DEBUG_HEADERS |
32 |
|
|
33 |
|
#include <gig.h> |
34 |
|
|
35 |
#include "../../common/RingBuffer.h" |
#include "../../common/RingBuffer.h" |
|
#include "../../lib/fileloader/libgig/gig.h" |
|
36 |
|
|
37 |
namespace LinuxSampler { namespace gig { |
namespace LinuxSampler { namespace gig { |
38 |
|
|
39 |
|
/** @brief Buffered Disk Stream |
40 |
|
* |
41 |
|
* This encapsulation of a disk stream uses a ring buffer to allow |
42 |
|
* thread safe refilling the stream's buffer with one thread (disk |
43 |
|
* thread) and actual use / extraction of the audio data from the |
44 |
|
* stream's buffer with another thread (audio thread). |
45 |
|
*/ |
46 |
class Stream { |
class Stream { |
47 |
public: |
public: |
48 |
// Member Types |
// Member Types |
61 |
}; |
}; |
62 |
|
|
63 |
// Methods |
// Methods |
64 |
Stream(uint BufferSize, uint BufferWrapElements); |
Stream( ::gig::buffer_t* pDecompressionBuffer, uint BufferSize, uint BufferWrapElements); |
65 |
~Stream(); |
virtual ~Stream(); |
66 |
int ReadAhead(unsigned long SampleCount); |
int ReadAhead(unsigned long SampleCount); |
67 |
void WriteSilence(unsigned long SilenceSampleWords); |
void WriteSilence(unsigned long SilenceSampleWords); |
68 |
|
|
69 |
inline int GetReadSpace() { |
inline int GetReadSpace() { |
70 |
return (pRingBuffer && State != state_unused) ? pRingBuffer->read_space() : 0; |
return (pRingBuffer && State != state_unused) ? pRingBuffer->read_space() / BytesPerSample : 0; |
71 |
} |
} |
72 |
|
|
73 |
inline int GetWriteSpace() { |
inline int GetWriteSpace() { |
75 |
} |
} |
76 |
|
|
77 |
inline int GetWriteSpaceToEnd() { |
inline int GetWriteSpaceToEnd() { |
78 |
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; |
79 |
} |
} |
80 |
|
|
81 |
// 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 |
82 |
// within the buffer (needed for interpolation) getting filled only partially |
// within the buffer (needed for interpolation) getting filled only partially |
83 |
// 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() |
84 |
inline int AdjustWriteSpaceToAvoidBoundary(int cnt, int capped_cnt) { |
inline int AdjustWriteSpaceToAvoidBoundary(int cnt, int capped_cnt) { |
85 |
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(); |
|
86 |
} |
} |
87 |
|
|
88 |
// gets the current read_ptr within the ringbuffer |
// gets the current read_ptr within the ringbuffer |
89 |
inline sample_t* GetReadPtr(void) { |
inline uint8_t* GetReadPtr(void) { |
90 |
return pRingBuffer->get_read_ptr(); |
return pRingBuffer->get_read_ptr(); |
91 |
} |
} |
92 |
|
|
93 |
inline void IncrementReadPos(uint Count) { |
inline void IncrementReadPos(uint Count) { |
94 |
|
Count *= BytesPerSample; |
95 |
uint leftspace = pRingBuffer->read_space(); |
uint leftspace = pRingBuffer->read_space(); |
96 |
pRingBuffer->increment_read_ptr(Min(Count, leftspace)); |
pRingBuffer->increment_read_ptr(Min(Count, leftspace)); |
97 |
if (State == state_end && Count >= leftspace) { |
if (State == state_end && Count >= leftspace) { |
103 |
inline static uint GetUnusedStreams() { return UnusedStreams; } |
inline static uint GetUnusedStreams() { return UnusedStreams; } |
104 |
protected: |
protected: |
105 |
// Methods |
// Methods |
106 |
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); |
107 |
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) |
108 |
inline Stream::Handle GetHandle() { return hThis; } |
inline Stream::Handle GetHandle() { return hThis; } |
109 |
inline Stream::state_t GetState() { return State; } |
inline Stream::state_t GetState() { return State; } |
114 |
state_t State; |
state_t State; |
115 |
Stream::Handle hThis; |
Stream::Handle hThis; |
116 |
unsigned long SampleOffset; |
unsigned long SampleOffset; |
117 |
::gig::Sample* pSample; |
::gig::DimensionRegion* pDimRgn; |
118 |
::gig::playback_state_t PlaybackState; |
::gig::playback_state_t PlaybackState; |
119 |
RingBuffer<sample_t>* pRingBuffer; |
RingBuffer<uint8_t,false>* pRingBuffer; |
120 |
bool DoLoop; |
bool DoLoop; |
121 |
|
::gig::buffer_t* pDecompressionBuffer; |
122 |
|
int BytesPerSample; |
123 |
|
|
124 |
// Static Attributes |
// Static Attributes |
125 |
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. |
126 |
|
static uint TotalStreams; //< Reflects how many stream objects currently exist. |
127 |
|
|
128 |
// Methods |
// Methods |
129 |
inline void Reset() { |
inline void Reset() { |
130 |
SampleOffset = 0; |
SampleOffset = 0; |
131 |
pSample = NULL; |
pDimRgn = NULL; |
132 |
PlaybackState.position = 0; |
PlaybackState.position = 0; |
133 |
PlaybackState.reverse = false; |
PlaybackState.reverse = false; |
134 |
hThis = 0; |
hThis = 0; |