MuseScore/zerberus/voice.h
2013-05-22 18:07:56 +02:00

180 lines
5.1 KiB
C++

//=============================================================================
// Zerberus
// Zample player
//
// Copyright (C) 2013 Werner Schweer
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation and appearing in
// the file LICENCE.GPL
//=============================================================================
#ifndef __MVOICE_H__
#define __MVOICE_H__
#include <cstdint>
#include <math.h>
class Channel;
struct Zone;
class Sample;
class Zerberus;
enum class LoopMode;
enum class OffMode;
static const int INTERP_MAX = 256;
static const int EG_SIZE = 256;
//---------------------------------------------------------
// Envelope
//---------------------------------------------------------
struct Envelope {
static float egPow[EG_SIZE];
static float egLin[EG_SIZE];
int steps, count;
float val;
float* table;
Envelope(float* f) { table = f; }
bool step() {
if (count) {
--count;
val = table[EG_SIZE * count/steps];
return false;
}
else
return true;
}
void setTime(float ms, int sampleRate);
};
//-----------------------------------------------------------------------------
// Phase
// Playing pointer for voice playback
//
// When a sample is played back at a different pitch, the playing pointer
// in the source sample will not advance exactly one sample per output sample.
//
// This playing pointer is implemented using Phase.
//-----------------------------------------------------------------------------
struct Phase {
union {
int64_t data;
struct {
uint8_t _fract;
};
};
void operator+=(const Phase& p) { data += p.data; }
void set(int b) { data = b * 256; }
void set(double b) { data = b * 256.0; }
int index() const { return data >> 8; }
unsigned fract() const { return _fract; }
Phase() {}
Phase(int64_t v) : data(v) {}
};
enum class VoiceState {
OFF,
ATTACK,
PLAYING,
SUSTAINED,
STOP
};
//---------------------------------------------------------
// Voice
//---------------------------------------------------------
class Voice {
Voice* _next;
Zerberus* _zerberus;
VoiceState _state = VoiceState::OFF;
Channel* _channel;
int _key;
int _velocity;
int audioChan;
short* data;
int eidx;
LoopMode _loopMode;
OffMode _offMode;
int _offBy;
float gain;
Phase phase, phaseIncr;
float fres; // the resonance frequency, in cents (not absolute cents)
float last_fres; // Current resonance frequency of the IIR filter
// Serves as a flag: A deviation between fres and last_fres
// indicates, that the filter has to be recalculated.
float q_lin; // the q-factor on a linear scale
float filter_gain; // Gain correction factor, depends on q
float hist1r, hist2r; // Sample history for the IIR filter
float hist1l, hist2l;
bool filter_startup; // Flag: If set, the filter will be set directly.
// Else it changes smoothly.
// filter coefficients
// b0 and b2 are identical >= b02
float b02; // b0 / a0
float b1; // b1 / a0
float a1; // a0 / a0
float a2; // a1 / a0
float b02_incr;
float b1_incr;
float a1_incr;
float a2_incr;
int filter_coeff_incr_count;
float modenv_val;
float modlfo_val;
Envelope attackEnv;
Envelope stopEnv;
static float interpCoeff[INTERP_MAX][4];
void updateFilter(float fres);
public:
Voice(Zerberus*);
Voice* next() const { return _next; }
void setNext(Voice* v) { _next = v; }
void start(Channel* channel, int key, int velo, const Zone*);
void process(int frames, float*);
Channel* channel() const { return _channel; }
int key() const { return _key; }
int velocity() const { return _velocity; }
bool isPlaying() const { return _state == VoiceState::PLAYING; }
bool isSustained() const { return _state == VoiceState::SUSTAINED; }
bool isOff() const { return _state == VoiceState::OFF; }
bool isStopped() const { return _state == VoiceState::STOP; }
void stop() { _state = VoiceState::STOP; }
void stop(float time);
void sustained() { _state = VoiceState::SUSTAINED; }
void off() { _state = VoiceState::OFF; }
const char* state() const;
LoopMode loopMode() const { return _loopMode; }
OffMode offMode() const { return _offMode; }
int offBy() const { return _offBy; }
static void init();
};
#endif