-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathREADME.txt
More file actions
262 lines (193 loc) · 10.9 KB
/
README.txt
File metadata and controls
262 lines (193 loc) · 10.9 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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
MDSynth
FPGA-based synthesizer system for the Xilinx Spartan-3A and Spartan-3E Starter Kits
Author: Daniel Cliche
Copyright (c) 2011-2022, Daniel Cliche. All rights reserved.
License: BSD for the sound synthesizer chip *only*, GPL for the complete 6809-based synthesizer system.
Languages: VHDL, 6809 assembly, C
============================================================
1. Overview
============================================================
The sound chip includes a delta-sigma DAC and two numerically-controlled oscillators. It has been integrated in a 6809-based system with keyboard support and video display output. The conversion from MIDI pitch to phase delta per clock with octave value is done by the 6809-based system for flexibility.
Four types of waveform are available:
- Square (fixed gain)
- Sawtooth (fixed gain)
- Sine (variable gain)
- Phase modulation (variable gain, similar to frequency modulation but easier to implement)
In phase modulation, the gains for both oscillators are applied without multiplications with the help of logarithmic and exponential tables. The technique is described below.
============================================================
2. Complete synthesizer as a 6809-based system
============================================================
Adaptation of the excellent System09 project by John E. Kent
http://members.optushome.com.au/jekent/system09/
2.1 6809 Toolset
================
All the source files of the toolset are provided. The following is provided:
- A 6809 assembler (tools/as09);
- A C compiler (tools/mc09);
- S19 to VHDL (tools/s19tovhd) for producing the ROM file.
- A text to binary converter (tools/txt2bin) for converting the text file containing 8-bit values from the simulator output to raw 8-bit data for inspection in Audacity.
The S19 file is to be uploaded to the board using a serial terminal at 57600-N-8-1 (see the installation section). The ROM contains the SYS09BUG utility available under "src/sys09bug" which perform the download of the file over the serial port.
The chain is the following:
"C" -- [ C compiler ] --> "ASM" -- [ 6809 assembler ] --> "S19" -- [ Serial upload with SYS09BUG ROM ] --> FPGA Block RAM Memory
The C compiler based on the public domain Micro-C is tiny (around 3K lines of code in a single file) and is quite impressive for its size. Obviously, no optimization is done and everything is done in a single pass, so there is no separation between data and code. It also only implement a subset of the C language.
If you plan to use this tiny C compiler, please read the README file located the project for known limitations and issues I encountered.
2.2. Sound Chip Addresses
=========================
Four sound chip channels are available at the following base addresses:
- 0xE080 Channel 0
- 0xE090 Channel 1
- 0xE0A0 Channel 2
- 0xE0B0 Channel 3
Write:
Base + 0: bits 2 downto 0: Waveform (0x00: DAC direct, 0x01: Square, 0x02: Sawtooth, 0x03: Sine, 0x04: Phase Modulation, 0x05: Noise)
bit 7: Note ON/OFF for PM and Noise (0: OFF, 1: ON)
Base + 1: Message Octave (4-bit) + Phase Delta MSB (4-bit)
Base + 2: Phase Delta LSB (8-bit)
Base + 3: Carrier Octave (4-bit)
Base + 4: Message Gain (6-bit, 63=1.0, sine and phase modulation only)
Base + 4: bits 5 downto 0: Message Gain (6-bit, sine and PM only)
bits 7 downto 6: Waveform Message (0: Full sine (++--), 1: Half sine (++00), 3: Full sine positive (++++), 4: Quarter sine positive (+0+0))
Base + 5: bits 5 downto 0: Modulated Gain (6-bit, PM only)
bits 7 downto 6: Waveform Modulated (0: Full sine (++--), 1: Half sine (++00), 3: Full sine positive (++++), 4: Quarter sine positive (+0+0))
Base + 5: Modulated Gain (6-bit, 63=1.0, phase modulation only)
Base + 6: DAC direct value (8-bit, DAC direct only)
Base + 7: bits 3 downto 0: Attack Rate (0xF: fastest)
bits 7 downto 4: Release Rate (0xF: fastest)
Base + 8 .. Base + 15: Reserved
Read:
Base + 0: bits 1 downto 0: Envelope Phase (0x0: Idle, 0x1: Attack, 0x2: Sustain, 0x3: Release)
Refer to section 4.1 for more details about the 12-bit phase delta value to provide to the NCO along with the 4-bit octave value.
2.3. Installation
=================
1. Compile the tools located in "src/tools" using the Visual C++ 2015 project.
2. Open a command prompt, go the the "src/synth" directory and execute "make". This command will produce the "synth.s19" file to upload.
3. Connect a VGA monitor to the synthesizer (your Xilinx Spartan 3A-Starter Kit board);
4. Connect a PS/2 keyboard to the synthesizer;
5. Connect speakers to the synthesizer;
6. Connect a serial cable to the synthesizer;
7. Program the FPGA by creating a projet with the files under the "rtl" folder;
8. Start a serial terminal at 57600-N-8-1;
9. On the serial terminal or on the synthesizer itself at the SYS09BUG prompt, type "l";
10. Upload the text file "src/synth/synth.s19" or "src/synthpoly/synth.s19" for the monophonic or polyphonic synthesizer respectively using your serial terminal;
11. At the SYS09BUG prompt, type "CTRL-P" to set the program counter;
12. Type "1000" (this is the starting address of the synthesizer project);
13. Type "g". You will see the user interface on the monitor of your synthesizer system;
14. Follow the on-screen instructions in order to play and change parameters;
15. Press the South button in order to go back to the SYS09BUG prompt.
2.2. Audio Outputs and MIDI I/O
===============================
2.2.1. Spartan-3A
=================
- Standard audio output connector of the board;
- Auxiliary audio ouput on J18, pins AA21 and AB21 being left and right channels respectively.
- MIDI Input on J18, pin AA19
- MIDI Output on J18, pin AB19
2.2.2. Spartan-3E
=================
- Main audio output on J1, pins B4 and A4 being left and right audio channels respectively;
- Auxiliary audio output on J2, pins A6 and B6 being left and right audio channels respectively.
- MIDI Input on J2, pin E7
- MIDI Output on J2, pin F7
You will need a RC filter at the output in order to see the waveform with an oscilloscope. Refer to the Xilinx application note 154 for more details about the DAC.
2.3. MIDI Interface
===================
The synthesizer is able to receive the MIDI note on/note off events from a MIDI device. Here's the schematic of a MIDI IN interface:
+--6N138--+
MIDI IN [4] ----- 220 -----------------[2] [8]--------------- VCC 3.3V
| | | |
1N4148 | | 220
| | | |
MIDI IN [5] ---------------------------[3] [6]--------------- FPGA MIDI INPUT
| |
| [5]--- GND
+---------+
============================================================
3. Test benches
============================================================
The test benches include a subset of the source files in order to quicky test some components of the synthesizer.
3.1. Channel Test Bench
=======================
Description
-----------
The pitch requested from the channel is increasing over time from 0 to 127.
See section 2.2 for details about the audio outputs.
This test has a single voice with a single channel per voice. Each channel has a pitch control and a waveform selection. The same channel is connected to both the left and right audio outputs.
Waveform selection
------------------
SW0 SW1 SW2 Waveform
--- --- --- --------
0 0 0 None
0 1 0 Square (message only)
1 0 0 Sawtooth (message only)
1 1 0 Sine (message only)
0 0 1 Phase Modulation
In phase modulation mode, press the north button for Note ON (Note: button not debounced).
Pitch
-----
The pitch is MIDI compatible. The value is between 0 and 127, 69 being A4 at 440Hz.
============================================================
4. Implementation Notes
============================================================
4.1 NCO
=======
I am using an numerically-controlled oscillator (NCO) in order to produce a phase value used as an index of the sine table.
pitch 69 (A4) will require the following: octave=6, note=9
The desired frequencies for octave 6 are the following:
note freq (Hz)
0 261.63 (C4)
1 277.18
2 293.66
3 311.13
4 329.63
5 349.23
6 369.99
7 392.00
8 415.30
9 440.00 (A4)
10 466.16
11 493.88
The frequency given to NCO is the following:
freq = (50E6 * (phase_delta * 2^octave)) / 2^32
phase_delta = freq * 2^32 / (50E6 * 2^octave)
4.2 Phase Modulation
====================
The formula is the following: y(t) = modulated_gain * sin(pi*m(t) + 2*pi*octave_carrier*freq*t)
where m(t) = message_gain * sin(2*pi*octave_message*freq*t)
4.3 Monophonic Pitch Stack
==========================
The synthesizer has currently only a single voice, but we need to keep track of all notes being held in order to always play the latest held note, if any. In order to achieve this, a stack is used, the tip of the stack being the currently played pitch. When a note is release, the corresponding entry is removed from the stack. The first element of the stack has a pitch of zero (quiet).
4.4 Gain Calculation without Multiplications
============================================
It is possible to use only additions for the gain calculation using this method:
We know that:
log(e^a * e^b) = log(e^(a+b)) = a + b
If gain = e^a and sine = e^b, we have:
log(gain * sine) = log(gain) + log(sine)
gain*sine = e^(log(gain) + log(sine))
We want the gain*sine result using lookup tables as shown here:
result(gain, phi) = exptable(loggain(gain) + logsine(phi));
The following will produce the tables for a 8-bit quarter cycle (copy and paste in GNU Octave):
f1 = 64;
logsine_size = 65;
loggain_size = 64;
exptable_size = (f1/32)*(256 + 256);
wave_max = 127;
logsine = abs(round(f1 * log(sin(linspace(0, pi/2, logsine_size))))); logsine(1) = 256 * (f1/32) - 1;
loggain = abs(round(f1 * log(linspace(0, 1, loggain_size)))); loggain(1) = 256 * (f1/32) - 1;
exptable = round(wave_max * exp(linspace(0, exptable_size - 1, exptable_size)/ -f1));
# In order to compare the 8-bit result (blue) with a full-resolution sine (red):
gain = 1.0
hold off
plot(exptable(logsine + loggain(loggain_size * gain) + 1), "b");
hold on
plot(gain * wave_max * sin(linspace(0, pi/2, logsine_size)), "r");
hold off
# output to CSV files
csvwrite("logsine.csv", logsine);
csvwrite("loggain.csv", loggain);
csvwrite("exptable.csv", exptable);
============================================================
5. Limitations and Known Issues
============================================================
- Decay and sustain level not yet implemented for the envelope;
- Gain for modulated signal is currently not used in phase modulation.