6Bit audio:

Using, learning, programming and modding the Gigatron and anything related.
Forum rules
Be nice. No drama.
at67
Site Admin
Posts: 647
Joined: 14 May 2018, 08:29

6Bit audio:

Post by at67 »

I've been meaning to experiment with 6Bit audio for over 2 years now; I finally got around to it...

I've added some experimental code to my emulator to enable/disable 6Bit audio mode on the fly with the audio editor, (CTRL+A). This lets you see/hear the stark contrast in quality between 4Bit and 6Bit mode. Try it with a running .gtMID file and you'll get an idea.

The way that it works, is that it patches the native ROM to output the full 6Bit mixed sample, instead of the normal truncated 4Bit mixed sample. The code changes were fairly trivial and I will document them here later, but there are some caveats:

1) It only works with ROMv5a and DEVROM currently, seeing as it is an experimental feature this seems appropriate.

2) You lose the ability to control the two most significant LED's and these same LED's now respond to the 2 lower order bits of the 6bit mixed output sample.

3) It is currently emulation only, I will be building a tiny daughter board that replaces the SIL resistor pack soon and testing these 6Bit theories on real hardware, (it will need bodge wires for the 2 LED outputs and power as well).

4) You can experiment in the Audio Editor in the new MIDI section and in .gbas code using the '_enable6BitAudioEmu_ <ON/OFF>' pragma. Neither modes do anything unless you are running ROMv5a or DEVROM.

5) You can hear as well see as the difference in audio quality; I always wondered why Marcel went to the trouble of storing, fetching, mixing 6 bit samples and then truncating and outputting only the highest 4 bits. It's a shame there wasn't a simple configurable software switch to switch between 4Bits:4LEDS and 6Bits:2LEDS. This would have required a minor altercation to the board and a different SIP resistor pack, but all worth it IMHO.

Here's a few pics to get the drift:

4Bit:
Audio_4bit.JPG
Audio_4bit.JPG (128.28 KiB) Viewed 7141 times
6Bit:
Audio_6bit.JPG
Audio_6bit.JPG (99.33 KiB) Viewed 7141 times
Audio Editor:
Audio_Editor.JPG
Audio_Editor.JPG (75.63 KiB) Viewed 7141 times
Sugarplum
Posts: 93
Joined: 30 Sep 2020, 22:19

Re: 6Bit audio:

Post by Sugarplum »

Neat! That looks a bit cleaner. I would love to hear a comparison.
at67
Site Admin
Posts: 647
Joined: 14 May 2018, 08:29

Re: 6Bit audio:

Post by at67 »

Sugarplum wrote: 13 Jan 2021, 19:23 Neat! That looks a bit cleaner. I would love to hear a comparison.
Yeah it is much cleaner, visually and audibly, you can listen to the results in the emulator as well. Just click the 4Bit/6Bit button whilst a MIDI is playing and the quantisation noise difference is immediately obvious.

The signal to noise power formula is something like this from memory (1.76 + (6*n))dB where n is number of bits.

Code: Select all

    n = 4 gives 25.76dB
    n = 6 gives 37.76dB
    n = 8 gives 49.76dB
The human ear can discern the quantisation noise between n=4 and n=6 to a greater degree than between n=6 and n=8.
denjhang
Posts: 54
Joined: 02 May 2021, 01:25
Location: yuenan
Contact:

Re: 6Bit audio:

Post by denjhang »

I want to know how to implement 6-bit audio, and what changes need to be made on the hardware? , I am very interested in it. Because I use gigatron as a retro music player, and I will write some music for gigatron.
at67
Site Admin
Posts: 647
Joined: 14 May 2018, 08:29

Re: 6Bit audio:

Post by at67 »

denjhang wrote: 02 May 2021, 01:48 I want to know how to implement 6-bit audio, and what changes need to be made on the hardware? , I am very interested in it. Because I use gigatron as a retro music player, and I will write some music for gigatron.
You need to modify the ROM and obviously you need an expansion circuit to breakout the new 6bit/8bit audio. You can also experiment with my emulator that allows you to test 4bit/6bit mode with playback of MIDI's, using CTRL-A; or by using gtBASIC and the _enable6BitAudioEmu_ ON pragma, (only works when compiling and running your gtBASIC code from within the emulator).

