1 // ---------------------------------------------------------------------------
2 // This file is part of reSID, a MOS6581 SID emulator engine.
3 // Copyright (C) 2004 Dag Lem <resid@nimrod.no>
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 // ---------------------------------------------------------------------------
19
20 #define __VOICE_CC__
21 #include "voice.h"
22
23 // ----------------------------------------------------------------------------
24 // Constructor.
25 // ----------------------------------------------------------------------------
Voice()26 Voice::Voice()
27 {
28 set_chip_model(MOS6581);
29 }
30
31 // ----------------------------------------------------------------------------
32 // Set chip model.
33 // ----------------------------------------------------------------------------
set_chip_model(chip_model model)34 void Voice::set_chip_model(chip_model model)
35 {
36 wave.set_chip_model(model);
37
38 if (model == MOS6581) {
39 // The waveform D/A converter introduces a DC offset in the signal
40 // to the envelope multiplying D/A converter. The "zero" level of
41 // the waveform D/A converter can be found as follows:
42 //
43 // Measure the "zero" voltage of voice 3 on the SID audio output
44 // pin, routing only voice 3 to the mixer ($d417 = $0b, $d418 =
45 // $0f, all other registers zeroed).
46 //
47 // Then set the sustain level for voice 3 to maximum and search for
48 // the waveform output value yielding the same voltage as found
49 // above. This is done by trying out different waveform output
50 // values until the correct value is found, e.g. with the following
51 // program:
52 //
53 // lda #$08
54 // sta $d412
55 // lda #$0b
56 // sta $d417
57 // lda #$0f
58 // sta $d418
59 // lda #$f0
60 // sta $d414
61 // lda #$21
62 // sta $d412
63 // lda #$01
64 // sta $d40e
65 //
66 // ldx #$00
67 // lda #$38 ; Tweak this to find the "zero" level
68 //l cmp $d41b
69 // bne l
70 // stx $d40e ; Stop frequency counter - freeze waveform output
71 // brk
72 //
73 // The waveform output range is 0x000 to 0xfff, so the "zero"
74 // level should ideally have been 0x800. In the measured chip, the
75 // waveform output "zero" level was found to be 0x380 (i.e. $d41b
76 // = 0x38) at 5.94V.
77
78 wave_zero = 0x380;
79
80 // The envelope multiplying D/A converter introduces another DC
81 // offset. This is isolated by the following measurements:
82 //
83 // * The "zero" output level of the mixer at full volume is 5.44V.
84 // * Routing one voice to the mixer at full volume yields
85 // 6.75V at maximum voice output (wave = 0xfff, sustain = 0xf)
86 // 5.94V at "zero" voice output (wave = any, sustain = 0x0)
87 // 5.70V at minimum voice output (wave = 0x000, sustain = 0xf)
88 // * The DC offset of one voice is (5.94V - 5.44V) = 0.50V
89 // * The dynamic range of one voice is |6.75V - 5.70V| = 1.05V
90 // * The DC offset is thus 0.50V/1.05V ~ 1/2 of the dynamic range.
91 //
92 // Note that by removing the DC offset, we get the following ranges for
93 // one voice:
94 // y > 0: (6.75V - 5.44V) - 0.50V = 0.81V
95 // y < 0: (5.70V - 5.44V) - 0.50V = -0.24V
96 // The scaling of the voice amplitude is not symmetric about y = 0;
97 // this follows from the DC level in the waveform output.
98
99 voice_DC = 0x800*0xff;
100 }
101 else {
102 // No DC offsets in the MOS8580.
103 wave_zero = 0x800;
104 voice_DC = 0;
105 }
106 }
107
108 // ----------------------------------------------------------------------------
109 // Set sync source.
110 // ----------------------------------------------------------------------------
set_sync_source(Voice * source)111 void Voice::set_sync_source(Voice* source)
112 {
113 wave.set_sync_source(&source->wave);
114 }
115
116 // ----------------------------------------------------------------------------
117 // Register functions.
118 // ----------------------------------------------------------------------------
writeCONTROL_REG(reg8 control)119 void Voice::writeCONTROL_REG(reg8 control)
120 {
121 wave.writeCONTROL_REG(control);
122 envelope.writeCONTROL_REG(control);
123 }
124
125 // ----------------------------------------------------------------------------
126 // SID reset.
127 // ----------------------------------------------------------------------------
reset()128 void Voice::reset()
129 {
130 wave.reset();
131 envelope.reset();
132 }
133