1 module pixelperfectengine.audio.modules.pcm8; 2 3 import pixelperfectengine.audio.base.modulebase; 4 import pixelperfectengine.audio.base.types; 5 import pixelperfectengine.audio.base.envgen; 6 import pixelperfectengine.audio.base.func; 7 import pixelperfectengine.audio.base.envgen; 8 import pixelperfectengine.audio.base.osc; 9 10 11 import collections.treemap; 12 13 import inteli.emmintrin; 14 15 import midi2.types.structs; 16 import midi2.types.enums; 17 18 import bitleveld.datatypes; 19 20 /** 21 PCM8 - implements a sample-based synthesizer. 22 23 It has support for 24 * 8 bit and 16 bit linear PCM 25 * Mu-Law and A-Law PCM 26 * IMA ADPCM 27 * Dialogic ADPCM 28 29 The module has 8 sample-based channels with looping capabilities and each has an ADSR envelop, and 4 outputs with a filter. 30 */ 31 public class PCM8 : AudioModule { 32 /** 33 Contains a table to calculate Attack, Decay, and Release values. 34 35 All values are seconds with factions. Actual values are live-calculated depending on sustain-level and sampling 36 frequency. 37 */ 38 public static immutable float[128] ADSR_TIME_TABLE = [ 39 // 0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |A |B |C |D |E |F 40 0.000, 0.0005,0.001, 0.0015,0.002, 0.0025,0.003, 0.0035,0.004, 0.0045,0.005, 0.006, 0.007, 0.008, 0.009, 0.010,//0 41 0.011, 0.012, 0.013, 0.014, 0.015, 0.017, 0.019, 0.021, 0.023, 0.025, 0.028, 0.031, 0.034, 0.038, 0.042, 0.047,//1 42 0.052, 0.057, 0.062, 0.067, 0.073, 0.079, 0.085, 0.092, 0.099, 0.107, 0.116, 0.126, 0.137, 0.149, 0.162, 0.176,//2 43 0.191, 0.207, 0.224, 0.242, 0.261, 0.281, 0.302, 0.324, 0.347, 0.371, 0.396, 0.422, 0.449, 0.477, 0.506, 0.536,//3 44 0.567, 0.599, 0.632, 0.666, 0.701, 0.737, 0.774, 0.812, 0.851, 0.891, 0.932, 0.974, 1.017, 1.061, 1.106, 1.152,//4 45 1.199, 1.247, 1.296, 1.346, 1.397, 1.499, 1.502, 1.556, 1.611, 1.667, 1.724, 1.782, 1.841, 1.901, 1.962, 2.024,//5 46 2.087, 2.151, 2.216, 2.282, 2.349, 2.417, 2.486, 2.556, 2.627, 2.699, 2.772, 2.846, 2.921, 2.997, 3.074, 3.152,//6 47 3.231, 3.331, 3.392, 3.474, 3.557, 3.621, 3.726, 3.812, 3.899, 3.987, 4.076, 4.166, 4.257, 4.349, 4.442, 4.535,//7 48 49 ]; 50 /** 51 Contains a table to calculate Sustain control values. 52 53 All values are seconds with fractions. Actual values are live-calculated depending on sustain level and sampling 54 frequency. Please note that with certain levels of sustain, the actual max time might be altered. 55 */ 56 public static immutable float[63] SUSTAIN_CONTROL_TIME_TABLE = [ 57 // 0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |A |B |C |D |E |F 58 70.00, 60.00, 55.00, 50.00, 45.00, 42.50, 40.00, 38.50, 35.00, 32.50, 30.00, 27.50, 25.00, 24.00, 23.00, 22.00,//0 59 21.00, 20.00, 19.00, 18.00, 17.50, 17.00, 16.50, 16.00, 15.50, 15.00, 14.50, 14.00, 13.50, 13.00, 12.50, 12.25,//1 60 12.00, 11.75, 11.50, 11.25, 11.00, 10.75, 10.50, 10.25, 10.00, 9.750, 9.500, 9.250, 9.000, 8.750, 8.500, 8.250,//2 61 8.000, 7.750, 7.500, 7.250, 7.000, 6.750, 6.500, 6.250, 6.000, 5.750, 5.500, 5.250, 5.000, 4.750, 4.500 //3 62 ]; 63 /** 64 Defines a single sample. 65 */ 66 protected struct Sample { 67 ///Stores sample data, which later can be decompressed 68 ubyte[] sampleData; 69 ///Stores what kind of format the sample has 70 WaveFormat format; 71 } 72 /** 73 Defines a single sample-to-note assignment. 74 */ 75 protected struct SampleAssignment { 76 ///Number of sample that is assigned. 77 uint sampleNum; 78 ///The base frequency of the sample. 79 ///Overrides the format definition. 80 float baseFreq; 81 ///Start of a looppoint. 82 ///0, if looppoint is not available. 83 uint loopBegin; 84 ///End of a looppoint. 85 ///0, if looppoint is not available. 86 uint loopEnd; 87 } 88 /** 89 Stores preset information. 90 */ 91 protected struct Preset { 92 /// Stores sample mappings for each note. 93 SampleAssignment[128] sampleMapping; 94 ubyte eAtk; ///Attack time selector 95 ubyte eDec; ///Decay time selector 96 ubyte eSusC; ///Sustain control (0: percussive; 1-63: descending; 64: constant; 65-127: ascending) 97 ubyte eRel; ///Release time selector 98 float eAtkShp = 0.5;///Attack shaping 99 float eRelShp = 0.5;///Release shaping 100 float eSusLev = 1;///Sustain level 101 float masterVol = 1;///Master output volume 102 float balance = 0.5;///Master output balance 103 float auxSendA = 0;///Aux send level A 104 float auxSendB = 0;///Aux send level B 105 float velToLevelAm = 0;///Assigns velocity to output levels 106 float velToAuxSendAm = 0;///Assigns velocity to aux send levels 107 float velToAtkShp = 0;///Assigns velocity to attack shape of envelop generator 108 float velToRelShp = 0;///Assigns velocity to release shape of envelop generator 109 uint flags; ///Contains various binary settings 110 } 111 protected enum PresetFlags { 112 cutoffOnKeyOff = 1<<0, ///If set, the sample playback will cut off on every key off event 113 modwheelToALFO = 1<<1, ///Assigns modulation wheel to amplitude LFO levels 114 modwheelToPLFO = 1<<2, ///Assigns modulation wheel to pitch LFO levels 115 panningALFO = 1<<3, ///Sets amplitude LFO to panning on this channel 116 disableADSRonVol = 1<<4, 117 } 118 /** 119 Defines a single channel's statuses. 120 */ 121 protected struct Channel { 122 int[1024] decoderBuffer; ///Stores a 1ks of decoded samples. 123 Preset presetCopy; ///The copy of the preset. 124 Workpad decoderWorkpad; ///Stores the current state of the decoder. 125 Workpad savedDWState; ///The state of the decoder when the beginning of the looppoint has been reached. 126 WavemodWorkpad waveModWorkpad; ///Stores the current state of the wave modulator. 127 WavemodWorkpad savedWMWState; ///The state of the wave modulator when the beginning of the looppoint has been reached. 128 ADSREnvelopGenerator envGen; ///Channel envelop generator. 129 ubyte currNote; ///The currently played note. 130 ubyte presetNum; ///Selected preset. 131 ushort bankNum; ///Bank select number. 132 float velocity; ///Velocity normalized between 0 and 1 133 float modWheel; ///Modulation wheel normalized between 0 and 1 134 float currShpA; ///The current attack shape 135 float currShpR; ///The current release shape 136 } 137 alias SampleMap = TreeMap!(uint, Sample); 138 alias PresetMap = TreeMap!(uint, Preset); 139 protected SampleMap sampleBank; ///Stores all current samples. 140 protected PresetMap presetBank; ///Stores all current presets. (bits: 0-6: preset number, 7-13: bank lsb, 14-20: bank msb) 141 protected Channel[8] channels; ///Channel status data. 142 protected Oscillator[2] lfo; ///Low frequency oscillators to modify values in real-time 143 protected float[][2] lfoOut; ///LFO output buffers 144 145 public this() @safe nothrow { 146 info.nOfAudioInput = 0; 147 info.nOfAudioOutput = 4; 148 info.outputChNames = ["mainL", "mainR", "auxSendA", "auxSendB"]; 149 info.isInstrument = true; 150 info.hasMidiIn = true; 151 info.hasMidiOut = true; 152 info.midiSendback = true; 153 } 154 /** 155 * Sets the module up. 156 * 157 * Can be overridden in child classes to allow resets. 158 */ 159 public override void moduleSetup(ubyte[] inputs, ubyte[] outputs, int sampleRate, size_t bufferSize, 160 ModuleManager handler) @safe nothrow { 161 enabledInputs = StreamIDSet(inputs); 162 enabledOutputs = StreamIDSet(outputs); 163 this.sampleRate = sampleRate; 164 this.bufferSize = bufferSize; 165 lfoOut[0].length = bufferSize; 166 lfoOut[1].length = bufferSize; 167 this.handler = handler; 168 } 169 /** 170 * MIDI 2.0 data received here. 171 * 172 * data: up to 128 bits of MIDI 2.0 commands. Any packets that are shorter should be padded with zeros. 173 * offset: time offset of the command. This can reduce jitter caused by the asynchronous operation of the 174 * sequencer and the audio plugin system. 175 */ 176 public override void midiReceive(uint[4] data, uint offset) @nogc nothrow { 177 178 } 179 /** 180 * Renders the current audio frame. 181 * 182 * input: the input buffers if any, null if none. 183 * output: the output buffers if any, null if none. 184 * 185 * NOTE: Buffers must have matching sizes. 186 */ 187 public override void renderFrame(float*[] input, float*[] output) @nogc nothrow { 188 189 } 190 /** 191 * Receives waveform data that has been loaded from disk for reading. Returns zero if successful, or a specific 192 * errorcode. 193 * 194 * id: The ID of the waveform. 195 * rawData: The data itself, in unprocessed form. 196 * format: The format of the wave data, including the data type, bit depth, base sampling rate 197 * 198 * Note: This function needs the audio system to be unlocked. 199 */ 200 public override int waveformDataReceive(uint id, ubyte[] rawData, WaveFormat format) nothrow { 201 int result; 202 if (!(format.format == AudioFormat.PCM || format.format == AudioFormat.MULAW || format.format == AudioFormat.ALAW || 203 format.format == AudioFormat.ADPCM || format.format == AudioFormat.DIALOGIC_OKI_ADPCM)) 204 result |= SampleLoadErrorCode.FormatNotSupported; 205 result |= format.channels == 1 ? 0 : SampleLoadErrorCode.ChNumNotSupported; 206 if (result) { 207 return result; 208 } else { 209 sampleBank[id] = Sample(rawData, format); 210 return 0; 211 } 212 } 213 /** 214 * Restores a parameter to the given preset. 215 * Returns an errorcode on failure. 216 */ 217 public override int recallParam_int(uint presetID, uint paramID, int value) @nogc nothrow { 218 return 0; 219 } 220 /** 221 * Restores a parameter to the given preset. 222 * Returns an errorcode on failure. 223 */ 224 public override int recallParam_uint(uint presetID, uint paramID, uint value) @nogc nothrow { 225 return 0; 226 } 227 /** 228 * Restores a parameter to the given preset. 229 * Returns an errorcode on failure. 230 */ 231 public override int recallParam_double(uint presetID, uint paramID, double value) @nogc nothrow { 232 return 0; 233 } 234 /** 235 * Restores a parameter to the given preset. 236 * Returns an errorcode on failure. 237 */ 238 public override int recallParam_string(uint presetID, uint paramID, string value) @nogc nothrow { 239 return 0; 240 } 241 }