*Note* you won't hear much of a difference using the default pulse/triangle/sawtooth waveforms, you need to load or draw your own waveform, (like a sine wave using the waveform editor), into waveform slot 2, (the default slot used by the MIDI playback code).

The ROM changes are kind of described here: https://github.com/at67/gigatron-rom/bl ... 67/cpu.cpp : line 639

ROMvX0 also has an 8bit audio path as well as the 6bit audio path I linked to above.

As far as hardware changes, the way I would do it would be to socket the XOUT register, (U38), and breakout the 8 data lines, CS, CLK, GND and 5V to a small PCB that plug's into the U38 socket. Then a cheap reasonably fast 8bit DAC that is simple to interface to an 8bit TTL bus like the TLC7524 or similar, followed by a rail to rail low noise single supply biased op-amp buffer and low pass filter outputting a standard 1vpp AC coupled audio signal.

This is the new emulator 6bit and 8bit audio code:

Code: Select all

    // Enable experimental 6bit and 8bit audio
    void enableAudioMode(RomType romType, AudioMode audioMode)
    {
        const std::vector<uint16_t> romv5aAddrs        = {0x0056, 0x012C, 0x015C, 0x01A6, 0x01A7, 0x02D6, 0x02D7};
        const std::vector<uint8_t>  romv5aOpcodes      = {0x00,   0x00,   0x00,   0x40,   0x20,   0x40,   0x20  };
        const std::vector<uint8_t>  romv5aOperands6bit = {0x03,   0x03,   0xFC,   0x03,   0xFC,   0x03,   0xFC  };
        const std::vector<uint8_t>  romv5aOperands8bit = {0x00,   0x00,   0xFF,   0x00,   0xFF,   0x00,   0xFF  };

        static bool firstTime = true;
        static std::map<uint16_t, uint8_t[2]> romv5aBackup;

        switch(romType)
        {
            case ROMv5a:
            case ROMvX0:
            case SDCARD:
            case DEVROM:
            {
                if(getRomType() < ROMv5a)
                {
                    if(audioMode > Audio4bit)
                    {
                        std::string romTypeStr;
                        getRomTypeStr(getRomType(), romTypeStr);
                        reportError(RomError, stderr, "\nCpu::enableAudioMode() : Error, ROM version must be >= ROMv5a, current ROM is %s\n", romTypeStr.c_str());
                    }
                    return;
                }

                if(firstTime) romv5aBackup.clear();

                for(uint16_t a=0x0130; a<=0x0147; a++)
                {
                    if(firstTime)
                    {
                        romv5aBackup[a][0] = _ROM[a][ROM_INST];
                        romv5aBackup[a][1] = _ROM[a][ROM_DATA];
                    }

                    switch(audioMode)
                    {
                        // Full LED pattern
                        case Audio4bit:
                        {
                            _ROM[a][ROM_INST] = romv5aBackup[a][0];
                            _ROM[a][ROM_DATA] = romv5aBackup[a][1];
                        }
                        break;

                        // LED pattern reduced to lower 2 LED's
                        case Audio6bit:
                        {
                            _ROM[a][ROM_INST] = 0x00;
                            _ROM[a][ROM_DATA] = a & 0x03;
                        }
                        break;

                        // No LED pattern
                        case Audio8bit:
                        {
                            _ROM[a][ROM_INST] = 0x00;
                            _ROM[a][ROM_DATA] = 0x00;
                        }
                        break;

                        default: break;
                    }
                }

                // Codes
                for(int i=0; i<int(romv5aAddrs.size()); i++)
                {
                    if(firstTime)
                    {
                        romv5aBackup[romv5aAddrs[i]][ROM_INST] = _ROM[romv5aAddrs[i]][ROM_INST];
                        romv5aBackup[romv5aAddrs[i]][ROM_DATA] = _ROM[romv5aAddrs[i]][ROM_DATA];
                    }

                    switch(audioMode)
                    {
                        case Audio4bit:
                        {
                            _ROM[romv5aAddrs[i]][ROM_INST] = romv5aBackup[romv5aAddrs[i]][0];
                            _ROM[romv5aAddrs[i]][ROM_DATA] = romv5aBackup[romv5aAddrs[i]][ROM_DATA];
                        }
                        break;

                        case Audio6bit:
                        {
                            _ROM[romv5aAddrs[i]][ROM_INST] = romv5aOpcodes[i];
                            _ROM[romv5aAddrs[i]][ROM_DATA] = romv5aOperands6bit[i];
                        }
                        break;

                        case Audio8bit:
                        {
                            _ROM[romv5aAddrs[i]][ROM_INST] = romv5aOpcodes[i];
                            _ROM[romv5aAddrs[i]][ROM_DATA] = romv5aOperands8bit[i];
                        }
                        break;

                        default: break;
                    }
                }

#if 0
                // LED mask
                _ROM[0x0056][ROM_INST] = 0x00;
                _ROM[0x0056][ROM_DATA] = 0x03;
        
                // LED mask
                _ROM[0x012C][ROM_INST] = 0x00;
                _ROM[0x012C][ROM_DATA] = 0x03;
        
                // Audio mask
                _ROM[0x015C][ROM_INST] = 0x00;
                _ROM[0x015C][ROM_DATA] = 0xFC;
        
                // LED mask
                _ROM[0x01A6][ROM_INST] = 0x40;
                _ROM[0x01A6][ROM_DATA] = 0x03;

                // Audio mask
                _ROM[0x01A7][ROM_INST] = 0x20;
                _ROM[0x01A7][ROM_DATA] = 0xFC;
        
                // LED mask
                _ROM[0x02D6][ROM_INST] = 0x40;
                _ROM[0x02D6][ROM_DATA] = 0x03;

                // Audio mask
                _ROM[0x02D7][ROM_INST] = 0x20;
                _ROM[0x02D7][ROM_DATA] = 0xFC;
#endif
                firstTime = false;
            }
            break;

            default: break;
        }
    }
