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 }