38 |
* Initializes and triggers the voice, a disk stream will be launched if |
* Initializes and triggers the voice, a disk stream will be launched if |
39 |
* needed. |
* needed. |
40 |
* |
* |
41 |
* @param MIDIKey - MIDI key number of the triggered key |
* @param pNoteOnEvent - event that caused triggering of this voice |
42 |
* @param Velocity - MIDI velocity value of the triggered key |
* @param Pitch - MIDI detune factor (-8192 ... +8191) |
43 |
* @param Pitch - MIDI detune factor (-8192 ... +8191) |
* @param pInstrument - points to the loaded instrument which provides sample wave(s) and articulation data |
44 |
* @param pInstrument - points to the loaded instrument which provides sample wave(s) and articulation data |
* @returns 0 on success, a value < 0 if something failed |
|
* @param Delay - number of sample points triggering should be delayed |
|
|
* @returns 0 on success, a value < 0 if something failed |
|
45 |
*/ |
*/ |
46 |
int Voice::Trigger(int MIDIKey, uint8_t Velocity, int Pitch, gig::Instrument* pInstrument, uint Delay) { |
int Voice::Trigger(ModulationSystem::Event* pNoteOnEvent, int Pitch, gig::Instrument* pInstrument) { |
47 |
Active = true; |
Active = true; |
48 |
this->MIDIKey = MIDIKey; |
MIDIKey = pNoteOnEvent->Key; |
49 |
pRegion = pInstrument->GetRegion(MIDIKey); |
pRegion = pInstrument->GetRegion(MIDIKey); |
50 |
PlaybackState = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed |
PlaybackState = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed |
51 |
Pos = 0; |
Pos = 0; |
52 |
ReleaseVelocity = 127; // default release velocity value |
ReleaseVelocity = 127; // default release velocity value |
53 |
this->Delay = Delay; |
Delay = pNoteOnEvent->FragmentPos(); |
54 |
ReleaseSignalReceived = false; |
pTriggerEvent = pNoteOnEvent; |
55 |
|
|
56 |
if (!pRegion) { |
if (!pRegion) { |
57 |
std::cerr << "Audio Thread: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush; |
std::cerr << "Audio Thread: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush; |
64 |
for (int i = pRegion->Dimensions - 1; i >= 0; i--) { // Check if instrument has a velocity split |
for (int i = pRegion->Dimensions - 1; i >= 0; i--) { // Check if instrument has a velocity split |
65 |
if (pRegion->pDimensionDefinitions[i].dimension == gig::dimension_velocity) { |
if (pRegion->pDimensionDefinitions[i].dimension == gig::dimension_velocity) { |
66 |
uint DimValues[5] = {0,0,0,0,0}; |
uint DimValues[5] = {0,0,0,0,0}; |
67 |
DimValues[i] = Velocity; |
DimValues[i] = pNoteOnEvent->Velocity; |
68 |
pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]); |
pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]); |
69 |
break; |
break; |
70 |
} |
} |
111 |
this->Pitch = ((double) Pitch / 8192.0) / 12.0 + (pDimRgn->PitchTrack) ? pow(2, ((double) (MIDIKey - (int) pDimRgn->UnityNote) + (double) pDimRgn->FineTune / 100.0) / 12.0) |
this->Pitch = ((double) Pitch / 8192.0) / 12.0 + (pDimRgn->PitchTrack) ? pow(2, ((double) (MIDIKey - (int) pDimRgn->UnityNote) + (double) pDimRgn->FineTune / 100.0) / 12.0) |
112 |
: pow(2, ((double) pDimRgn->FineTune / 100.0) / 12.0); |
: pow(2, ((double) pDimRgn->FineTune / 100.0) / 12.0); |
113 |
|
|
114 |
Volume = pDimRgn->GetVelocityAttenuation(Velocity); |
Volume = pDimRgn->GetVelocityAttenuation(pNoteOnEvent->Velocity); |
115 |
|
|
116 |
EG1.Trigger(pDimRgn->EG1PreAttack, pDimRgn->EG1Attack, pDimRgn->EG1Release, Delay); |
EG1.Trigger(pDimRgn->EG1PreAttack, |
117 |
|
pDimRgn->EG1Attack, |
118 |
|
pDimRgn->EG1Hold, |
119 |
|
pSample->LoopStart, |
120 |
|
pDimRgn->EG1Decay1, |
121 |
|
pDimRgn->EG1Decay2, |
122 |
|
pDimRgn->EG1InfiniteSustain, |
123 |
|
pDimRgn->EG1Sustain, |
124 |
|
pDimRgn->EG1Release, |
125 |
|
Delay); |
126 |
|
|
127 |
// ************************************************ |
// ************************************************ |
128 |
// TODO: ARTICULATION DATA HANDLING IS MISSING HERE |
// TODO: ARTICULATION DATA HANDLING IS MISSING HERE |
154 |
|
|
155 |
|
|
156 |
// Let all modulators throw their parameter changes for the current audio fragment |
// Let all modulators throw their parameter changes for the current audio fragment |
157 |
EG1.Process(Samples); |
EG1.Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, pTriggerEvent, this->Pos, this->Pitch); |
158 |
|
|
159 |
|
|
160 |
switch (this->PlaybackState) { |
switch (this->PlaybackState) { |
210 |
// Reset delay |
// Reset delay |
211 |
Delay = 0; |
Delay = 0; |
212 |
|
|
213 |
|
pTriggerEvent = NULL; |
214 |
|
|
215 |
// If release stage finished, let the voice be killed |
// If release stage finished, let the voice be killed |
216 |
if (EG1.GetStage() == EG_VCA::stage_end) this->PlaybackState = playback_state_end; |
if (EG1.GetStage() == EG_VCA::stage_end) this->PlaybackState = playback_state_end; |
365 |
DiskStreamRef.OrderID = 0; |
DiskStreamRef.OrderID = 0; |
366 |
Active = false; |
Active = false; |
367 |
} |
} |
|
|
|
|
/** |
|
|
* Release the voice in an appropriate time range, the voice will go through |
|
|
* it's release stage before it will be killed. |
|
|
* |
|
|
* @param Delay - number of sample points releasing should be delayed (for jitter correction) |
|
|
*/ |
|
|
void Voice::Release(uint Delay) { |
|
|
if (!ReleaseSignalReceived) { |
|
|
EG1.Release(Delay); |
|
|
ReleaseSignalReceived = true; |
|
|
} |
|
|
} |
|