Sound: Difference between revisions

From WSdev Wiki
Jump to navigationJump to search
 
(12 intermediate revisions by the same user not shown)
Line 40: Line 40:
port $69            port $66
port $69            port $66
</pre>
</pre>
== Wavetable RAM ==
The wavetable RAM is an user-configurable 64-byte area of memory which stores four 16-byte waveforms. Each waveform contains 32 4-bit samples for the respective channel (from 1 to 4):
<pre>
Address $00 $01 $02 $03 $04 $05 $06 $07 $08 $09 $0A $0B $0C $0D $0E $0F
        98  CB  ED  FF  FF  EF  BD  8A  57  24  01  00  00  21  43  76
Sample
    15  ..  ..  ..  ##  ##  #.  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..
    14  ..  ..  .#  ||  ||  |#  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..
    13  ..  ..  #|  ||  ||  ||  #.  ..  ..  ..  ..  ..  ..  ..  ..  ..
    12  ..  .#  ||  ||  ||  ||  |.  ..  ..  ..  ..  ..  ..  ..  ..  ..
    11  ..  #|  ||  ||  ||  ||  |#  ..  ..  ..  ..  ..  ..  ..  ..  ..
    10  ..  ||  ||  ||  ||  ||  ||  #.  ..  ..  ..  ..  ..  ..  ..  ..
      9  .#  ||  ||  ||  ||  ||  ||  |.  ..  ..  ..  ..  ..  ..  ..  ..
      8  #|  ||  ||  ||  ||  ||  ||  |#  ..  ..  ..  ..  ..  ..  ..  ..
      7  ||  ||  ||  ||  ||  ||  ||  ||  #.  ..  ..  ..  ..  ..  ..  .#
      6  ||  ||  ||  ||  ||  ||  ||  ||  |.  ..  ..  ..  ..  ..  ..  #|
      5  ||  ||  ||  ||  ||  ||  ||  ||  |#  ..  ..  ..  ..  ..  ..  ||
      4  ||  ||  ||  ||  ||  ||  ||  ||  ||  #.  ..  ..  ..  ..  .#  ||
      3  ||  ||  ||  ||  ||  ||  ||  ||  ||  |.  ..  ..  ..  ..  #|  ||
      2  ||  ||  ||  ||  ||  ||  ||  ||  ||  |#  ..  ..  ..  .#  ||  ||
      1  ||  ||  ||  ||  ||  ||  ||  ||  ||  ||  #.  ..  ..  #|  ||  ||
      0  ||  ||  ||  ||  ||  ||  ||  ||  ||  ||  |#  ##  ##  ||  ||  ||
</pre>
Note that the ''higher'' bits - the first hexadecimal number - specify the ''later'' samples; that is to say, the nybbles of each sample are swapped relative to the wave drawing.
The current sample to be played (from 0 to 31) is selected by an internal sample index counter; there is no known way to reset this counter.


== I/O Ports ==
== I/O Ports ==
Line 54: Line 84:
</pre>
</pre>


This frequency is used for wavetable output. It is calculated as follows: <code>sample rate = 3072000 Hz / (2048 - divisor)</code>.
This value controls the sample period counters. Every <code>2048 - divisor</code> cycles, the index of the sample to be fetched from the wavetable is incremented; in addition, if noise is enabled, the state of the noise LFSR is advanced.


Note that this refers to the sample rate of the ''wavetable'', and needs to be scaled accordingly for a given waveform when performing music playback.
The resulting frequency is calculated as follows: <code>sample rate = 3072000 Hz / (2048 - divisor)</code>.
 
Note that this refers to the sample rate of each sample in the ''wavetable'', and needs to be scaled accordingly for a given waveform. For example, a 50% duty square wave (16 samples of <tt>0</tt> followed by 16 samples of <tt>15</tt>) will have an effective sample rate of <code>(3072000 / 32) Hz / (2048 - divisor)</code>, or <code> 96000 Hz / (2048 - divisor)</code>.


