1 module PixelPerfectEngine.audio.common;
2 
3 import PixelPerfectEngine.system.platform;
4 static if(USE_INTEL_INTRINSICS){
5 	import inteli.emmintrin;
6 	//immutable __m128i zeroes;
7 	immutable __m128 multiVal = [32_768f, 32_768f, 32_768f, 32_768f];
8 }else{
9 	immutable float[4] multiVal = [32_768f, 32_768f, 32_768f, 32_768f];
10 }
11 
12 import std.bitmanip;
13 import std.math;
14 
15 /**
16  * Defines basic functions for an envelope generator.
17  */
18 public interface IEnvelopeGenerator{
19 	public @nogc uint updateEnvelopeState();
20 	public @nogc void setKeyOn();
21 	public @nogc void setKeyOff();
22 }
23 /**
24  * Stores an MICP command on 64 bits.
25  */
26 public struct MICPCommand{
27 	mixin(bitfields!(
28 		ushort, "command", 6,
29 		ushort, "channel", 10));
30 	ushort val0;		///
31 	union{
32 		ushort[2] vals;
33 		float valf;
34 		ubyte[4] midiCMD;
35 		uint val32;
36 	}
37 	/*alias note = val0;
38 	alias parameter = val0;
39 	alias velocity = val1[0];
40 	alias expr = val1[1];
41 	alias program = val1[0];
42 	alias bank = val1[1];
43 	alias valueInt = val1[0];
44 	alias valueFloat = val2;*/
45 }
46 /**
47  * Command list for MICP
48  */
49 public enum MICPCommandList : ushort{
50 	NULL	=	0,
51 	KeyOn	=	1,			///val0: Note, val1: Velocity, val2: Expression
52 	KeyOff	=	2,			///val0: Note, val1: Velocity, val2: Expression
53 	AfterTouch	=	3,		///val0: Note, val1: Velocity, val2: Expression
54 	PitchBend	=	4,		///val0: Note, val1: Corase, val2: Fine
55 	PitchBentFP	=	5,		///val0: Note, valf: Amount
56 	ProgSelect	=	6,		///val0: Prog, val1: Bank if used, val2: Unused
57 	ParamEdit	=	7,		///val0: Parameter ID, val1: New value, val2: Unused
58 	ParamEditFP	=	8,		///val0: Parameter ID, valf: New value
59 	ParamEdit32 =	9,		///val0: Parameter ID, val32: New value
60 	PrgKeyOn	=	11,		///Special key-on command. Same params as KeyOn. Mainly used for arpeggiation and programming sequences
61 	PrgKeyOff	=	12,		///Special key-off command. Same params as KeyOff. Mainly used for arpeggiation and programming sequences
62 	SysExc	=	16,
63 	MIDIThruMICP	=	17,	///val0 is unused
64 	Wait	=	24			///val0: bits 32-47 if needed, val32: bits 0-31
65 }
66 
67 /**
68  * All PPE-FX synths and effects should be inherited from this class.
69  */
70 abstract class AbstractPPEFX{
71 	public abstract @nogc void render(float** inputBuffers, float** outputBuffers);
72 	public abstract @nogc int setRenderParams(float samplerate, size_t framelength, size_t nOfFrames);
73 	public abstract @nogc void receiveMICPCommand(MICPCommand cmd);
74 	public abstract void loadConfig(ref void[] data);
75 	public abstract ref void[] saveConfig();
76 	public abstract PPEFXInfo* getPPEFXInfo();
77 	/**
78 	 * Converts a midi note to frequency, can also take fine tuning.
79 	 */
80 	public @nogc float midiNoteToFrequency(float note, float tuning = 440.0f){
81     	return tuning * pow(2.0, (note - 69.0f) / 12.0f);
82 	}
83 	/**
84 	 * Changes the frequency by the given pitch.
85 	 */
86 	public @nogc float bendFreqByPitch(float pitch, float input){
87     	return input * pow(2.0, pitch / 12.0f);
88 	}
89 	public @nogc float frequencyToMidiNote(float frequency, float tuning = 440.0f){
90     	return 69.0f + 12.0f * log2(frequency / tuning);
91 	}
92 	/**
93 	 * Converts int16 values to single-precision floating-point.
94 	 */
95 	public @nogc void int16ToFloat(short* input, float* output, size_t length){
96 		static if(USE_INTEL_INTRINSICS){
97 			while(length > 4){
98 				__m128i vals;// = [input[0],input[1],input[2],input[3]];
99 				vals[0] = input[0];
100 				vals[1] = input[1];
101 				vals[2] = input[2];
102 				vals[3] = input[3];
103 				*cast(__m128*)output = _mm_cvtepi32_ps(vals) / multiVal;
104 				input += 4;
105 				output += 4;
106 				length -= 4;
107 			}
108 		}
109 		while(length > 0){
110 			*output = cast(float)*input / multiVal[0];
111 			input++;
112 			output++;
113 			length--;
114 		}
115 	}
116 	/**
117 	 * Converts single-precision floating point to int16 values.
118 	 */
119 	public @nogc void floatToInt16(float* input, short* output, size_t length){
120 		static if(USE_INTEL_INTRINSICS){
121 			while(length > 4){
122 				__m128i vals = _mm_cvtps_epi32(*cast(__m128*)input * multiVal);
123 				output[0] = cast(short)vals[0];
124 				output[1] = cast(short)vals[1];
125 				output[2] = cast(short)vals[2];
126 				output[3] = cast(short)vals[3];
127 				input += 4;
128 				output += 4;
129 				length -= 4;
130 			}
131 		}
132 		while(length > 0){
133 			*output = cast(short)(*input / multiVal[0]);
134 			input++;
135 			output++;
136 			length--;
137 		}
138 	}
139 	/**
140 	 * Mixes a stream into the target.
141 	 */
142 	public @nogc void mixStreamIntoTarget(float* input, float* output, size_t length, float sendLevel){
143 		static if(USE_INTEL_INTRINSICS){
144 			__m128 sendLevel4;// = [sendLevel,sendLevel,sendLevel,sendLevel];
145 			sendLevel4[0] = sendLevel;
146 			sendLevel4[1] = sendLevel;
147 			sendLevel4[2] = sendLevel;
148 			sendLevel4[3] = sendLevel;
149 			while(length > 4){
150 				*cast(__m128*)output += *cast(__m128*)input * sendLevel4;
151 				input += 4;
152 				output += 4;
153 				length -= 4;
154 			}
155 		}
156 		while(length > 0){
157 			*output += *input * sendLevel;
158 			input++;
159 			output++;
160 			length--;
161 		}
162 	}
163 	/**
164 	 * Converts an int16 stream into floating point, then adds it to the target.
165 	 */
166 	public @nogc void convAndMixStreamIntoTarget(short* input, float* output, size_t length, float sendLevel){
167 		static if(USE_INTEL_INTRINSICS){
168 			__m128 sendLevel4;// = [sendLevel,sendLevel,sendLevel,sendLevel];
169 			sendLevel4[0] = sendLevel;
170 			sendLevel4[1] = sendLevel;
171 			sendLevel4[2] = sendLevel;
172 			sendLevel4[3] = sendLevel;
173 			while(length > 4){
174 				__m128i vals;// = [input[0],input[1],input[2],input[3]];
175 				vals[0] = input[0];
176 				vals[1] = input[1];
177 				vals[2] = input[2];
178 				vals[3] = input[3];
179 				*cast(__m128*)output += (_mm_cvtepi32_ps(vals) / multiVal) * sendLevel4;
180 				input += 4;
181 				output += 4;
182 				length -= 4;
183 			}
184 		}
185 		while(length > 0){
186 			*output += (cast(float)*input / multiVal[0]) * sendLevel;
187 			input++;
188 			output++;
189 			length--;
190 		}
191 	}
192 }
193 
194 public struct PPEFXInfo{
195 	public int nOfInputs;
196 	public int nOfOutputs;
197 	public string[] inputNames;
198 	public string[] outputNames;
199 	public bool isSynth;
200 
201 }