-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathvirtualmachine.h
232 lines (182 loc) · 6.1 KB
/
virtualmachine.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
/*
Virtual machine for running basic DSP programs
Copyright 2006-2016
Niels A. Moseley
Pieter-Tjerk de Boer
License: GPLv2
*/
#ifndef virtualmachine_h
#define virtualmachine_h
#include <stdint.h>
#include <vector>
#include <QMutex>
#include "varinfo.h"
#include "qmainwindow.h"
#include "portaudio.h"
#include "portaudio_helper.h"
#include "pa_ringbuffer.h"
#include "wavstreamer.h"
#ifndef M_PI
#define M_PI 3.1415927
#endif
// instruction set of the VM
#define P_add 1
#define P_sub 2
#define P_mul 3
#define P_div 4
#define P_neg 5
#define P_literal 200
#define P_sin 100
#define P_cos 101
#define P_sin1 102
#define P_cos1 103
#define P_mod1 104
#define P_abs 105
#define P_round 106
#define P_sqrt 107
#define P_tan 108
#define P_tanh 109
#define P_pow 110
#define P_limit 111
#define P_atan2 112
#define P_sign 113
#define P_noise 114
#define P_trunc 115
#define P_ceil 116
#define P_floor 117
#define P_choose 118
// the following opcodes use the lower 16 bits for further identifying a variable or FIR
#define P_writevar 0x81000000
#define P_readvar 0x82000000
#define P_fir 0x83000000
#define P_biquad 0x84000000
#define P_writedelay 0x85000000
#define P_readdelay 0x86000000
namespace VM
{
union instruction_t
{
uint32_t icode;
float value;
};
typedef std::vector<instruction_t> program_t;
typedef std::vector<varInfo> variables_t;
/** find a variable by name. returns -1 if not found */
int32_t findVariableByName(const variables_t &vars, const std::string &name);
}
/** Virtual machine that executes BasicDSP programs.
The VM runs in a different thread (due to PortAudio)
and care must be taken to avoid data corruption
caused by multi-threading.
*/
class VirtualMachine
{
public:
VirtualMachine(QMainWindow *guiWindow);
virtual ~VirtualMachine();
/** load a program consisting of byte code */
void loadProgram(const VM::program_t &program, const VM::variables_t &variables);
/** start the execution of the program */
bool start();
/** stop the execution of the program */
void stop();
/** returns true if the virtual machine is running */
bool isRunning() const
{
return m_runState;
}
/** execute VM */
void processSamples(const float *inbuf,
float *outbuf,
uint32_t framesPerBuffer);
/** get the current VU levels */
void getVU(float &left, float &right)
{
QMutexLocker locker(&m_controlMutex);
left = m_leftLevel;
right = m_rightLevel;
}
/** set the value of a slider */
void setSlider(uint32_t id, float value);
/** set the source input */
enum src_t {SRC_SOUNDCARD, SRC_NOISE, SRC_SINE, SRC_QUADSINE, SRC_WAV, SRC_IMPULSE};
void setSource(src_t source);
/** set the frequency for the sine or quadsine generator in Hertz */
void setFrequency(double Hz);
/** dump the (human readable) VM program to an output stream */
void dump(std::ostream &s);
/** set monitoring variables for ring buffer */
bool setMonitoringVariable(uint32_t ringBufID, uint32_t channel, const std::string &varname);
/** set the audio file for the wav streamer */
bool setAudioFile(const QString &filename);
/** returns true if there is a valid audio file to use */
bool hasAudioFile();
/** get a pointer to one of the two ring buffers
to allow the reading of data by the GUI thread */
PaUtilRingBuffer* getRingBufferPtr(uint32_t ringBufID);
/** set the soundcard device parameters */
void setupSoundcard(PaDeviceIndex inDevice, PaDeviceIndex outDevice,
float sampleRate);
PaDeviceIndex getInputDevice() const
{
return m_inDevice;
}
PaDeviceIndex getOutputDevice() const
{
return m_outDevice;
}
float getSamplerate() const
{
return m_sampleRate;
}
struct ring_buffer_data_t
{
float s1;
float s2;
};
protected:
/** initialize internal pointers */
void init();
/** execute the program once */
void executeProgram(float inLeft, float inRight, float &outLeft, float &outRight);
/** calculate FIR output.
returns the number of stack elements that are popped.
*/
uint32_t execFIR(uint32_t n, float *stack);
/** calculate Biquad section.
returns the number of stack elements that are popped.
*/
uint32_t execBiquad(uint32_t n, float *stack);
QMainWindow *m_guiWindow;
PaStream *m_stream;
PaDeviceIndex m_inDevice;
PaDeviceIndex m_outDevice;
double m_sampleRate; // the current sample rate in Hz
float m_leftLevel; // the left channel VU level
float m_rightLevel; // the right channel VU level
bool m_runState; // true if VM is running a program
QMutex m_controlMutex; // mutex to synchronize GUI and VM threads
VM::program_t m_program; // VM byte code
VM::variables_t m_vars; // VM program variables
src_t m_source; // selected input source
// the following pointers are variables in
// m_vars, or NULL if the variable does not exist
// in the current VM program
float *m_lout; // pointer to left OUT variable
float *m_lin; // pointer to left IN variable
float *m_rout; // pointer to right OUT variable
float *m_rin; // pointer to right IN variable
float *m_in; // pointer to mono IN variable
float *m_out; // pointer to mono OUT variable
float *m_slider[4]; // pointers to slider variables
float m_freq; // sine or quadsine frequency (in Hz)
float m_phaseaccu; // phase accumulator [0..1) for frequency generator
// variables to send to spectrum & scope displays
// can be NULL if nothing is selected
float *m_monitorVar[4];
// thread-safe ring buffers for GUI I/O
PaUtilRingBuffer m_ringbuffer[2];
// handles audio streaming from .wav files
WavStreamer m_wavstreamer;
};
#endif