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 * |
* 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 * |
24 |
#ifndef __LS_GIG_VOICE_H__ |
#ifndef __LS_GIG_VOICE_H__ |
25 |
#define __LS_GIG_VOICE_H__ |
#define __LS_GIG_VOICE_H__ |
26 |
|
|
27 |
#include "../../common/global.h" |
#include "../../common/global_private.h" |
28 |
|
|
29 |
#include <gig.h> |
#include <gig.h> |
30 |
|
|
31 |
#include "../../common/RTMath.h" |
#include "../../common/RTMath.h" |
|
#include "../../common/RingBuffer.h" |
|
32 |
#include "../../common/Pool.h" |
#include "../../common/Pool.h" |
33 |
#include "../../drivers/audio/AudioOutputDevice.h" |
#include "../../drivers/audio/AudioOutputDevice.h" |
|
#include "../common/BiquadFilter.h" |
|
|
#include "Engine.h" |
|
|
#include "EngineChannel.h" |
|
34 |
#include "Stream.h" |
#include "Stream.h" |
35 |
#include "DiskThread.h" |
#include "DiskThread.h" |
36 |
#include "EGADSR.h" |
#include "EGADSR.h" |
37 |
#include "EGDecay.h" |
#include "EGDecay.h" |
38 |
#include "Filter.h" |
#include "Filter.h" |
39 |
#include "../common/LFOBase.h" |
#include "../common/LFOBase.h" |
40 |
|
#include "../common/VoiceBase.h" |
41 |
#include "SynthesisParam.h" |
#include "SynthesisParam.h" |
42 |
|
#include "SmoothVolume.h" |
43 |
|
|
44 |
// include the appropriate (unsigned) triangle LFO implementation |
// include the appropriate (unsigned) triangle LFO implementation |
45 |
#if CONFIG_UNSIGNED_TRIANG_ALGO == INT_MATH_SOLUTION |
#if CONFIG_UNSIGNED_TRIANG_ALGO == INT_MATH_SOLUTION |
64 |
#endif |
#endif |
65 |
|
|
66 |
namespace LinuxSampler { namespace gig { |
namespace LinuxSampler { namespace gig { |
|
|
|
67 |
class Engine; |
class Engine; |
68 |
|
class EngineChannel; |
69 |
|
|
70 |
/// Reflects a MIDI controller |
/// Reflects a MIDI controller |
71 |
struct midi_ctrl { |
struct midi_ctrl { |
94 |
* |
* |
95 |
* Renders a voice for the Gigasampler format. |
* Renders a voice for the Gigasampler format. |
96 |
*/ |
*/ |
97 |
class Voice { |
class Voice : public LinuxSampler::VoiceBase< ::gig::DimensionRegion> { |
98 |
public: |
public: |
|
// Types |
|
|
enum type_t { |
|
|
type_normal, |
|
|
type_release_trigger_required, ///< If the key of this voice will be released, it causes a release triggered voice to be spawned |
|
|
type_release_trigger ///< Release triggered voice which cannot be killed by releasing its key |
|
|
}; |
|
|
|
|
99 |
// Attributes |
// Attributes |
100 |
type_t Type; ///< Voice Type |
type_t Type; ///< Voice Type |
101 |
int MIDIKey; ///< MIDI key number of the key that triggered the voice |
int MIDIKey; ///< MIDI key number of the key that triggered the voice |
109 |
void Render(uint Samples); |
void Render(uint Samples); |
110 |
void Reset(); |
void Reset(); |
111 |
void SetOutput(AudioOutputDevice* pAudioOutputDevice); |
void SetOutput(AudioOutputDevice* pAudioOutputDevice); |
112 |
void SetEngine(Engine* pEngine); |
void SetEngine(LinuxSampler::Engine* pEngine); |
113 |
int Trigger(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent, int PitchBend, ::gig::DimensionRegion* pDimRgn, type_t VoiceType, int iKeyGroup); |
int Trigger(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent, int PitchBend, ::gig::DimensionRegion* pDimRgn, type_t VoiceType, int iKeyGroup); |
114 |
inline bool IsActive() { return PlaybackState; } |
inline bool IsActive() { return PlaybackState; } |
115 |
inline bool IsStealable() { return !itKillEvent && PlaybackState >= playback_state_ram; } |
inline bool IsStealable() { return !itKillEvent && PlaybackState >= playback_state_ram; } |
116 |
void UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent); |
void UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent); |
117 |
|
|
118 |
//private: |
virtual ::gig::DimensionRegion* GetRegion() { return pDimRgn; } |
|
// Types |
|
|
enum playback_state_t { |
|
|
playback_state_end = 0, |
|
|
playback_state_init = 1, |
|
|
playback_state_ram = 2, |
|
|
playback_state_disk = 3 |
|
|
}; |
|
119 |
|
|
120 |
|
//private: |
121 |
// Attributes |
// Attributes |
122 |
EngineChannel* pEngineChannel; |
EngineChannel* pEngineChannel; |
123 |
Engine* pEngine; ///< Pointer to the sampler engine, to be able to access the event lists. |
Engine* pEngine; ///< Pointer to the sampler engine, to be able to access the event lists. |
124 |
float Volume; ///< Volume level of the voice |
float VolumeLeft; ///< Left channel volume. This factor is calculated when the voice is triggered and doesn't change after that. |
125 |
float PanLeft; |
float VolumeRight; ///< Right channel volume. This factor is calculated when the voice is triggered and doesn't change after that. |
126 |
float PanRight; |
SmoothVolume CrossfadeSmoother; ///< Crossfade volume, updated by crossfade CC events |
127 |
float CrossfadeVolume; ///< Current attenuation level caused by a crossfade (only if a crossfade is defined of course) |
SmoothVolume VolumeSmoother; ///< Volume, updated by CC 7 (volume) events |
128 |
|
SmoothVolume PanLeftSmoother; ///< Left channel volume, updated by CC 10 (pan) events |
129 |
|
SmoothVolume PanRightSmoother; ///< Right channel volume, updated by CC 10 (pan) events |
130 |
double Pos; ///< Current playback position in sample |
double Pos; ///< Current playback position in sample |
131 |
float PitchBase; ///< Basic pitch depth, stays the same for the whole life time of the voice |
float PitchBase; ///< Basic pitch depth, stays the same for the whole life time of the voice |
132 |
float PitchBend; ///< Current pitch value of the pitchbend wheel |
float PitchBend; ///< Current pitch value of the pitchbend wheel |
133 |
|
float PitchBendRange; ///< The pitch range of the pitchbend wheel, value is in cents / 8192 |
134 |
float CutoffBase; ///< Cutoff frequency before control change, EG and LFO are applied |
float CutoffBase; ///< Cutoff frequency before control change, EG and LFO are applied |
135 |
::gig::Sample* pSample; ///< Pointer to the sample to be played back |
::gig::Sample* pSample; ///< Pointer to the sample to be played back |
136 |
::gig::DimensionRegion* pDimRgn; ///< Pointer to the articulation information of current dimension region of this voice |
::gig::DimensionRegion* pDimRgn; ///< Pointer to the articulation information of current dimension region of this voice |
137 |
|
bool Orphan; ///< true if this voice is playing a sample from an instrument that is unloaded. When the voice dies, the sample (and dimension region) will be handed back to the instrument resource manager. |
138 |
playback_state_t PlaybackState; ///< When a sample will be triggered, it will be first played from RAM cache and after a couple of sample points it will switch to disk streaming and at the end of a disk stream we have to add null samples, so the interpolator can do it's work correctly |
playback_state_t PlaybackState; ///< When a sample will be triggered, it will be first played from RAM cache and after a couple of sample points it will switch to disk streaming and at the end of a disk stream we have to add null samples, so the interpolator can do it's work correctly |
139 |
bool DiskVoice; ///< If the sample is very short it completely fits into the RAM cache and doesn't need to be streamed from disk, in that case this flag is set to false |
bool DiskVoice; ///< If the sample is very short it completely fits into the RAM cache and doesn't need to be streamed from disk, in that case this flag is set to false |
140 |
Stream::reference_t DiskStreamRef; ///< Reference / link to the disk stream |
Stream::reference_t DiskStreamRef; ///< Reference / link to the disk stream |
148 |
EGDecay EG3; ///< Envelope Generator 3 (Pitch) |
EGDecay EG3; ///< Envelope Generator 3 (Pitch) |
149 |
midi_ctrl VCFCutoffCtrl; |
midi_ctrl VCFCutoffCtrl; |
150 |
midi_ctrl VCFResonanceCtrl; |
midi_ctrl VCFResonanceCtrl; |
|
static const float FILTER_CUTOFF_COEFF; |
|
151 |
LFOUnsigned* pLFO1; ///< Low Frequency Oscillator 1 (Amplification) |
LFOUnsigned* pLFO1; ///< Low Frequency Oscillator 1 (Amplification) |
152 |
LFOUnsigned* pLFO2; ///< Low Frequency Oscillator 2 (Filter cutoff frequency) |
LFOUnsigned* pLFO2; ///< Low Frequency Oscillator 2 (Filter cutoff frequency) |
153 |
LFOSigned* pLFO3; ///< Low Frequency Oscillator 3 (Pitch) |
LFOSigned* pLFO3; ///< Low Frequency Oscillator 3 (Pitch) |
159 |
Pool<Event>::Iterator itKillEvent; ///< Event which caused this voice to be killed |
Pool<Event>::Iterator itKillEvent; ///< Event which caused this voice to be killed |
160 |
//private: |
//private: |
161 |
int SynthesisMode; |
int SynthesisMode; |
|
float fFinalVolume; |
|
162 |
float fFinalCutoff; |
float fFinalCutoff; |
163 |
float fFinalResonance; |
float fFinalResonance; |
164 |
SynthesisParam finalSynthesisParameters; |
SynthesisParam finalSynthesisParameters; |
168 |
static float CalculateFilterCutoffCoeff(); |
static float CalculateFilterCutoffCoeff(); |
169 |
|
|
170 |
// Methods |
// Methods |
171 |
void KillImmediately(); |
Stream::Handle KillImmediately(bool bRequestNotification = false); |
172 |
void ProcessEvents(uint Samples); |
void ProcessEvents(uint Samples); |
173 |
void Synthesize(uint Samples, sample_t* pSrc, uint Skip); |
void Synthesize(uint Samples, sample_t* pSrc, uint Skip); |
174 |
void processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End); |
void processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End); |
178 |
void processCutoffEvent(RTList<Event>::Iterator& itEvent); |
void processCutoffEvent(RTList<Event>::Iterator& itEvent); |
179 |
void processResonanceEvent(RTList<Event>::Iterator& itEvent); |
void processResonanceEvent(RTList<Event>::Iterator& itEvent); |
180 |
|
|
181 |
inline float CrossfadeAttenuation(uint8_t& CrossfadeControllerValue) { |
inline uint8_t CrossfadeAttenuation(uint8_t& CrossfadeControllerValue) { |
182 |
float att = (!pDimRgn->Crossfade.out_end) ? CrossfadeControllerValue / 127.0f /* 0,0,0,0 means no crossfade defined */ |
uint8_t c = std::max(CrossfadeControllerValue, pDimRgn->AttenuationControllerThreshold); |
183 |
: (CrossfadeControllerValue < pDimRgn->Crossfade.in_end) ? |
c = (!pDimRgn->Crossfade.out_end) ? c /* 0,0,0,0 means no crossfade defined */ |
184 |
((CrossfadeControllerValue <= pDimRgn->Crossfade.in_start) ? 0.0f |
: (c < pDimRgn->Crossfade.in_end) ? |
185 |
: float(CrossfadeControllerValue - pDimRgn->Crossfade.in_start) / float(pDimRgn->Crossfade.in_end - pDimRgn->Crossfade.in_start)) |
((c <= pDimRgn->Crossfade.in_start) ? 0 |
186 |
: (CrossfadeControllerValue <= pDimRgn->Crossfade.out_start) ? 1.0f |
: 127 * (c - pDimRgn->Crossfade.in_start) / (pDimRgn->Crossfade.in_end - pDimRgn->Crossfade.in_start)) |
187 |
: (CrossfadeControllerValue < pDimRgn->Crossfade.out_end) ? float(pDimRgn->Crossfade.out_end - CrossfadeControllerValue) / float(pDimRgn->Crossfade.out_end - pDimRgn->Crossfade.out_start) |
: (c <= pDimRgn->Crossfade.out_start) ? 127 |
188 |
: 0.0f; |
: (c < pDimRgn->Crossfade.out_end) ? 127 * (pDimRgn->Crossfade.out_end - c) / (pDimRgn->Crossfade.out_end - pDimRgn->Crossfade.out_start) |
189 |
return pDimRgn->InvertAttenuationController ? 1 - att : att; |
: 0; |
190 |
|
return pDimRgn->InvertAttenuationController ? 127 - c : c; |
191 |
} |
} |
192 |
|
|
193 |
inline float Constrain(float ValueToCheck, float Min, float Max) { |
inline float Constrain(float ValueToCheck, float Min, float Max) { |