Page 1 of 1

TRS80 model 3 sound

Posted: Wed Jun 02, 2021 12:38 am
by voidstar
Greetings,

I'm trying to do sound on a TRS-80, like in the game Eliminator for that platform.

I figured out sound for the Commodore and Apple, but I'm not seeing any notes for the TRS-80.

There are some manuals about TRS-80 BASIC that referenced a BEEP and SOUND command. But in the trs80gp.exe emulator, these commands didn't work (syntax error on both). Not that I want to use BASIC, but if the programming manuals suggest the system can perform sound (and even has a note/frequency chart), I'm not quite sure why those commands aren't working. And as mentioned, the game Eliminator has a few sound effects.

z88dk has worked great for me in compiling for the TRS-80 target, with very little change in my C code. I looked in libsrc/target/trs80 for any sound related examples, but didn't not see any.

Thanks for any help to point me in the right direction on this :)

Re: TRS80 model 3 sound

Posted: Wed Jun 02, 2021 10:03 am
by voidstar
I was able to make it work in cc65 with the sample below. I looked into USR(ARGS), disassembled that, which seems to be: load what is in 4121h into HL...
// e7 rst 0x20
// 2a2141 ld hl,(0x4121) == 16673 dec (load content at 0x4121 into HL)
// f8 ret m

But I made the adjustment to by-pass all that, and just directly load values into HL (which you can POKEW directory into that address).

....
// Based on BASIC sample referenced here:
// http://www.trs-80.com/wordpress/zaps-pa ... elanguage/

#define AUDIO_BASE 0xFACE
POKE(AUDIO_BASE , 33); // 0x21 LD HL
POKE(AUDIO_BASE+1, 0); // H placeholder (POKE here)
POKE(AUDIO_BASE+2, 0); // L placeholder (POKE here)
POKE(AUDIO_BASE+3, 77); // 4D ld c,l
POKE(AUDIO_BASE+4, 68);
POKE(AUDIO_BASE+5, 62);
POKE(AUDIO_BASE+6, 1);
POKE(AUDIO_BASE+7, 105);
POKE(AUDIO_BASE+8, 211);
POKE(AUDIO_BASE+9, 255);
POKE(AUDIO_BASE+10, 45);
POKE(AUDIO_BASE+11, 32);
POKE(AUDIO_BASE+12, 253);
// -----------------------
POKE(AUDIO_BASE+13, 60);
POKE(AUDIO_BASE+14, 105);
POKE(AUDIO_BASE+15, 211);
POKE(AUDIO_BASE+16, 255);
POKE(AUDIO_BASE+17, 45);
POKE(AUDIO_BASE+18, 32);
POKE(AUDIO_BASE+19, 253);
POKE(AUDIO_BASE+20, 13);
POKE(AUDIO_BASE+21, 16);
POKE(AUDIO_BASE+22, 238);
POKE(AUDIO_BASE+23, 175);
POKE(AUDIO_BASE+24, 211); // D3
POKE(AUDIO_BASE+25, 255); // FF
POKE(AUDIO_BASE+26, 201); // C9 RET

#asm
call AUDIO_BASE
#endasm

for (v = 1027; v >= 755; --v)
{
POKEW(AUDIO_BASE+1, v);

#asm
call AUDIO_BASE
#endasm
}
...

Re: TRS80 model 3 sound

Posted: Wed Jun 02, 2021 4:41 pm
by stefano
that poke sequence is creating a z80 machine code routine looping around the out (ff) instruction. I think that the existing z88dk functions are already built to work on that port.
Could you try the examples provided in the "sound" folder? are they all failing?

Re: TRS80 model 3 sound

Posted: Thu Jun 03, 2021 2:42 am
by voidstar
Oh - I'm not using any of the standard library and didn't notice the sound.h in the include folder :) I do recall a note that z88dk does include quite a bit of extra stuff in its library, although I wasn't sure how much of it applied to the TRS80.

So now I tried those sound folder samples - I'm not sure if bit_click() is working, but yes synth_play(xxx) and bit_synth(xxx) are working (with trs80gp emulator, ran as: trs80gp -m3 test.cmd -dx ). Nice examples, very cool.

However,

I think synth_phase/synth_play(xxx) is taking about 2387 bytes,

and bit_synth(xxx) is taking about 1041 bytes.


The POKE example earlier takes under 100 bytes and does provide a bit of audio range. But you just have to find a "safe" place to POKE it into - I wasn't sure of the 26 bytes after 0xFACE was "safe" (it's working for using trs80gp.exe -m3 -dx, but not sure if it's just coincidence).


Thanks for pointing out the samples! Now have a variety of sound options.

Re: TRS80 model 3 sound

Posted: Fri Jun 04, 2021 8:15 pm
by stefano
The bit_fx functions are smaller, the example program looks big because it uses them all together and includes the console output code.

Re: TRS80 model 3 sound

Posted: Fri Jun 04, 2021 8:27 pm
by stefano
Your function can be simply put in a code frame in C,

e.g. something like:

void mysound() {
#asm
defb 33,0,0, ...
#endasm
}

Re: TRS80 model 3 sound

Posted: Sat Jun 05, 2021 9:50 am
by voidstar
Yes, I considered that - except then it's harder to know the offset of where to POKE to adjust the H/L register values (and obviously you don't want the overhead of passing an argument). Some C compilers have the &&label option ("address of a label") but I don't think that worked for me in z88dk (it's not exactly a standard feature in some compilers). Or you can take the address of the function itself (except for me, I think z88dk also had some issue on the syntax for that -- I can't remember the specific issue I had; probably I was just tired and gave up too easily since the POKE option was working).

So poking an word at AUDIO_BASE+1 works out. You're right, the function-style would be better to make it just a natural part of whatever code-space your program uses. Then you POKE, something like:

void mysound() {..}

POKEW(&mysound+2, val); // Think that's what I tried initially, but just seems z88dk required me to cast &mysound somehow, or maybe define a function pointer typedef?

Re: TRS80 model 3 sound

Posted: Sat Jun 05, 2021 2:03 pm
by stefano
you may have noticed the #asm directive, labels and mnemonics are allowed ;)

Re: TRS80 model 3 sound

Posted: Sun Jun 06, 2021 7:32 pm
by dom
To take the address of a function it's pretty standard:

```
extern int test();

int main() {
void *ptr = test;
....
}
```

For what features are available for which target, <features.h> is useful and is driven by this spreadsheet: https://github.com/z88dk/z88dk/blob/mas ... atures.csv