{{Anchor|Sound Channel Volume}}
{{Anchor|Sound Channel Volume}}
=== Sound Channel Volume ($88; $89; $8A; $8B) ===
=== Sound Channel Volume ($88; $89; $8A; $8B) ===


Line 85: Line 118:
</pre>
</pre>


This sample is used for voice output.
This sample is used for channel 2's voice output mode.


{{Anchor|Sound Channel 3 Sweep Amount}}
{{Anchor|Sound Channel 3 Sweep Amount}}
=== Sound Channel 3 Sweep Amount ($8C) ===
=== Sound Channel 3 Sweep Amount ($8C) ===


Line 173: Line 207:
Noise output works using the following algorithm, performed once per sample generated:
Noise output works using the following algorithm, performed once per sample generated:


# Create a new bit by XORing bit 7 with the tap bit.
# Create a new bit by inverting the XOR of bit 7 with the tap bit.
# Shift the LFSR register one bit to the left.
# Shift the LFSR register one bit to the left.
# Write the new bit as bit 0.
# Write the new bit as bit 0.
# Use the new bit as if it were a wavetable sample: 0 = 0, 1 = 15.
# Use the new bit as if it were a wavetable sample: 0 = 0, 1 = 15.
Note that, for the LFSR register to advance, all three of: the channel 4 enable bit, the channel 4 noise mode bit, and the LFSR enable bit have to be set.


{{Anchor|Sound Wavetable Address}}
{{Anchor|Sound Wavetable Address}}
=== Sound Wavetable Address ($8F) ===
=== Sound Wavetable Address ($8F) ===


Line 188: Line 225:
++++-++++- Wavetable address (bits 6-13)
++++-++++- Wavetable address (bits 6-13)
</pre>
</pre>
The wavetable is 4 x 16 bytes long; each 16-byte block contains 32 4-bit samples for the relevant channel:
<pre>
Address $00 $01 $02 $03 $04 $05 $06 $07 $08 $09 $0A $0B $0C $0D $0E $0F
        98  CB  ED  FF  FF  EF  BD  8A  57  24  01  00  00  21  43  76
Sample
    15  ..  ..  ..  ##  ##  #.  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..
    14  ..  ..  .#  ||  ||  |#  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..
    13  ..  ..  #|  ||  ||  ||  #.  ..  ..  ..  ..  ..  ..  ..  ..  ..
    12  ..  .#  ||  ||  ||  ||  |.  ..  ..  ..  ..  ..  ..  ..  ..  ..
    11  ..  #|  ||  ||  ||  ||  |#  ..  ..  ..  ..  ..  ..  ..  ..  ..
    10  ..  ||  ||  ||  ||  ||  ||  #.  ..  ..  ..  ..  ..  ..  ..  ..
      9  .#  ||  ||  ||  ||  ||  ||  |.  ..  ..  ..  ..  ..  ..  ..  ..
      8  #|  ||  ||  ||  ||  ||  ||  |#  ..  ..  ..  ..  ..  ..  ..  ..
      7  ||  ||  ||  ||  ||  ||  ||  ||  #.  ..  ..  ..  ..  ..  ..  .#
      6  ||  ||  ||  ||  ||  ||  ||  ||  |.  ..  ..  ..  ..  ..  ..  #|
      5  ||  ||  ||  ||  ||  ||  ||  ||  |#  ..  ..  ..  ..  ..  ..  ||
      4  ||  ||  ||  ||  ||  ||  ||  ||  ||  #.  ..  ..  ..  ..  .#  ||
      3  ||  ||  ||  ||  ||  ||  ||  ||  ||  |.  ..  ..  ..  ..  #|  ||
      2  ||  ||  ||  ||  ||  ||  ||  ||  ||  |#  ..  ..  ..  .#  ||  ||
      1  ||  ||  ||  ||  ||  ||  ||  ||  ||  ||  #.  ..  ..  #|  ||  ||
      0  ||  ||  ||  ||  ||  ||  ||  ||  ||  ||  |#  ##  ##  ||  ||  ||
