-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaudio.cpp
More file actions
118 lines (96 loc) · 2.93 KB
/
audio.cpp
File metadata and controls
118 lines (96 loc) · 2.93 KB
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
#include <stdexcept>
#include <string>
#include "Audio.hpp"
void checkPaError(PaError err) {
if (err != paNoError) {
fprintf(stderr, "PortAudio error: %s\n", Pa_GetErrorText(err));
exit(-1);
}
}
static int apuCallback (const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData ) {
Audio *apu = (Audio *) userData;
float *out = (float *) outputBuffer;
(void) inputBuffer; /* Prevent unused variable warning. */
for(int i = 0; i < framesPerBuffer; i++) {
*out++ = apu->lastSampleLeft;
*out++ = apu->lastSampleRight;
apu->tick();
}
return 0;
}
Audio::Audio(CPU *cpu, float sampleRate)
: time(0), sampleRate(sampleRate), timeStep(1.0/sampleRate),
pulses(std::vector<PulseUnit>(N_PULSE_UNITS, PulseUnit(sampleRate))),
custom(sampleRate),
cpu(cpu)
{
}
Audio::~Audio(void) {
PaError err = Pa_StopStream(stream);
checkPaError(err);
err = Pa_Terminate();
checkPaError(err);
}
void Audio::apuInit(void) {
PaError err = Pa_Initialize();
checkPaError(err);
err = Pa_OpenDefaultStream(
&stream,
0, /* no input channels */
2, /* stereo output */
paFloat32, /* 32 bit floating point output */
(int) sampleRate, /* sample rate */
256, /* frames per buffer */
apuCallback, /* callback */
this); /* pointer passed to callback */
checkPaError(err);
err = Pa_StartStream(stream);
checkPaError(err);
}
// Computes one sample. Stores it in lastSampleLeft and
// lastSampleRight. Automatically advances the stored time.
void Audio::tick(void) {
float outLeft = 0.0;
float outRight = 0.0;
// TODO confirm how mixing works
float channelOne = pulses[0].tick() / (15.0 * N_UNITS);
if (cpu->audio_terminals & CHANNEL_1_LEFT) {
outLeft += channelOne;
}
if (cpu->audio_terminals & CHANNEL_1_RIGHT) {
outRight += channelOne;
}
float channelTwo = pulses[1].tick() / (15.0 * N_UNITS);
if (cpu->audio_terminals & CHANNEL_2_LEFT) {
outLeft += channelTwo;
}
if (cpu->audio_terminals & CHANNEL_2_RIGHT) {
outRight += channelTwo;
}
float channelThree = custom.tick() / (15.0 * N_UNITS);
if (cpu->audio_terminals & CHANNEL_3_LEFT) {
outLeft += channelThree;
}
if (cpu->audio_terminals & CHANNEL_3_RIGHT) {
outRight += channelThree;
}
// SO2
float mixerLeftVolume = (((cpu->audio_volume >> 4) & 0x7) + 1) / 16.0;
outLeft *= mixerLeftVolume;
// SO1
float mixerRightVolume = ((cpu->audio_volume & 0x7) + 1) / 16.0;
outRight *= mixerRightVolume;
lastSampleLeft = outLeft;
lastSampleRight = outRight;
time += timeStep;
}
void Audio::frameTick() {
for (int pulse_i = 0; pulse_i < N_PULSE_UNITS; pulse_i++) {
pulses[pulse_i].frameTick();
}
custom.frameTick();
}