Some features of the music coprocessor
ZXNet echo conference «music.zx»
From Ivan Roshin → To All 7 December 2000
Hello, All!
═══════════════════ mus_sopr.1 ══════════════════
(c) Ivan Roshchin, Moscow
Fido: 2:5020/689.53
ZXNet: 500:95/462.53
E-mail: asder_ffc@softhome.net
WWW: http://www.zx.ru/echo/roschin
Some features of the music coprocessor
─────────────────────── ────────────────────────
("Radio Amateur. Your Computer" 11/2000)
(under the pseudonym BV_Creator)
1. Necessary explanations
This article is written based on materials previously posted
me to the ZX.SPECTRUM conference, and based on the subsequent
these discussions, in which Vadik Akimoff, Roman took part
Panteleyev and Ilya Vinogradov. I thank them for their help! Also
thanks to Alexey Letaev, who helped me purchase
AY music coprocessor and provided access to Fido and the Internet.
The information given in the article was checked by me on two
copies of coprocessors YM2149F (Yamaha, Japan) 1990 and 1992
years of manufacture and on the AY38910A/P coprocessor (Microchip, Taiwan).
2. Change in volume when adding sounds of the same frequency
Exploring the capabilities of the music editor 'Pro Tracker 3'
From Ivan Roshin → To All 7 December 2000
Hello, All!
═══════════════════ mus_sopr.2 ══════════════════
Apparently, in "on interrupt" melodies, i.e. when
the music coprocessor is programmed 50 times per second, with
nothing can be done about the occurrence of a phase difference. overcome
the problem is only possible with the help of “digital sound”, when the program
directly sets the output signal level
coprocessor at any time, without using
tone generators (i.e. the coprocessor operates in DAC mode). Maybe
maybe someone can write one based on this principle
"on interrupt" music player?
I don’t know how this problem is dealt with in different
Spectrum emulators/AY emulators. It is quite possible that there
no phase difference occurs (which means the music sounds better than
on the real Spectrum!). As the famous Spectrum writer wrote:
musician EA/Antares, "you can't emulate a chip in software
along with its glitches."
At the same time, for sounds using only the envelope
or just noise, it is quite possible to manipulate the volume,
including sound in one, two or three channels at once. The point is that
tone generators in the coprocessor are unique for each channel, and
envelope and noise generators exist in a single
instance, so when using them, the phase differences are simply
nowhere to come from.
A┼ A┼ A┼│ │ │ ┌─┐ ┌─┐ ┌─
│ + │ = │ │ │ │ │ │
│ ┌─┐ ┌─┐ ┌─ │ ┌─┐ ┌─┐ ┌─ │ ┌┘ └┐ ┌┘ └┐ ┌┘
│ ┌┘ └┐ ┌┘ └┐ ┌┘ │ ┌┘ └┐ ┌┘ └┐ ┌┘ │ │ │ │ │ │
└─┴───┴─┴───┴─┴──> └─┴───┴─┴───┴─┴──> └─┴───┴─┴───┴─┴──>
t t t
This opportunity is even more valuable if
take into account that the volume of sounds obtained using
envelope cannot be controlled any other way.
3. Extraneous sounds when changing the sound frequency
This unpleasant effect was again discovered when studying
features of the 'Pro Tracker' editor. Let's install it in this editor
frequency table "SOUNDTRACKER" and create the following sample:
┌──────────────────── ────────────────────┐
│ EDIT SAMPLE 01 │
│ ▒00 000 -0004 00 T-E ███████████████ F │
│ ▒01 000 -0003 00 T-E ███████████████ F │
Now let's try what the note B-4 ('M' key) will sound like.
Compare its sound with the sound of other notes. Well, did you hear?
As I managed to find out, when playing this note
the coprocessor alternately outputs sound at a frequency corresponding to
division factor #0100 (hereinafter referred to as sound #0100) and sound #00FF.
There is 1/50 of a second between two changes in sound frequency.For definiteness, let's assume that the sound is output in channel B.
The frequency division ratio for this channel is set in
registers R2 (low byte) and R3 (high byte). Since
access to the coprocessor registers occurs in turn, and Pro
Tracker first changes register R2, and then R3, when changing
value #00FF to #0100, this is what happens:
R3 R2
00 FF ;initial value #00FF
00 00 ;changed R2 - got #0000
01 00 ;changed R3 - got #0100
When changing back:
R3 R2
01 00 ;initial value #0100
01 FF ;changed R2 - got #01FF
00 FF ;changed R3 - got #00FF
It can be seen that at certain times the value of the divisor
frequency turns out to be #0000 and #01FF, and somehow this
leads to the appearance of extraneous sounds.
I tried changing the register values in a different order,
by writing a small program in assembly language. Let it when necessary
go from sound #00FF to #0100, register R3 changes first, and
when you need to go from #0100 to #00FF, the register is changed first
R2:
Method 1
────────
R3 R2
00 FF ;initial value #00FF01 FF ;changed R3 - got #01FF
01 00 ;changed R2 - got #0100
01 00 ;initial value #0100
01 FF ;changed R2 - got #01FF
00 FF ;changed R3 - got #00FF
In this case, the extraneous value of the frequency divider is only
#01FF, but the situation did not improve. Let it now
on the contrary, when you need to go from sound #00FF to #0100, the first
register R2 changes, and when you need to go from #0100 to #00FF,
Register R3 is changed first:
Method 2
────────
R3 R2
00 FF ;initial value #00FF
00 00 ;changed R2 - got #0000
01 00 ;changed R3 - got #0100
01 00 ;initial value #0100
00 00 ;changed R3 - got #0000
00 FF ;changed R2 - got #00FF
The extraneous value of the frequency divider in this case is equal to
#0000, but the sound did not improve. Then I tried to ban
output the tone frequency for the duration of the change in R2 and R3, and then -
allow. For this, register R7 (mixer) is used. Three
The least significant bits of this register control the output of the tone frequency in
channels A, B and C (0 - output enabled, 1 - disabled), and three
The most significant bits similarly control the noise output.
════════════════════════ ════════════════════════Best regards, Ivan Roshchin.
[ZX] [BestView 3.0 - 26%]
From Ivan Roshin → To All 7 December 2000
Hello, All!
═══════════════════ mus_sopr.3 ══════════════════
Method 3
────────
R7 R3 R2
%00111000 00 FF ;initial value #00FF
%00111010 00 FF ;tone frequency output disabled
%00111010 00 00 ;changed R2 - got #0000
%00111010 01 00 ;changed R3 - got #0100
%00111000 01 00 ;allowed tone frequency output
But at the same time some crackling appeared, which also
unpleasant, although better than in the previous case. Then I
I tried this: set the divisor value in channel A
frequencies #0100, in channel B - #00FF, and then switch these
channels by controlling the mixer. Since at the same time
tone frequency output is allowed in one channel and disabled in
friend, the sound should have been better...
Method 4
────────
R7 R3 R2 R1 R0
%00111001 00 FF 01 00 ;A - disabled, B - enabled
%00111010 00 FF 01 00 ;A - enabled, B - disabled
The sound, however, only got worse. So, none of the four
The considered methods failed to solve the problem.
Let's try to figure it out in more detail. What do we have? When
alternating sounds #00FF and #0100, outsiders become audible
overtones (instead of a smooth transition). Obviously, a significant rolethis is played by the fact that #00FF and #0100 are different, and
and the most significant byte, which means the frequency divider when moving from
one sound to another acquires extraneous meanings (#0000
and #01FF). After all, if you alternate sounds that differ only in
one byte (for example, #00FE and #00FF), no overtones
arises.
Let's make a generalization: when alternating any sounds that have
frequency dividers differ in both the low and high bytes, they must
extraneous sounds arise. As a result of the experiment this
the assumption is confirmed. You can check it yourself
sound pairs #01FF and #0200, #02FF and #0300 ... #0EFF and #0F00
(the frequency divider value is limited to #0FFF).
As the values increase, the overtones become less noticeable, but
don't disappear at all. Difference between two alternating values
does not have to be single - overtones will appear when
alternating sounds #00FE and #0101.
It is clear that this reduces the usability
music coprocessor. Musicians know about this unpleasant
phenomenon - after all, they don’t use similar alternations of sounds
in your works!
When alternating sounds with frequency dividers
differ in both the low and high bytes, the frequency divider will be
acquire extraneous meanings. It's clear that this is happening
because it is impossible to instantly change the values of two at oncecoprocessor registers. And if it were possible, then no
there would be no extraneous sounds...
Of course, one could completely refuse to use
tone generator, with all the problems associated with the installation
the frequency divider values for this generator would disappear on their own
yourself. We use digital sound - that's all! The quality is perfect!
Yes, but this will require absolutely all the resources of the Z80, which we
not satisfied at all.
Well, let's look into it further. Firstly, can
general appearance of extraneous dividers for a very short time
Do frequencies have any effect on the sound? You and I know
what can it do, and how! But let's see what he says about this
theory...
The tone generator in the music coprocessor works quite well
simple: there is a counter whose value is sequential
decreases, and as soon as it decreases to zero, the level
the output signal changes, and the value from
frequency divider registers. Thus, they are formed
rectangular pulses:
A ┼
│
├────┐ ┌────┐ ┌────┐ ┌────┐ ┌───
│ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │
└────┴────┴────┴────┴── ──┴────┴────┴────┴────>
tIt follows from this that while the counter is not 0, the change
Frequency divider registers should not affect the sound.
But if the counter is reset at the moment when in the registers
the frequency divider contains an extraneous value, this is undoubtedly
will affect the sound. Let's try to calculate the probability of this
events.
Let the frequency divider value change from #0100 to #00FF,
the interval between changing the frequency divider registers is
50 Z80 cycles (it is during this period that the divider
frequency will take on an extraneous value #01FF), clock
Z80 frequency is 3.5 MHz, and coprocessor clock speed is
1.75 MHz.
When the frequency divider is #0100, the tone generator generates
sound with the following frequency:
(1750000/16)/256 = 427.2 Hz
The tone generator counter is reset accordingly
twice as often, with a frequency of 854.4 Hz. Let's count how many cycles Z80
goes between two counter reboots:
3500000/854.4 = 4096
Then the probability that the counter will be rebooted is
at the moment when the frequency divider is equal to #01FF, it is equal to:
50/4096 = 0.012
As we can see, the probability that the tone generator will do although
at least one half-cycle with an extraneous frequency, very small - barely
more than 1%. But we hear extraneous sounds with 100% probability!Something is wrong here. Maybe the frequency counter is rebooting
immediately when writing a new value to the frequency divider registers?
════════════════════════ ════════════════════════
Best regards, Ivan Roshchin.
[ZX] [BestView 3.0 - 26%]
From Ivan Roshin → To All 7 December 2000
Hello, All!
═══════════════════ mus_sopr.4 ══════════════════
If this is so, the appearance of extraneous sounds becomes
understandable. Consider the waveform as the divider changes
frequencies from #0100 to #00FF:
A ┼
│
├────┐ ┌──┐┌────┐ ┌────┐ ┌────┐
│ │ │ ││ │ │ │ │ │
│ │ │ ││ │ │ │ │ │
│ │ │ ││ │ │ │ │ │
└────┴────┴──┴┴────┴── ──┴────┴────┴────┴───>
xy t
At first, the frequency divider was equal to #0100 - that is, R3=#01,
R2=#00. Let at the moment of register change R2 the output be
high signal level, as shown in the graph. At point x
#FF is written to R2 - the frequency divider receives extraneous
value #01FF, frequency counter reboots, signal level
changes from high to low. At point y #00 is written in R3 -
frequency divider became equal to #00FF, frequency counter
reboots, the signal level changes from low to high.
Due to these two differences in signal level with very small
Apparently, the interval between them is where the overtones appear.
I had no way to check whether
The output of the coprocessor produces a signal of exactly the same shape as
on the chart. Then I did it differently: using "digitalsound", tried to reproduce the signal shown on the graph and
appreciate its sound. As you would expect, the sound
turned out to be the same as when using a tone generator, with
the same extraneous sounds. From this we can conclude,
that for the values considered in the example, the frequency counter
reloads immediately when writing a new value to the registers
frequency divider.
By the way, it’s easy to check by ear that the frequency counter
the envelope also reboots immediately when installing a new one
envelope frequency divider (it is set in registers R11 and R12).
Here's a way to check: if you enter the envelope shape into the register
(R13) value %1000 (gradual decrease in signal level from
15 to 0 in each period of the envelope), and in registers R11, R12
enter #FFFF (so that the envelope period is maximum), to
The output of the coprocessor will be this:
A ┼
│ │ │\n
│ │ │ \n
│ │ │ \n
│ │ │ \n
│ │ │ \n
└──────────────────>
<──T──> t
Envelope frequency: F = (1750000/256)/#FFFF = 0.1043 Hz.
Envelope period: T = 1/F = 9.59 s.
That is The envelope frequency counter is reset every
9.59/16 = 0.6 seconds (this is for the AY coprocessor, and on the YM the counterwill reboot twice as often - 32 steps are formed there
envelope instead of 16). If we assume that the counter is rebooting,
only when it decreases to zero will we have to admit that
no matter how the value of registers R11, R12 changes, the sound
will change only after 0.6 seconds - and when holding
experiment, the sound changed instantly!
The maximum frequency divider value was chosen because
that with this value the counter reset time is also
maximum, and one can confidently distinguish the two by ear
possible cases - when the sound changes instantly, and when
it changes after the counter is reset. For smaller values
frequency divider experiments were not carried out.
In various Spectrum emulators/AY emulators, how
I know that the counter is rebooted only when it is
zeroed, so the sound produced is different from the sound
real coprocessor (for example, when changing the frequency divider from
#0100 to #00FF no extraneous sounds will be heard). You can
it would be fair to say that the coprocessor sounds better under the emulator
real - but there is no benefit from it, no one
will write music exclusively for listening to
emulator. But the bad side of inaccurate emulation is obvious -
anyone who writes music under an emulator can allow
such changes in the frequency of sounds that on a real coprocessorwill be played with extraneous sounds.
4. Determining the type of music coprocessor
In the eighth issue of the electronic newspaper 'KrNews' I read that
you can programmatically distinguish the type of used
coprocessor - AY or YM, and that such a check was in the demo
'ACTION'. True, the method of definition in this newspaper is not
described. In the process of studying the specified demo, I discovered
the following code snippet:
#8021: LD BC,#FFFD
LD A,0
OUT (C),A ;set R0
LD B,#BF
LD A,#40 ;wrote #40 to R0
OUT(C),A
LD B,#FF
IN A,(C) ;read from R0
CP #40 ;read what you wrote down?
JR Z,#803B ;yes -> there is a coprocessor.
LD HL,#84FA ;message address "NO"
JR #804E ;go to proc. print messages
#803B: LD BC,#FFFD
LD A,#10
OUT (C),A ;set to "undocumented"
;register R16
IN A,(C) ;read from it
CP #FF ;compare with #FF
LD HL,#84E6 ;message address "AY-8910/12"
JR NZ,#804E ;not #FF -> display this message.
LD HL,#84F0 ;message address "YM2149F"#804E: ............ ;proc. print message
Thus, if you try to read the content
"undocumented register", then YM will always read
#FF. And on AY, as I found out during experiments, the number will be read
register (in this example - number #10).
If the coprocessor is connected in such a way that its registers are not accessible
for reading, the test will show the absence of a coprocessor.
════════════════════════ ════════════════════════
Best regards, Ivan Roshchin.
[ZX] [BestView 3.0 - 26%]