denjhang
Posts: 54
Joined: 02 May 2021, 01:25
Location: yuenan
Contact:

Re: 6Bit audio:

Post by denjhang »

Thank you for your hint, I prefer 8-bit or even higher-quality audio to 6-bit audio.
Regarding the hardware transformation of 8-bit audio, can you show me the schematic diagram? I am not very skilled in the circuit, but I would like to try it.
at67
Site Admin
Posts: 647
Joined: 14 May 2018, 08:29

Re: 6Bit audio:

Post by at67 »

denjhang wrote: 02 May 2021, 13:08 Thank you for your hint, I prefer 8-bit or even higher-quality audio to 6-bit audio.
Regarding the hardware transformation of 8-bit audio, can you show me the schematic diagram? I am not very skilled in the circuit, but I would like to try it.
I'm sorry, I don't have the time to design a circuit and verify it, even if it is a simple one.

Maybe someone else can give it a go?
alastair
Posts: 68
Joined: 10 Oct 2019, 14:28

Re: 6Bit audio:

Post by alastair »

at67 wrote: 03 May 2021, 11:22 Maybe someone else can give it a go?
I can explain the delta: You would replace R9 with the 8-bit version - https://www.mouser.com/ProductDetail/bo ... QJlw%3D%3D

Pins 1-5 of the new R9 would remain unchanged, pin 10 would go to ground. The rest of the pins on the new R9 would map to U38 as follows: 6->2, 7->5, 8->6, 9->9. The output impedance of the new R9 is the same, so none of the filter components need to change.
denjhang
Posts: 54
Joined: 02 May 2021, 01:25
Location: yuenan
Contact:

Re: 6Bit audio:

Post by denjhang »

I will try and draw a simple circuit diagram.
lb3361
Posts: 360
Joined: 17 Feb 2021, 23:07

Re: 6Bit audio:

Post by lb3361 »

There might be a way to conciliate 6 bit audio with 4 blinkenlights. The idea is to piggy back the xout flip-flops with a board that mostly contains a 22r10 gal, the same kind I am using in my memory board. The 22r10 conveniently contains 10 flip-flops, that is 6+4. Whenever hsync strikes, we can latch the low 6 bits of the accumulator and use the high bits to incrementally update the 4 blinkenlights flip-flops. The gal can hold the logic for this. I can see two ways:

- turn off the 4 blinkenlights on vsync, then, at each hsync, turn on the one whose index is given by the high 2 bits of the accumulator. This requires bringing vsync to the piggy back board.

- at each hsync, do the following depending on the two high bits of the accumulator:
00 : do nothing
1x : left shift x into the 4 flip-flops
(led3<-led2<-led1<-led0<-x)

I wish I had socketed all my ICs...

- Leon
Post Reply