andrewm@55
|
1 /*
|
andrewm@55
|
2 * render.cpp
|
andrewm@55
|
3 *
|
andrewm@55
|
4 * Created on: Oct 24, 2014
|
andrewm@55
|
5 * Author: parallels
|
andrewm@55
|
6 */
|
andrewm@55
|
7
|
andrewm@55
|
8
|
andrewm@56
|
9 #include <BeagleRT.h>
|
andrewm@55
|
10 #include <cmath>
|
andrewm@55
|
11
|
andrewm@55
|
12 #define ANALOG_LOW (2048.0 / 65536.0)
|
andrewm@55
|
13 #define ANALOG_HIGH (50000.0 / 65536.0)
|
andrewm@55
|
14
|
andrewm@55
|
15 const int gDACPinOrder[] = {6, 4, 2, 0, 1, 3, 5, 7};
|
andrewm@55
|
16
|
andrewm@55
|
17 uint64_t gLastErrorFrame = 0;
|
andrewm@55
|
18 uint32_t gEnvelopeSampleCount = 0;
|
andrewm@55
|
19 float gEnvelopeValue = 0.5;
|
andrewm@55
|
20 float gEnvelopeDecayRate = 0.9995;
|
andrewm@55
|
21
|
andrewm@56
|
22 // setup() is called once before the audio rendering starts.
|
andrewm@55
|
23 // Use it to perform any initialisation and allocation which is dependent
|
andrewm@55
|
24 // on the period size or sample rate.
|
andrewm@55
|
25 //
|
andrewm@55
|
26 // userData holds an opaque pointer to a data structure that was passed
|
andrewm@55
|
27 // in from the call to initAudio().
|
andrewm@55
|
28 //
|
andrewm@55
|
29 // Return true on success; returning false halts the program.
|
andrewm@55
|
30
|
andrewm@56
|
31 bool setup(BeagleRTContext *context, void *userData)
|
andrewm@55
|
32 {
|
andrewm@55
|
33 return true;
|
andrewm@55
|
34 }
|
andrewm@55
|
35
|
andrewm@55
|
36 // render() is called regularly at the highest priority by the audio engine.
|
andrewm@55
|
37 // Input and output are given from the audio hardware and the other
|
andrewm@55
|
38 // ADCs and DACs (if available). If only audio is available, numMatrixFrames
|
andrewm@55
|
39 // will be 0.
|
andrewm@55
|
40
|
andrewm@55
|
41 void render(BeagleRTContext *context, void *userData)
|
andrewm@55
|
42 {
|
andrewm@55
|
43 static float phase = 0.0;
|
andrewm@55
|
44 static int sampleCounter = 0;
|
andrewm@55
|
45 static int invertChannel = 0;
|
andrewm@55
|
46 float frequency = 0;
|
andrewm@55
|
47
|
andrewm@55
|
48 // Play a sine wave on the audio output
|
andrewm@55
|
49 for(unsigned int n = 0; n < context->audioFrames; n++) {
|
andrewm@55
|
50 context->audioOut[2*n] = context->audioOut[2*n + 1] = gEnvelopeValue * sinf(phase);
|
andrewm@55
|
51
|
andrewm@55
|
52 // If one second has gone by with no error, play one sound, else
|
andrewm@55
|
53 // play another
|
andrewm@55
|
54 if(context->audioSampleCount + n - gLastErrorFrame > 44100) {
|
andrewm@55
|
55 gEnvelopeValue *= gEnvelopeDecayRate;
|
andrewm@55
|
56 gEnvelopeSampleCount++;
|
andrewm@55
|
57 if(gEnvelopeSampleCount > 22050) {
|
andrewm@55
|
58 gEnvelopeValue = 0.5;
|
andrewm@55
|
59 gEnvelopeSampleCount = 0;
|
andrewm@55
|
60 }
|
andrewm@55
|
61 frequency = 880.0;
|
andrewm@55
|
62 }
|
andrewm@55
|
63 else {
|
andrewm@55
|
64 gEnvelopeValue = 0.5;
|
andrewm@55
|
65 frequency = 220.0;
|
andrewm@55
|
66 }
|
andrewm@55
|
67
|
andrewm@55
|
68 phase += 2.0 * M_PI * frequency / 44100.0;
|
andrewm@55
|
69 if(phase >= 2.0 * M_PI)
|
andrewm@55
|
70 phase -= 2.0 * M_PI;
|
andrewm@55
|
71 }
|
andrewm@55
|
72
|
andrewm@55
|
73 for(unsigned int n = 0; n < context->analogFrames; n++) {
|
andrewm@55
|
74 // Change outputs every 512 samples
|
andrewm@55
|
75 if(sampleCounter < 512) {
|
andrewm@55
|
76 for(int k = 0; k < 8; k++) {
|
andrewm@55
|
77 if(k == invertChannel)
|
andrewm@55
|
78 context->analogOut[n*8 + gDACPinOrder[k]] = ANALOG_HIGH;
|
andrewm@55
|
79 else
|
andrewm@55
|
80 context->analogOut[n*8 + gDACPinOrder[k]] = 0;
|
andrewm@55
|
81 }
|
andrewm@55
|
82 }
|
andrewm@55
|
83 else {
|
andrewm@55
|
84 for(int k = 0; k < 8; k++) {
|
andrewm@55
|
85 if(k == invertChannel)
|
andrewm@55
|
86 context->analogOut[n*8 + gDACPinOrder[k]] = 0;
|
andrewm@55
|
87 else
|
andrewm@55
|
88 context->analogOut[n*8 + gDACPinOrder[k]] = ANALOG_HIGH;
|
andrewm@55
|
89 }
|
andrewm@55
|
90 }
|
andrewm@55
|
91
|
andrewm@55
|
92 // Read after 256 samples: input should be low
|
andrewm@55
|
93 if(sampleCounter == 256) {
|
andrewm@55
|
94 for(int k = 0; k < 8; k++) {
|
andrewm@55
|
95 if(k == invertChannel) {
|
andrewm@55
|
96 if(context->analogIn[n*8 + k] < ANALOG_HIGH) {
|
andrewm@55
|
97 rt_printf("FAIL [output %d, input %d] -- output HIGH input %f (inverted)\n", gDACPinOrder[k], k, context->analogIn[n*8 + k]);
|
andrewm@55
|
98 gLastErrorFrame = context->audioSampleCount + n;
|
andrewm@55
|
99 }
|
andrewm@55
|
100 }
|
andrewm@55
|
101 else {
|
andrewm@55
|
102 if(context->analogIn[n*8 + k] > ANALOG_LOW) {
|
andrewm@55
|
103 rt_printf("FAIL [output %d, input %d] -- output LOW --> input %f\n", gDACPinOrder[k], k, context->analogIn[n*8 + k]);
|
andrewm@55
|
104 gLastErrorFrame = context->audioSampleCount + n;
|
andrewm@55
|
105 }
|
andrewm@55
|
106 }
|
andrewm@55
|
107 }
|
andrewm@55
|
108 }
|
andrewm@55
|
109 else if(sampleCounter == 768) {
|
andrewm@55
|
110 for(int k = 0; k < 8; k++) {
|
andrewm@55
|
111 if(k == invertChannel) {
|
andrewm@55
|
112 if(context->analogIn[n*8 + k] > ANALOG_LOW) {
|
andrewm@55
|
113 rt_printf("FAIL [output %d, input %d] -- output LOW input %f (inverted)\n", gDACPinOrder[k], k, context->analogIn[n*8 + k]);
|
andrewm@55
|
114 gLastErrorFrame = context->audioSampleCount + n;
|
andrewm@55
|
115 }
|
andrewm@55
|
116 }
|
andrewm@55
|
117 else {
|
andrewm@55
|
118 if(context->analogIn[n*8 + k] < ANALOG_HIGH) {
|
andrewm@55
|
119 rt_printf("FAIL [output %d, input %d] -- output HIGH input %f\n", gDACPinOrder[k], k, context->analogIn[n*8 + k]);
|
andrewm@55
|
120 gLastErrorFrame = context->audioSampleCount + n;
|
andrewm@55
|
121 }
|
andrewm@55
|
122 }
|
andrewm@55
|
123 }
|
andrewm@55
|
124 }
|
andrewm@55
|
125
|
andrewm@55
|
126 if(++sampleCounter >= 1024) {
|
andrewm@55
|
127 sampleCounter = 0;
|
andrewm@55
|
128 invertChannel++;
|
andrewm@55
|
129 if(invertChannel >= 8)
|
andrewm@55
|
130 invertChannel = 0;
|
andrewm@55
|
131 }
|
andrewm@55
|
132 }
|
andrewm@55
|
133 }
|
andrewm@55
|
134
|
andrewm@56
|
135 // cleanup() is called once at the end, after the audio has stopped.
|
andrewm@56
|
136 // Release any resources that were allocated in setup().
|
andrewm@55
|
137
|
andrewm@56
|
138 void cleanup(BeagleRTContext *context, void *userData)
|
andrewm@55
|
139 {
|
andrewm@55
|
140
|
andrewm@55
|
141 }
|