2016-05-02 18:16:26 -07:00
|
|
|
#ifndef __AMUSE_VOICE_HPP__
|
|
|
|
#define __AMUSE_VOICE_HPP__
|
|
|
|
|
2017-12-28 23:57:22 -08:00
|
|
|
#include <cstdint>
|
|
|
|
#include <cstdlib>
|
2016-05-02 18:16:26 -07:00
|
|
|
#include <memory>
|
2016-05-06 14:22:39 -07:00
|
|
|
#include <list>
|
2016-05-02 18:16:26 -07:00
|
|
|
#include "SoundMacroState.hpp"
|
|
|
|
#include "Entity.hpp"
|
2016-05-10 21:48:08 -07:00
|
|
|
#include "AudioGroupSampleDirectory.hpp"
|
|
|
|
#include "AudioGroup.hpp"
|
2016-05-11 14:30:45 -07:00
|
|
|
#include "Envelope.hpp"
|
2018-07-28 20:37:06 -07:00
|
|
|
#include "Studio.hpp"
|
2016-05-02 18:16:26 -07:00
|
|
|
|
|
|
|
namespace amuse
|
|
|
|
{
|
|
|
|
class IBackendVoice;
|
2016-05-14 23:48:26 -07:00
|
|
|
struct Keymap;
|
|
|
|
struct LayerMapping;
|
2016-05-02 18:16:26 -07:00
|
|
|
|
|
|
|
/** State of voice over lifetime */
|
|
|
|
enum class VoiceState
|
|
|
|
{
|
2016-05-13 23:33:21 -07:00
|
|
|
Playing, /**< SoundMacro actively executing, not in KeyOff */
|
2016-07-13 21:54:46 -07:00
|
|
|
KeyOff, /**< KeyOff event issued, macro beginning fade-out */
|
|
|
|
Dead /**< Default state, causes Engine to remove voice at end of pump cycle */
|
2016-05-02 18:16:26 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
/** Individual source of audio */
|
|
|
|
class Voice : public Entity
|
|
|
|
{
|
|
|
|
friend class Engine;
|
2016-05-14 23:48:26 -07:00
|
|
|
friend class Sequencer;
|
2018-07-13 23:06:33 -07:00
|
|
|
friend struct SoundMacroState;
|
2016-06-08 18:22:18 -07:00
|
|
|
friend class Envelope;
|
2017-09-18 20:59:20 -07:00
|
|
|
friend class Emitter;
|
2018-08-19 13:05:39 -07:00
|
|
|
friend struct SoundMacro::CmdScaleVolume;
|
|
|
|
friend struct SoundMacro::CmdKeyOff;
|
|
|
|
friend struct SoundMacro::CmdScaleVolumeDLS;
|
|
|
|
friend struct SoundMacro::CmdReturn;
|
|
|
|
friend struct SoundMacro::CmdGoSub;
|
|
|
|
friend struct SoundMacro::CmdTrapEvent;
|
|
|
|
friend struct SoundMacro::CmdUntrapEvent;
|
|
|
|
friend struct SoundMacro::CmdGetMessage;
|
|
|
|
friend struct SoundMacro::CmdModeSelect;
|
2018-08-15 23:26:44 -07:00
|
|
|
|
|
|
|
struct VolumeCache
|
|
|
|
{
|
|
|
|
bool m_curDLS = false; /**< Current DLS status of cached lookup */
|
|
|
|
float m_curVolLUTKey = -1.f; /**< Current input level cached out of LUT */
|
|
|
|
float m_curVolLUTVal = 0.f; /**< Current output level cached out of LUT */
|
|
|
|
float getVolume(float vol, bool dls);
|
|
|
|
float getCachedVolume() const { return m_curVolLUTVal; }
|
|
|
|
};
|
2018-07-13 23:06:33 -07:00
|
|
|
|
|
|
|
void _setObjectId(ObjectId id) { m_objectId = id; }
|
|
|
|
|
2016-07-13 21:54:46 -07:00
|
|
|
int m_vid; /**< VoiceID of this voice instance */
|
|
|
|
bool m_emitter; /**< Voice is part of an Emitter */
|
2018-07-28 20:37:06 -07:00
|
|
|
ObjToken<Studio> m_studio; /**< Studio this voice outputs to */
|
2018-08-09 23:19:23 -07:00
|
|
|
IObjToken<Sequencer> m_sequencer; /**< Strong reference to parent sequencer to retain ctrl vals */
|
2016-05-11 14:30:45 -07:00
|
|
|
|
2016-05-06 14:22:39 -07:00
|
|
|
std::unique_ptr<IBackendVoice> m_backendVoice; /**< Handle to client-implemented backend voice */
|
2016-07-13 21:54:46 -07:00
|
|
|
SoundMacroState m_state; /**< State container for SoundMacro playback */
|
|
|
|
SoundMacroState::EventTrap m_keyoffTrap; /**< Trap for keyoff (SoundMacro overrides default envelope behavior) */
|
2016-05-15 19:40:18 -07:00
|
|
|
SoundMacroState::EventTrap m_sampleEndTrap; /**< Trap for sampleend (SoundMacro overrides voice removal) */
|
2016-07-13 21:54:46 -07:00
|
|
|
SoundMacroState::EventTrap m_messageTrap; /**< Trap for messages sent from other SoundMacros */
|
2018-07-19 23:38:09 -07:00
|
|
|
int32_t m_latestMessage = 0; /**< Latest message received on voice */
|
2018-07-28 20:37:06 -07:00
|
|
|
std::list<ObjToken<Voice>> m_childVoices; /**< Child voices for PLAYMACRO usage */
|
2016-07-13 21:54:46 -07:00
|
|
|
uint8_t m_keygroup = 0; /**< Keygroup voice is a member of */
|
2016-05-06 14:22:39 -07:00
|
|
|
|
2018-07-28 20:37:06 -07:00
|
|
|
ObjToken<SampleEntryData> m_curSample; /**< Current sample entry playing */
|
2016-05-10 21:48:08 -07:00
|
|
|
const unsigned char* m_curSampleData = nullptr; /**< Current sample data playing */
|
2016-07-13 21:54:46 -07:00
|
|
|
SampleFormat m_curFormat; /**< Current sample format playing */
|
|
|
|
uint32_t m_curSamplePos = 0; /**< Current sample position */
|
|
|
|
uint32_t m_lastSamplePos = 0; /**< Last sample position (or last loop sample) */
|
|
|
|
int16_t m_prev1 = 0; /**< DSPADPCM prev sample */
|
|
|
|
int16_t m_prev2 = 0; /**< DSPADPCM prev-prev sample */
|
2017-09-18 20:59:20 -07:00
|
|
|
double m_dopplerRatio = 1.0; /**< Current ratio to mix with chromatic pitch for doppler effects */
|
2017-06-17 19:48:52 -07:00
|
|
|
double m_sampleRate = NativeSampleRate; /**< Current sample rate computed from relative sample key or SETPITCH */
|
2016-07-13 21:54:46 -07:00
|
|
|
double m_voiceTime = 0.0; /**< Current seconds of voice playback (per-sample resolution) */
|
|
|
|
uint64_t m_voiceSamples = 0; /**< Count of samples processed over voice's lifetime */
|
|
|
|
float m_lastLevel = 0.f; /**< Last computed level ([0,1] mapped to [-10,0] clamped decibels) */
|
|
|
|
float m_nextLevel = 0.f; /**< Next computed level used for lerp-mode amplitude */
|
2018-08-15 23:26:44 -07:00
|
|
|
VolumeCache m_nextLevelCache;
|
|
|
|
VolumeCache m_lerpedCache;
|
2016-05-10 21:48:08 -07:00
|
|
|
|
2016-05-14 15:38:37 -07:00
|
|
|
VoiceState m_voxState = VoiceState::Dead; /**< Current high-level state of voice */
|
2016-07-13 21:54:46 -07:00
|
|
|
bool m_sustained = false; /**< Sustain pedal pressed for this voice */
|
|
|
|
bool m_sustainKeyOff = false; /**< Keyoff event occured while sustained */
|
|
|
|
uint8_t m_curAftertouch = 0; /**< Aftertouch value (key pressure when 'bottoming out') */
|
|
|
|
|
|
|
|
float m_targetUserVol = 1.f; /**< Target user volume of voice (slewed to prevent audible aliasing) */
|
|
|
|
float m_curUserVol = 1.f; /**< Current user volume of voice */
|
|
|
|
float m_curVol = 1.f; /**< Current volume of voice */
|
|
|
|
float m_curReverbVol = 0.f; /**< Current reverb volume of voice */
|
|
|
|
float m_curAuxBVol = 0.f; /**< Current AuxB volume of voice */
|
|
|
|
float m_curPan = 0.f; /**< Current pan of voice */
|
2017-11-28 02:05:59 -08:00
|
|
|
float m_curSpan = -1.f; /**< Current surround pan of voice */
|
2016-07-13 21:54:46 -07:00
|
|
|
float m_curPitchWheel = 0.f; /**< Current normalized wheel value for control */
|
2018-08-14 01:36:02 -07:00
|
|
|
int32_t m_pitchWheelUp = 200; /**< Up range for pitchwheel control in cents */
|
|
|
|
int32_t m_pitchWheelDown = 200; /**< Down range for pitchwheel control in cents */
|
2016-07-13 21:54:46 -07:00
|
|
|
int32_t m_pitchWheelVal = 0; /**< Current resolved pitchwheel delta for control */
|
|
|
|
int32_t m_curPitch; /**< Current base pitch in cents */
|
|
|
|
bool m_pitchDirty = true; /**< m_curPitch has been updated and needs sending to voice */
|
|
|
|
bool m_needsSlew = false; /**< next _setTotalPitch will be slewed */
|
2018-08-15 23:26:44 -07:00
|
|
|
bool m_dlsVol = false; /**< Use DLS LUT for resolving voice volume */
|
2016-05-11 14:30:45 -07:00
|
|
|
|
2016-07-13 21:54:46 -07:00
|
|
|
Envelope m_volAdsr; /**< Volume envelope */
|
2016-06-01 19:28:48 -07:00
|
|
|
double m_envelopeTime = -1.f; /**< time since last ENVELOPE command, -1 for no active volume-sweep */
|
2016-07-13 21:54:46 -07:00
|
|
|
double m_envelopeDur; /**< requested duration of last ENVELOPE command */
|
|
|
|
float m_envelopeStart; /**< initial value for last ENVELOPE command */
|
|
|
|
float m_envelopeEnd; /**< final value for last ENVELOPE command */
|
2016-05-11 14:30:45 -07:00
|
|
|
const Curve* m_envelopeCurve; /**< curve to use for ENVELOPE command */
|
|
|
|
|
|
|
|
bool m_pitchEnv = false; /**< Pitch envelope activated */
|
2016-07-13 21:54:46 -07:00
|
|
|
Envelope m_pitchAdsr; /**< Pitch envelope for SETPITCHADSR */
|
2016-05-11 14:30:45 -07:00
|
|
|
int32_t m_pitchEnvRange; /**< Pitch delta for SETPITCHADSR (in cents) */
|
|
|
|
|
2016-06-01 19:28:48 -07:00
|
|
|
float m_portamentoTime = -1.f; /**< time since last portamento invocation, -1 for no active portamento-glide */
|
2016-07-13 21:54:46 -07:00
|
|
|
int32_t m_portamentoTarget; /**< destination pitch for latest portamento invocation */
|
2016-06-01 14:17:16 -07:00
|
|
|
|
2018-05-18 22:15:12 -07:00
|
|
|
int32_t m_pitchSweep1 = 0; /**< Current value of PITCHSWEEP1 controller (in cents) */
|
|
|
|
int32_t m_pitchSweep2 = 0; /**< Current value of PITCHSWEEP2 controller (in cents) */
|
2016-07-13 21:54:46 -07:00
|
|
|
int16_t m_pitchSweep1Add = 0; /**< Value to add to PITCHSWEEP1 controller each cycle */
|
|
|
|
int16_t m_pitchSweep2Add = 0; /**< Value to add to PITCHSWEEP2 controller each cycle */
|
2016-06-01 19:28:48 -07:00
|
|
|
uint8_t m_pitchSweep1Times = 0; /**< Remaining times to advance PITCHSWEEP1 controller */
|
|
|
|
uint8_t m_pitchSweep2Times = 0; /**< Remaining times to advance PITCHSWEEP2 controller */
|
2016-07-13 21:54:46 -07:00
|
|
|
uint8_t m_pitchSweep1It = 0; /**< Current iteration of PITCHSWEEP1 controller */
|
|
|
|
uint8_t m_pitchSweep2It = 0; /**< Current iteration of PITCHSWEEP2 controller */
|
2016-05-11 14:30:45 -07:00
|
|
|
|
2016-06-01 19:28:48 -07:00
|
|
|
float m_panningTime = -1.f; /**< time since last PANNING command, -1 for no active pan-sweep */
|
2016-07-13 21:54:46 -07:00
|
|
|
float m_panningDur; /**< requested duration of last PANNING command */
|
|
|
|
uint8_t m_panPos; /**< initial pan value of last PANNING command */
|
|
|
|
int8_t m_panWidth; /**< delta pan value to target of last PANNING command */
|
2016-05-11 14:30:45 -07:00
|
|
|
|
2016-06-01 19:28:48 -07:00
|
|
|
float m_spanningTime = -1.f; /**< time since last SPANNING command, -1 for no active span-sweep */
|
2016-07-13 21:54:46 -07:00
|
|
|
float m_spanningDur; /**< requested duration of last SPANNING command */
|
|
|
|
uint8_t m_spanPos; /**< initial pan value of last SPANNING command */
|
|
|
|
int8_t m_spanWidth; /**< delta pan value to target of last SPANNING command */
|
2016-05-11 14:30:45 -07:00
|
|
|
|
2018-05-18 22:15:12 -07:00
|
|
|
float m_vibratoTime = -1.f; /**< time since last VIBRATO command, -1 for no active vibrato */
|
2016-07-13 21:54:46 -07:00
|
|
|
int32_t m_vibratoLevel = 0; /**< scale of vibrato effect (in cents) */
|
|
|
|
int32_t m_vibratoModLevel = 0; /**< scale of vibrato mod-wheel influence (in cents) */
|
|
|
|
float m_vibratoPeriod = 0.f; /**< vibrato wave period-time, 0.f will disable vibrato */
|
2016-06-01 19:28:48 -07:00
|
|
|
bool m_vibratoModWheel = false; /**< vibrato scaled with mod-wheel if set */
|
2016-05-11 14:30:45 -07:00
|
|
|
|
2016-07-13 21:54:46 -07:00
|
|
|
float m_tremoloScale = 0.f; /**< minimum volume factor produced via LFO */
|
2016-06-01 19:28:48 -07:00
|
|
|
float m_tremoloModScale = 0.f; /**< minimum volume factor produced via LFO, scaled via mod wheel */
|
2016-05-11 14:30:45 -07:00
|
|
|
|
2016-07-13 21:54:46 -07:00
|
|
|
float m_lfoPeriods[2] = {}; /**< time-periods for LFO1 and LFO2 */
|
2016-05-15 14:56:23 -07:00
|
|
|
std::unique_ptr<int8_t[]> m_ctrlValsSelf; /**< Self-owned MIDI Controller values */
|
2016-07-13 21:54:46 -07:00
|
|
|
int8_t* m_extCtrlVals = nullptr; /**< MIDI Controller values (external storage) */
|
2016-05-11 14:30:45 -07:00
|
|
|
|
2018-08-14 01:36:02 -07:00
|
|
|
uint16_t m_rpn = 0; /**< Current RPN (only pitch-range 0x0000 supported) */
|
|
|
|
|
2016-05-06 14:22:39 -07:00
|
|
|
void _destroy();
|
2016-05-27 19:28:59 -07:00
|
|
|
bool _checkSamplePos(bool& looped);
|
2016-05-10 21:48:08 -07:00
|
|
|
void _doKeyOff();
|
2016-05-15 19:40:18 -07:00
|
|
|
void _macroKeyOff();
|
|
|
|
void _macroSampleEnd();
|
2016-07-13 21:54:46 -07:00
|
|
|
void _procSamplePre(int16_t& samp);
|
2018-08-15 23:26:44 -07:00
|
|
|
VolumeCache m_masterCache;
|
2016-07-13 21:54:46 -07:00
|
|
|
template <typename T>
|
|
|
|
T _procSampleMaster(double time, T samp);
|
2018-08-15 23:26:44 -07:00
|
|
|
VolumeCache m_auxACache;
|
2016-07-13 21:54:46 -07:00
|
|
|
template <typename T>
|
|
|
|
T _procSampleAuxA(double time, T samp);
|
2018-08-15 23:26:44 -07:00
|
|
|
VolumeCache m_auxBCache;
|
2016-07-13 21:54:46 -07:00
|
|
|
template <typename T>
|
|
|
|
T _procSampleAuxB(double time, T samp);
|
2016-05-16 20:47:12 -07:00
|
|
|
void _setTotalPitch(int32_t cents, bool slew);
|
2016-05-14 23:48:26 -07:00
|
|
|
bool _isRecursivelyDead();
|
2016-05-13 21:46:39 -07:00
|
|
|
void _bringOutYourDead();
|
2016-05-27 19:28:59 -07:00
|
|
|
static uint32_t _GetBlockSampleCount(SampleFormat fmt);
|
2018-07-28 20:37:06 -07:00
|
|
|
ObjToken<Voice> _findVoice(int vid, ObjToken<Voice> thisPtr);
|
2016-05-15 14:56:23 -07:00
|
|
|
std::unique_ptr<int8_t[]>& _ensureCtrlVals();
|
2016-05-11 14:30:45 -07:00
|
|
|
|
2018-07-28 20:37:06 -07:00
|
|
|
std::list<ObjToken<Voice>>::iterator _allocateVoice(double sampleRate, bool dynamicPitch);
|
|
|
|
std::list<ObjToken<Voice>>::iterator _destroyVoice(std::list<ObjToken<Voice>>::iterator it);
|
2016-05-06 14:22:39 -07:00
|
|
|
|
2018-07-14 23:10:50 -07:00
|
|
|
bool _loadSoundMacro(SoundMacroId id, const SoundMacro* macroData, int macroStep, double ticksPerSec,
|
2018-07-13 23:06:33 -07:00
|
|
|
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
|
2018-07-14 23:10:50 -07:00
|
|
|
bool _loadKeymap(const Keymap* keymap, double ticksPerSec, uint8_t midiKey,
|
2018-07-13 23:06:33 -07:00
|
|
|
uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
|
2018-07-14 23:10:50 -07:00
|
|
|
bool _loadLayer(const std::vector<LayerMapping>& layer, double ticksPerSec,
|
2018-07-13 23:06:33 -07:00
|
|
|
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
|
2018-07-28 20:37:06 -07:00
|
|
|
ObjToken<Voice> _startChildMacro(ObjectId macroId, int macroStep, double ticksPerSec, uint8_t midiKey,
|
|
|
|
uint8_t midiVel, uint8_t midiMod, bool pushPc = false);
|
2016-05-21 14:40:03 -07:00
|
|
|
|
2017-09-18 20:59:20 -07:00
|
|
|
void _panLaw(float coefsOut[8], float frontPan, float backPan, float totalSpan) const;
|
2016-05-21 14:40:03 -07:00
|
|
|
void _setPan(float pan);
|
|
|
|
void _setSurroundPan(float span);
|
2017-09-18 20:59:20 -07:00
|
|
|
void _setChannelCoefs(const float coefs[8]);
|
2016-06-19 20:35:57 -07:00
|
|
|
void _setPitchWheel(float pitchWheel);
|
2016-05-21 14:40:03 -07:00
|
|
|
void _notifyCtrlChange(uint8_t ctrl, int8_t val);
|
2016-07-13 21:54:46 -07:00
|
|
|
|
2016-05-02 18:16:26 -07:00
|
|
|
public:
|
2016-05-14 15:38:37 -07:00
|
|
|
~Voice();
|
2018-07-28 20:37:06 -07:00
|
|
|
Voice(Engine& engine, const AudioGroup& group, int groupId, int vid, bool emitter, ObjToken<Studio> studio);
|
2016-07-13 21:54:46 -07:00
|
|
|
Voice(Engine& engine, const AudioGroup& group, int groupId, ObjectId oid, int vid, bool emitter,
|
2018-07-28 20:37:06 -07:00
|
|
|
ObjToken<Studio> studio);
|
2016-05-02 18:16:26 -07:00
|
|
|
|
2016-07-04 18:08:00 -07:00
|
|
|
/** Called before each supplyAudio invocation to prepare voice
|
|
|
|
* backend for possible parameter updates */
|
|
|
|
void preSupplyAudio(double dt);
|
|
|
|
|
2016-05-02 18:16:26 -07:00
|
|
|
/** Request specified count of audio frames (samples) from voice,
|
|
|
|
* internally advancing the voice stream */
|
|
|
|
size_t supplyAudio(size_t frames, int16_t* data);
|
|
|
|
|
2016-07-13 21:54:46 -07:00
|
|
|
/** Called three times after resampling supplyAudio output, voice should
|
|
|
|
* perform volume processing / send routing for each aux bus and master */
|
|
|
|
void routeAudio(size_t frames, double dt, int busId, int16_t* in, int16_t* out);
|
|
|
|
void routeAudio(size_t frames, double dt, int busId, int32_t* in, int32_t* out);
|
|
|
|
void routeAudio(size_t frames, double dt, int busId, float* in, float* out);
|
|
|
|
|
2016-07-12 20:04:55 -07:00
|
|
|
/** Obtain pointer to Voice's Studio */
|
2018-07-28 20:37:06 -07:00
|
|
|
ObjToken<Studio> getStudio() { return m_studio; }
|
2016-05-07 15:10:57 -07:00
|
|
|
|
2016-05-02 18:16:26 -07:00
|
|
|
/** Get current state of voice */
|
2016-07-13 21:54:46 -07:00
|
|
|
VoiceState state() const { return m_voxState; }
|
2016-05-02 18:16:26 -07:00
|
|
|
|
2016-05-02 22:16:37 -07:00
|
|
|
/** Get VoiceId of this voice (unique to all currently-playing voices) */
|
2016-07-13 21:54:46 -07:00
|
|
|
int vid() const { return m_vid; }
|
2016-05-02 22:16:37 -07:00
|
|
|
|
2016-05-11 14:30:45 -07:00
|
|
|
/** Get max VoiceId of this voice and any contained children */
|
|
|
|
int maxVid() const;
|
|
|
|
|
2016-05-02 22:16:37 -07:00
|
|
|
/** Allocate parallel macro and tie to voice for possible emitter influence */
|
2018-07-28 20:37:06 -07:00
|
|
|
ObjToken<Voice> startChildMacro(int8_t addNote, ObjectId macroId, int macroStep);
|
2016-05-02 22:16:37 -07:00
|
|
|
|
2018-07-14 23:10:50 -07:00
|
|
|
/** Load specified SoundMacro Object from within group into voice */
|
|
|
|
bool loadMacroObject(SoundMacroId macroId, int macroStep, double ticksPerSec, uint8_t midiKey, uint8_t midiVel,
|
2016-07-13 21:54:46 -07:00
|
|
|
uint8_t midiMod, bool pushPc = false);
|
2016-05-02 22:16:37 -07:00
|
|
|
|
2018-07-31 01:04:43 -07:00
|
|
|
/** Load specified SoundMacro Object into voice */
|
|
|
|
bool loadMacroObject(const SoundMacro* macro, int macroStep, double ticksPerSec, uint8_t midiKey, uint8_t midiVel,
|
|
|
|
uint8_t midiMod, bool pushPc = false);
|
|
|
|
|
2018-07-14 23:10:50 -07:00
|
|
|
/** Load specified song page object (Keymap/Layer) from within group into voice */
|
|
|
|
bool loadPageObject(ObjectId objectId, double ticksPerSec, uint8_t midiKey, uint8_t midiVel, uint8_t midiMod);
|
|
|
|
|
2016-05-10 21:48:08 -07:00
|
|
|
/** Signals voice to begin fade-out (or defer if sustained), eventually reaching silence */
|
2016-05-02 18:16:26 -07:00
|
|
|
void keyOff();
|
|
|
|
|
2016-05-06 14:22:39 -07:00
|
|
|
/** Sends numeric message to voice and all siblings */
|
|
|
|
void message(int32_t val);
|
|
|
|
|
2016-05-10 21:48:08 -07:00
|
|
|
/** Start playing specified sample from within group, optionally by sample offset */
|
2018-07-16 00:41:15 -07:00
|
|
|
void startSample(SampleId sampId, int32_t offset);
|
2016-05-10 21:48:08 -07:00
|
|
|
|
|
|
|
/** Stop playing current sample */
|
2016-05-05 22:19:19 -07:00
|
|
|
void stopSample();
|
2016-05-10 21:48:08 -07:00
|
|
|
|
|
|
|
/** Set current voice volume immediately */
|
2016-05-02 18:16:26 -07:00
|
|
|
void setVolume(float vol);
|
2016-05-10 21:48:08 -07:00
|
|
|
|
|
|
|
/** Set current voice panning immediately */
|
2016-05-11 14:30:45 -07:00
|
|
|
void setPan(float pan);
|
2016-05-10 21:48:08 -07:00
|
|
|
|
|
|
|
/** Set current voice surround-panning immediately */
|
2016-05-11 14:30:45 -07:00
|
|
|
void setSurroundPan(float span);
|
|
|
|
|
2017-09-18 20:59:20 -07:00
|
|
|
/** Set current voice channel coefficients immediately */
|
|
|
|
void setChannelCoefs(const float coefs[8]);
|
|
|
|
|
2016-05-11 14:30:45 -07:00
|
|
|
/** Start volume envelope to specified level */
|
|
|
|
void startEnvelope(double dur, float vol, const Curve* envCurve);
|
|
|
|
|
|
|
|
/** Start volume envelope from zero to current level */
|
|
|
|
void startFadeIn(double dur, float vol, const Curve* envCurve);
|
|
|
|
|
|
|
|
/** Start pan envelope to specified position */
|
2016-05-21 14:40:03 -07:00
|
|
|
void startPanning(double dur, uint8_t panPos, int8_t panWidth);
|
2016-05-11 14:30:45 -07:00
|
|
|
|
|
|
|
/** Start span envelope to specified position */
|
2016-05-21 14:40:03 -07:00
|
|
|
void startSpanning(double dur, uint8_t spanPos, int8_t spanWidth);
|
2016-05-10 21:48:08 -07:00
|
|
|
|
|
|
|
/** Set voice relative-pitch in cents */
|
2016-05-05 22:19:19 -07:00
|
|
|
void setPitchKey(int32_t cents);
|
2016-05-10 21:48:08 -07:00
|
|
|
|
|
|
|
/** Set sustain status within voice; clearing will trigger a deferred keyoff */
|
2016-05-02 18:16:26 -07:00
|
|
|
void setPedal(bool pedal);
|
2016-05-10 21:48:08 -07:00
|
|
|
|
|
|
|
/** Set doppler factor for voice */
|
2016-05-02 18:16:26 -07:00
|
|
|
void setDoppler(float doppler);
|
2016-05-10 21:48:08 -07:00
|
|
|
|
2016-05-11 14:30:45 -07:00
|
|
|
/** Set vibrato parameters for voice */
|
2018-05-18 22:15:12 -07:00
|
|
|
void setVibrato(int32_t level, bool modScale, float period);
|
2016-05-11 14:30:45 -07:00
|
|
|
|
|
|
|
/** Configure modwheel influence range over vibrato */
|
|
|
|
void setMod2VibratoRange(int32_t modLevel);
|
|
|
|
|
|
|
|
/** Setup tremolo parameters for voice */
|
|
|
|
void setTremolo(float tremoloScale, float tremoloModScale);
|
|
|
|
|
|
|
|
/** Setup LFO1 for voice */
|
2016-07-13 21:54:46 -07:00
|
|
|
void setLFO1Period(float period) { m_lfoPeriods[0] = period; }
|
2016-05-11 14:30:45 -07:00
|
|
|
|
|
|
|
/** Setup LFO2 for voice */
|
2016-07-13 21:54:46 -07:00
|
|
|
void setLFO2Period(float period) { m_lfoPeriods[1] = period; }
|
2016-05-11 14:30:45 -07:00
|
|
|
|
|
|
|
/** Setup pitch sweep controller 1 */
|
|
|
|
void setPitchSweep1(uint8_t times, int16_t add);
|
|
|
|
|
|
|
|
/** Setup pitch sweep controller 2 */
|
|
|
|
void setPitchSweep2(uint8_t times, int16_t add);
|
|
|
|
|
2016-05-10 21:48:08 -07:00
|
|
|
/** Set reverb mix for voice */
|
2016-05-02 18:16:26 -07:00
|
|
|
void setReverbVol(float rvol);
|
2016-05-10 21:48:08 -07:00
|
|
|
|
2016-07-13 21:54:46 -07:00
|
|
|
/** Set AuxB volume for voice */
|
|
|
|
void setAuxBVol(float bvol);
|
|
|
|
|
2016-05-10 21:48:08 -07:00
|
|
|
/** Set envelope for voice */
|
2016-05-16 13:20:29 -07:00
|
|
|
void setAdsr(ObjectId adsrId, bool dls);
|
2016-05-10 21:48:08 -07:00
|
|
|
|
|
|
|
/** Set pitch in absolute hertz */
|
2016-05-05 22:19:19 -07:00
|
|
|
void setPitchFrequency(uint32_t hz, uint16_t fine);
|
2016-05-10 21:48:08 -07:00
|
|
|
|
|
|
|
/** Set pitch envelope */
|
2016-05-05 22:19:19 -07:00
|
|
|
void setPitchAdsr(ObjectId adsrId, int32_t cents);
|
2016-05-10 21:48:08 -07:00
|
|
|
|
2016-05-14 23:48:26 -07:00
|
|
|
/** Set pitchwheel value for use with controller */
|
|
|
|
void setPitchWheel(float pitchWheel);
|
|
|
|
|
2016-05-10 21:48:08 -07:00
|
|
|
/** Set effective pitch range via the pitchwheel controller */
|
2016-05-06 14:22:39 -07:00
|
|
|
void setPitchWheelRange(int8_t up, int8_t down);
|
2016-05-10 21:48:08 -07:00
|
|
|
|
2016-05-14 23:48:26 -07:00
|
|
|
/** Set aftertouch */
|
|
|
|
void setAftertouch(uint8_t aftertouch);
|
|
|
|
|
2016-05-10 21:48:08 -07:00
|
|
|
/** Assign voice to keygroup for coordinated mass-silencing */
|
2016-07-13 21:54:46 -07:00
|
|
|
void setKeygroup(uint8_t kg) { m_keygroup = kg; }
|
2016-05-05 22:19:19 -07:00
|
|
|
|
2016-05-15 14:56:23 -07:00
|
|
|
/** Get note played on voice */
|
2016-07-13 21:54:46 -07:00
|
|
|
uint8_t getLastNote() const { return m_state.m_initKey; }
|
2016-05-15 14:56:23 -07:00
|
|
|
|
2016-06-01 14:17:16 -07:00
|
|
|
/** Do portamento glide; returns `false` if portamento disabled */
|
|
|
|
bool doPortamento(uint8_t newNote);
|
|
|
|
|
2016-05-15 14:56:23 -07:00
|
|
|
/** Get MIDI Controller value on voice */
|
2016-05-14 23:48:26 -07:00
|
|
|
int8_t getCtrlValue(uint8_t ctrl) const
|
|
|
|
{
|
2016-05-15 14:56:23 -07:00
|
|
|
if (!m_extCtrlVals)
|
|
|
|
{
|
|
|
|
if (m_ctrlValsSelf)
|
2018-05-24 23:37:27 -07:00
|
|
|
return m_ctrlValsSelf[ctrl];
|
2016-05-14 23:48:26 -07:00
|
|
|
return 0;
|
2016-05-15 14:56:23 -07:00
|
|
|
}
|
|
|
|
return m_extCtrlVals[ctrl];
|
2016-05-14 23:48:26 -07:00
|
|
|
}
|
2016-05-15 14:56:23 -07:00
|
|
|
|
|
|
|
/** Set MIDI Controller value on voice */
|
2016-05-14 23:48:26 -07:00
|
|
|
void setCtrlValue(uint8_t ctrl, int8_t val)
|
|
|
|
{
|
2016-05-15 14:56:23 -07:00
|
|
|
if (!m_extCtrlVals)
|
|
|
|
{
|
|
|
|
std::unique_ptr<int8_t[]>& vals = _ensureCtrlVals();
|
|
|
|
vals[ctrl] = val;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_extCtrlVals[ctrl] = val;
|
2016-05-21 14:40:03 -07:00
|
|
|
_notifyCtrlChange(ctrl, val);
|
2016-05-14 23:48:26 -07:00
|
|
|
}
|
2016-05-15 14:56:23 -07:00
|
|
|
|
|
|
|
/** 'install' external MIDI controller storage */
|
|
|
|
void installCtrlValues(int8_t* cvs)
|
2016-05-14 23:48:26 -07:00
|
|
|
{
|
2016-05-15 14:56:23 -07:00
|
|
|
m_ctrlValsSelf.reset();
|
|
|
|
m_extCtrlVals = cvs;
|
2018-08-07 00:09:23 -07:00
|
|
|
for (ObjToken<Voice>& vox : m_childVoices)
|
|
|
|
vox->installCtrlValues(cvs);
|
2016-05-14 23:48:26 -07:00
|
|
|
}
|
2016-05-15 14:56:23 -07:00
|
|
|
|
|
|
|
/** Get MIDI pitch wheel value on voice */
|
2016-07-13 21:54:46 -07:00
|
|
|
float getPitchWheel() const { return m_curPitchWheel; }
|
2016-05-15 14:56:23 -07:00
|
|
|
|
|
|
|
/** Get MIDI aftertouch value on voice */
|
2016-07-13 21:54:46 -07:00
|
|
|
int8_t getAftertouch() const { return m_curAftertouch; }
|
2016-05-15 14:56:23 -07:00
|
|
|
|
|
|
|
/** Get count of all voices in hierarchy, including this one */
|
2016-05-14 23:48:26 -07:00
|
|
|
size_t getTotalVoices() const;
|
2016-05-02 18:16:26 -07:00
|
|
|
|
2018-07-31 01:04:43 -07:00
|
|
|
/** Get latest decoded sample index */
|
|
|
|
uint32_t getSamplePos() const { return m_curSamplePos; }
|
|
|
|
|
2016-05-31 13:40:51 -07:00
|
|
|
/** Recursively mark voice as dead for Engine to deallocate on next cycle */
|
|
|
|
void kill();
|
2016-05-02 18:16:26 -07:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // __AMUSE_VOICE_HPP__
|