</pre>
Note that the ''higher'' bits - the first hexadecimal number - specify the ''later'' samples; that is to say, the nybbles of each sample are swapped relative to the wave drawing.


{{Anchor|Sound Channel Control}}
{{Anchor|Sound Channel Control}}
Line 227: Line 238:
|||  |+--- Channel 3 enable
|||  |+--- Channel 3 enable
|||  +---- Channel 4 enable
|||  +---- Channel 4 enable
||+------- Channel 2 mode: 0 = wavetable, 1 = voice
||+------- Channel 2 voice enable (overrides wavetable enable)
|+-------- Channel 3 sweep: 0 = disable, 1 = enable
|+-------- Channel 3 sweep: 0 = disable, 1 = enable
+--------- Channel 4 mode: 0 = wavetable, 1 = noise
+--------- Channel 4 mode: 0 = wavetable, 1 = noise
</pre>
</pre>
Note that:
* Channel 1-4 enable bits also control whether or not the sample period counters are active.
* Channel 2's voice mode (bit 5) does not require channel 2's wavetable mode (bit 1) to be enabled.
* Conversely, Channel 4's noise mode (bit 7) ''does'' require channel 4's wavetable mode (bit 3) to be enabled.


{{Anchor|Sound Output Control}}
{{Anchor|Sound Output Control}}
=== Sound Output Control ($91) ===
=== Sound Output Control ($91) ===


Line 241: Line 259:
|    ||||
|    ||||
|    |||+- Internal speaker output enable
|    |||+- Internal speaker output enable
|    |++-- Internal speaker shift right value
|    |++-- Internal speaker shift/volume:
|    |      0 = 100%  1 = 50%
|    |      2 = 25%    3 = 12.5%
|    +---- Headphone output enable
|    +---- Headphone output enable
+--------- Headphones connected: 1 if true
+--------- Headphones connected, 1 if true
</pre>
</pre>


It is a good idea to set the internal speaker shift right value correctly. If the value is too low, multi-channel music will clip; if the value is too high, single-channel PCM sample playback will be very quiet.
For correct playback on the internal speaker, it is important to set the shift/volume correctly, to match the peak summed output of the first four channels. If the value is too low, music using multiple loud channels will wrap, causing audible distortion. If the value is too high, single-channel PCM sample playback will be very quiet.


{{Anchor|Sound Channel 4 LFSR Register}}
{{Anchor|Sound Channel 4 LFSR Register}}
=== Sound Channel 4 LFSR Register ($92, $93 read) ===
=== Sound Channel 4 LFSR Register ($92, $93 read) ===


Line 276: Line 297:


The <code>50% volume</code> have no effect if their respective <code>100% volume</code> bits are set.
The <code>50% volume</code> have no effect if their respective <code>100% volume</code> bits are set.
{{Anchor|Sound Test}}
=== Sound Test ($95) ===
<pre>
7  bit  0
---- ----
??5? llsh
  |  ||||
  |  |||+- Hold Ch1-4 output updates
  |  ||+-- Use 3072000 Hz CPU clock for sweep
  |  ++--- Hold noise LFSR output
  |        (Differences between bit 2/3
  |        behavior are unknown)
  +------- Force L10/R10 outputs to (channel 2 voice output * 5) & 0x3FF
</pre>


{{Anchor|Sound Channel Output Right}}
{{Anchor|Sound Channel Output Right}}
=== Sound Channel Output Right ($96, $97 read) ===
=== Sound Channel Output Right ($96, $97 read) ===


Line 309: Line 347:
       +++--++++-++++- Unsigned 11-bit sample
       +++--++++-++++- Unsigned 11-bit sample
</pre>
</pre>
{{Anchor|Sound Speaker Main Volume}}
=== Sound Speaker Main Volume ($9E) ===
<pre>
15  bit  8  7  bit  0
---- ----  ---- ----
.... ....  .... ..vv
                  ||
                  ++- Built-in speaker output volume
