-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patht85apu.h
More file actions
239 lines (212 loc) · 7.79 KB
/
t85apu.h
File metadata and controls
239 lines (212 loc) · 7.79 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
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
233
234
235
236
237
238
239
/*
t85apu.h
Part of the ATtiny85APU emulation library
Written by alexmush
2024-2024
*/
#ifndef __T85APU_H__
#define __T85APU_H__
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C"
{
#endif
/*
The T85APU_REGWRITE_BUFFER_SIZE define sets the size of the register write buffer. If it is 0 or less (or undefined), then the register write buffer size is decided when initializing the t85APU.
*/
#if T85APU_REGWRITE_BUFFER_SIZE < 1
#undef T85APU_REGWRITE_BUFFER_SIZE
#endif
typedef struct __t85apu {
// Replica of internal RAM
uint16_t noiseLFSR;
uint16_t envPhaseAccs[2];
uint16_t smpPhaseAccs[2];
uint8_t envStates[2];
uint8_t envShape;
uint8_t dutyCycles[5];
uint16_t noiseXOR;
uint8_t volumes[5];
uint8_t channelConfigs[5];
uint16_t envLdBuffer;
uint8_t increments[8];
uint16_t shiftedIncrements[8]; // This is simplified
uint8_t octaveValues[7];
// Replica of registers
// Phase accumulators
uint16_t tonePhaseAccs[5];
uint16_t noisePhaseAcc;
uint8_t envSmpVolume[4];
uint8_t noiseMask;
uint8_t envZeroFlg;
// Compile-time options
uint_fast8_t outputType;
uint_fast8_t outputBitdepth;
uint_fast16_t outputDelay;
// Sample rate converter
uint_fast16_t clockCycle; // 0..511, on 0 an update is invoked
double ticksPerClockCycle;
double ticks; // Reset when updated to keep precision
uint_fast8_t quality; // 0 - no interpolation/alialising, 1 - averaging of outputs per sample
bool outPending;
uint32_t * resamplingBuffer;
// Output
uint16_t channelOutput[5];
uint32_t currentOutput;
uint32_t outputQueue[3]; // Only really applies to the PWM output
// Emulator-only options
bool channelMute[5];
// Shift register emulation
#ifdef T85APU_REGWRITE_BUFFER_SIZE
uint16_t shiftRegister[T85APU_REGWRITE_BUFFER_SIZE];
#else
uint16_t * shiftRegister;
size_t shiftRegSize;
#endif
size_t shiftRegCurIdx;
} t85APU;
/**
* @name T85APU_OUTPUT defines
* Output types for t85APU.
* @todo make this an enum lmao
*/
///@{
/**
* @brief Output type for t85APU: emulates the PWM output from the @c OUT pin as an 8-bit DAC.
*/
#define T85APU_OUTPUT_PB4 0
/**
* @brief Output type for t85APU: emulates the PWM output from the @c OUT pin as the exact PWM (at the rate of (t85APU's clock / 256)). Can take more CPU time.
*/
#define T85APU_OUTPUT_PB4_EXACT 1
///@}
/**
* @name t85APU functions
* Functions interacting with the t85APU.
*/
///@{
#ifdef T85APU_REGWRITE_BUFFER_SIZE
/**
* @brief Creates a new instance of t85APU
*
* @param clock The master clock speed of the t85APU, in Hz. If not set (i.e. 0), will default to 8000000 - 8MHz.
* @param rate The output sample rate of the t85APU, in Hz. If not set (i.e. 0), will default to (clock / 512).
* @param outputType The output type of the t85APU. Use the @c T85APU_OUTPUT_XXX defines above to select the output type.
* @return The pointer to the newly created instance of t85APU. Returns a null pointer if an error has occured.
*/
t85APU * t85APU_new (double clock, double rate, uint_fast8_t outputType); // Automatically resets it
#else
/**
* @brief Creates a new instance of t85APU
*
* @param clock The master clock speed of the t85APU, in Hz. If not set (i.e. 0), will default to 8000000 - 8MHz.
* @param rate The output sample rate of the t85APU, in Hz. If not set (i.e. 0), will default to (clock / 512).
* @param outputType The output type of the t85APU. Use the @c T85APU_OUTPUT_XXX defines above to select the output type.
* @param shiftRegisterSize The size of the register write buffer. Has to be at least 1.
* @return The pointer to the newly created instance of t85APU. Returns a null pointer if an error has occured.
*/
t85APU * t85APU_new (double clock, double rate, uint_fast8_t outputType, size_t shiftRegisterSize);
#endif
/**
* @brief Deletes the instance of t85APU from memory.
*
* @param apu The t85APU instance to delete.
*/
void t85APU_delete (t85APU * apu);
/**
* @brief Resets all internal variables of the t85APU to their default initalization state - effectively the same as pulling the @c /RESET pin low on real hardware.
* @note This does NOT clear the register write buffer as it is considered emulated external hardware. This also does not reset the settings of the t85APU (clock speed, sample rate, output type, quality and muting).
*
* @param apu The t85APU instance to reset.
*/
void t85APU_reset (t85APU * apu);
/**
* @brief Sets clock speed and sample rate of the t85APU.
*
* @param apu The t85APU instance to set the clock speed and sample rate for.
* @param clock The master clock speed of the t85APU, in Hz. If not set (i.e. 0), will default to 8000000 - 8MHz.
* @param rate The output sample rate of the t85APU, in Hz. If not set (i.e. 0), will default to (clock / 512).
*/
void t85APU_setClocknRate (t85APU * apu, double clock, double rate);
/**
* @brief Sets the output type of the t85APU.
*
* @param apu The t85APU instance to set the output type for.
* @param outputType The output type of the t85APU. Use the @c T85APU_OUTPUT_XXX defines above to select the output type.
*/
void t85APU_setOutputType (t85APU * apu, uint_fast8_t outputType);
/**
* @brief Sets the sample rate converter quality.
*
* @param apu The t85APU instance to set the quality of the sample rate converter for.
* @param quality The quality setting
* @li 0 makes the immediate output of the t85APU the final output. Takes less CPU time, but has alialising issues.
* @li 1 averages all of the outputs in that tick and makes that the final output. Takes more CPU time, but doesn't have alialising issues.
*/
void t85APU_setQuality (t85APU * apu, uint_fast8_t quality);
/**
* @brief Pushes data onto the register write buffer of the t85APU.
*
* @param apu The t85APU instance to push the register write onto.
* @param addr The register number to write to.
* @param data The data to write to the register.
*/
void t85APU_writeReg (t85APU * apu, uint8_t addr, uint8_t data);
/**
* @brief Calculates 1 sample and return its raw value.
*
* @param apu The t85APU instance.
* @return The raw value of the sample, depends on the bitdepth of the output mode.
*/
uint32_t t85APU_calc (t85APU * apu);
/**
* @brief Calculates 1 sample and return its sample value mapped to unsigned 16-bit limits.
*
* @param apu The t85APU instance.
* @return The sample value, mapped from its raw value to 0..65535.
*/
uint16_t t85APU_calcU16 (t85APU * apu);
/**
* @brief Calculates 1 sample and return its sample value mapped to unsigned 15-bit limits.
*
* @param apu The t85APU instance.
* @return The sample value, mapped from its raw value to 0..32767.
*/
int16_t t85APU_calcS16 (t85APU * apu);
/**
* @brief Calculates 1 sample and return its sample value mapped to unsigned 16-bit limits.
*
* @param apu The t85APU instance.
* @return The sample value, mapped from its raw value to 0..4294967295.
*/
uint32_t t85APU_calcU32 (t85APU * apu);
/**
* @brief Calculates 1 sample and return its sample value mapped to unsigned 31-bit limits.
*
* @param apu The t85APU instance.
* @return The sample value, mapped from its raw value to 0..2147483647.
*/
int32_t t85APU_calcS32 (t85APU * apu);
/**
* @brief Tells you whether the register write buffer has at least one write pending.
*
* @param apu The t85APU instance.
* @return true if there is at least one write pending.
* @return false if there are no writes pending (aka the buffer is completely empty).
*/
bool t85APU_shiftRegisterPending (t85APU * apu);
/**
* @brief Enables or disables channel muting in the total output of @c t85APU_calcXXX functions.
*
* @param apu The t85APU instance to change the muting settings of.
* @param channel The channel to mute/unmute.
* @param mute The mute setting. @c true means to mute the channel, @c false means to unmute it.
*/
void t85APU_setMute(t85APU * apu, uint_fast8_t channel, bool mute);
///@}
#ifdef __cplusplus
}
#endif
#endif