</pre>
Writing to this port changes the output volume of the built-in speaker.
While it functions the same way as the SOUND button (and affects the same internal register), pressing the SOUND button does ''not'' update this port's value. However, manual writes do, and those values can be read out.
This port does not affect the headphone output in any way, just like the SOUND button.
TODO: The exact volume levels have not been verified; it's probably either 0, 25, 50, 100% or 0, ~33, ~67, 100%.

Latest revision as of 20:32, 9 March 2025

The WonderSwan features the following sound hardware:

  • Four audio channels:
    • channel 1 - wavetable (32 x 4-bit samples),
    • channel 2 - wavetable or 8-bit unsigned PCM sample,
    • channel 3 - wavetable with optional hardware sweep,
    • channel 4 - wavetable or LFSR noise,
  • Hyper Voice(color) - headphone output exclusive 16-bit stereo PCM output,
  • 24000 Hz output:
    • internal speaker - 8-bit, mono,
    • headphone output - 16-bit, stereo.

Hyper Voice functionality is documented on its own sub-page.

Mixing diagram

The sound is mixed as follows:

      Ch1 Ch2 Ch3 Ch4                        Glossary: L = left, R = right, M = mono 
       |   |   |   |                                               Mnn = nn-bit mono
       8   8   8   8      port $98                            port $nn =  value port
       |   |   |   |       /
      _V___V___V___V_     /              _____          _____
     |               |--L10------+----->|     |        |     |
     |       +       |           |      |  +  |--M11-->| >>r |--M8--> Speaker output
     |_______________|--R10------|-+--->|_____|  /     |_____|
                        /       _|_|_           /     (r=0...3)
                       /       |     |         /        \
                  port $96     | <<5 |      port $9A     \
                               |_____|                    \
                                 | |                    port $91
                                 | |
port $68            port $64     | |
 /    _______________   \      __V_V__                  _____
L8-->| (Color only)  |--L16-->|       |----------L16-->|     |
     |  Hyper Voice  |        |  + +  |                | I2S |------> Headphone output
R8-->|_______________|--R16-->|_______|----------R16-->|_____|
 \                      /
port $69            port $66

Wavetable RAM

The wavetable RAM is an user-configurable 64-byte area of memory which stores four 16-byte waveforms. Each waveform contains 32 4-bit samples for the respective channel (from 1 to 4):

Address $00 $01 $02 $03 $04 $05 $06 $07 $08 $09 $0A $0B $0C $0D $0E $0F
         98  CB  ED  FF  FF  EF  BD  8A  57  24  01  00  00  21  43  76
 Sample
     15  ..  ..  ..  ##  ##  #.  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..
     14  ..  ..  .#  ||  ||  |#  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..
     13  ..  ..  #|  ||  ||  ||  #.  ..  ..  ..  ..  ..  ..  ..  ..  ..
     12  ..  .#  ||  ||  ||  ||  |.  ..  ..  ..  ..  ..  ..  ..  ..  ..
     11  ..  #|  ||  ||  ||  ||  |#  ..  ..  ..  ..  ..  ..  ..  ..  ..
     10  ..  ||  ||  ||  ||  ||  ||  #.  ..  ..  ..  ..  ..  ..  ..  ..
      9  .#  ||  ||  ||  ||  ||  ||  |.  ..  ..  ..  ..  ..  ..  ..  ..
      8  #|  ||  ||  ||  ||  ||  ||  |#  ..  ..  ..  ..  ..  ..  ..  ..
      7  ||  ||  ||  ||  ||  ||  ||  ||  #.  ..  ..  ..  ..  ..  ..  .#
      6  ||  ||  ||  ||  ||  ||  ||  ||  |.  ..  ..  ..  ..  ..  ..  #|
      5  ||  ||  ||  ||  ||  ||  ||  ||  |#  ..  ..  ..  ..  ..  ..  ||
      4  ||  ||  ||  ||  ||  ||  ||  ||  ||  #.  ..  ..  ..  ..  .#  ||
      3  ||  ||  ||  ||  ||  ||  ||  ||  ||  |.  ..  ..  ..  ..  #|  ||
      2  ||  ||  ||  ||  ||  ||  ||  ||  ||  |#  ..  ..  ..  .#  ||  ||
      1  ||  ||  ||  ||  ||  ||  ||  ||  ||  ||  #.  ..  ..  #|  ||  ||
      0  ||  ||  ||  ||  ||  ||  ||  ||  ||  ||  |#  ##  ##  ||  ||  ||

Note that the higher bits - the first hexadecimal number - specify the later samples; that is to say, the nybbles of each sample are swapped relative to the wave drawing.

The current sample to be played (from 0 to 31) is selected by an internal sample index counter; there is no known way to reset this counter.

I/O Ports

Sound Channel Frequency ($80, $81; $82, $83; $84, $85; $86, $87)

15  bit  8  7  bit  0
 ---- ----  ---- ----
 .... .ddd  dddd dddd
       |||  |||| ||||
       +++--++++-++++- Frequency divisor

This value controls the sample period counters. Every 2048 - divisor cycles, the index of the sample to be fetched from the wavetable is incremented; in addition, if noise is enabled, the state of the noise LFSR is advanced.

The resulting frequency is calculated as follows: sample rate = 3072000 Hz / (2048 - divisor).

Note that this refers to the sample rate of each sample in the wavetable, and needs to be scaled accordingly for a given waveform. For example, a 50% duty square wave (16 samples of 0 followed by 16 samples of 15) will have an effective sample rate of (3072000 / 32) Hz / (2048 - divisor), or 96000 Hz / (2048 - divisor).

Sound Channel Volume ($88; $89; $8A; $8B)

7  bit  0
---------
llll rrrr
|||| ||||
|||| ++++- Right channel volume (0-15)
++++------ Left channel volume (0-15)

This volume is used for wavetable output.

The calculation to get an unsigned 8-bit sample out of a 4-bit wavetable sample / 4-bit volume pair is simple: out_sample = sample * volume. This means that the maximum sample in wavetable output mode is 15 * 15 = 225.

Sound Channel 2 Voice Sample ($89)

7  bit  0
---- ----
ssss ssss
|||| ||||
++++-++++- Unsigned 8-bit PCM sample (0-255)

This sample is used for channel 2's voice output mode.

Sound Channel 3 Sweep Amount ($8C)

7  bit  0
---- ----
vvvv vvvv
|||| ||||
++++-++++- Value; 8-bit, signed.

This port is used for wavetable output with sweep enabled.

The signed value in this port will be added to the frequency divider for channel 3 every sweep step (as determined by the Sweep Ticks port). Wraparound is present - adding 1 to a frequency divider value of 2047 will cause it to roll over back to 0.

Sound Channel 3 Sweep Ticks ($8D)

7  bit  0
---- ----
...t tttt
   | ||||
   +-++++- Ticks per step - 1

This port is used for wavetable output with sweep enabled.

Every ttttt + 1 ticks, clocked at 375 Hz, the value in the Sweep Amount port will be added to the frequency divider for channel 3.

Sound Channel 4 Noise Control ($8E)

7  bit  0
---- ----
...e rttt
   | ||||
   | |+++- LFSR tap mode
   | +---- LFSR reset: 1 = reset shift register
   +------ LFSR enabled: 0 = off, 1 = on

This port is used for noise output.

List of LFSR tap modes
Tap mode Tap bit Sequence length
0 14 32767
1 10 1953
2 13 254
3 4 217
4 8 73
5 6 63
6 9 42
7 11 28

Noise output works using the following algorithm, performed once per sample generated:

  1. Create a new bit by inverting the XOR of bit 7 with the tap bit.
  2. Shift the LFSR register one bit to the left.
  3. Write the new bit as bit 0.
  4. Use the new bit as if it were a wavetable sample: 0 = 0, 1 = 15.

Note that, for the LFSR register to advance, all three of: the channel 4 enable bit, the channel 4 noise mode bit, and the LFSR enable bit have to be set.

Sound Wavetable Address ($8F)

7  bit  0
---- ----
wwww wwww
|||| ||||
++++-++++- Wavetable address (bits 6-13)

Sound Channel Control ($90)

7  bit  0
---- ----
nsv. 4321
|||  ||||
|||  |||+- Channel 1 enable
|||  ||+-- Channel 2 enable
|||  |+--- Channel 3 enable
|||  +---- Channel 4 enable
||+------- Channel 2 voice enable (overrides wavetable enable)
|+-------- Channel 3 sweep: 0 = disable, 1 = enable
+--------- Channel 4 mode: 0 = wavetable, 1 = noise

Note that:

  • Channel 1-4 enable bits also control whether or not the sample period counters are active.
  • Channel 2's voice mode (bit 5) does not require channel 2's wavetable mode (bit 1) to be enabled.
  • Conversely, Channel 4's noise mode (bit 7) does require channel 4's wavetable mode (bit 3) to be enabled.

Sound Output Control ($91)

7  bit  0
---- ----
H... hrrs
|    ||||
|    |||+- Internal speaker output enable
|    |++-- Internal speaker shift/volume:
|    |      0 = 100%   1 = 50%
|    |      2 = 25%    3 = 12.5%
|    +---- Headphone output enable
+--------- Headphones connected, 1 if true

For correct playback on the internal speaker, it is important to set the shift/volume correctly, to match the peak summed output of the first four channels. If the value is too low, music using multiple loud channels will wrap, causing audible distortion. If the value is too high, single-channel PCM sample playback will be very quiet.

Sound Channel 4 LFSR Register ($92, $93 read)

15  bit  8  7  bit  0
 ---- ----  ---- ----
 .rrr rrrr  rrrr rrrr
  ||| ||||  |||| ||||
  +++-++++--++++-++++- Shift register value

Sound Channel 2 Voice Volume ($94)

7  bit  0
---- ----
.... lLrR
     ||||
     |||+- Right channel 100% volume
     ||+-- Right channel 50% volume
     |+--- Left channel 100% volume
     +---- Left channel 50% volume

This port is used for voice output.

The 50% volume have no effect if their respective 100% volume bits are set.

Sound Test ($95)

7  bit  0
---- ----
??5? llsh
  |  ||||
  |  |||+- Hold Ch1-4 output updates
  |  ||+-- Use 3072000 Hz CPU clock for sweep
  |  ++--- Hold noise LFSR output
  |        (Differences between bit 2/3
  |        behavior are unknown)
  +------- Force L10/R10 outputs to (channel 2 voice output * 5) & 0x3FF

Sound Channel Output Right ($96, $97 read)

15  bit  8  7  bit  0
 ---- ----  ---- ----
 .... ..ss  ssss ssss
        ||  |||| ||||
        ++--++++-++++- Unsigned 10-bit sample

Sound Channel Output Left ($98, $99 read)

15  bit  8  7  bit  0
 ---- ----  ---- ----
 .... ..ss  ssss ssss
        ||  |||| ||||
        ++--++++-++++- Unsigned 10-bit sample

Sound Channel Output Sum ($9A, $9B read)

15  bit  8  7  bit  0
 ---- ----  ---- ----
 .... .sss  ssss ssss
       |||  |||| ||||
       +++--++++-++++- Unsigned 11-bit sample

Sound Speaker Main Volume ($9E)

15  bit  8  7  bit  0
 ---- ----  ---- ----
 .... ....  .... ..vv
                   ||
                   ++- Built-in speaker output volume

Writing to this port changes the output volume of the built-in speaker.

While it functions the same way as the SOUND button (and affects the same internal register), pressing the SOUND button does not update this port's value. However, manual writes do, and those values can be read out.

This port does not affect the headphone output in any way, just like the SOUND button.

TODO: The exact volume levels have not been verified; it's probably either 0, 25, 50, 100% or 0, ~33, ~67, 100%.