Page 2 of 3

Re: Sound bits

PostPosted: Mon Aug 09, 2010 10:06 pm
by jmetal88
I think I'm gonna take on the assembler version of this as a project. I'm still waiting on my PCjr keyboard to arrive, so I'll start it after I get that, when I'll be able to actually test the code.

I've had this book, Peter Abel's IBM PC Assembler Language and Programming, for ages and I've never done anything with it. I bet I can scrape together enough info skimming it to at least put together two simple COM files, one for turning sound on, and one for turning sound off.

Re: Sound bits

PostPosted: Thu Dec 30, 2010 12:27 am
by jmetal88
I said I was going to take on the assembler version of this, then completely forgot. :lol:

I found this listing in the PCjr Club Library archive today, though, and thought it might be of use.

Code: Select all

Subject: the Internal speaker


  The following will turn off the internal speaker.  I do it in my

AUTOEXEC.BAT I haven't found any programs that turn it back on

including basic.  This does also disallow use of cassette port.







xxxx:0100  push ds

xxxx:0101  mov ax,0000

xxxx:0104  push ax

xxxx:0105  in al,61

xxxx:0107  or ax,0010

xxxx:010A  out 61,al

xxxx:010C  int 20

xxxx:010E  (enter)





I haven't compared it to the sections of my assembly book that I was looking at, so I can't be sure it turns on the Tandy sound, but it looks like it might. It's similar to what I remember thinking about writing, anyway.

Re: Sound bits

PostPosted: Fri Jan 07, 2011 3:14 pm
by Retro
For comparison, here's a Forth version of Vorticon's TSOUND program.

Code: Select all

  130 C@ 32 OR [CHAR] s = IF
    13 ." SPEAKER NOW ACTIVE..." 
  THEN 97 PC! CR ;


Compiling it with ForthCMP 2.30S yields a COM executable of 184 bytes (cf. Turbo Pascal ~12k).

Re: Sound bits

PostPosted: Fri Jan 07, 2011 9:06 pm
by Vorticon
Nice :) Definitely beats the 12K bloatware! There is a nice version of Forth forthcoming (no pun intended) for the TI 99/4A which should revolutionize the way we program for that machine, and I'm looking forward to learning this interesting but rather odd language.

Re: Sound bits

PostPosted: Mon Jan 10, 2011 8:40 am
by deathshadow60
Vorticon wrote:I used Turbo Pascal 3. I did notice the large size for such a small program which really all it does is set the port bits, and it should not take that much space.

TP3 actually performs few optimizations and does NOT remove unused library code like later versions. It also puts the ENTIRE runtime library of functions in your .com file which adds about 6-7k of 'bloat' -- especially if you aren't using any of those functions. Compile the same code in TP7 (well, after fixing the compatibility bug on CHAR vs. STRING) and it comes in at 6k instead of the 13k it does in TP3.

It's actually one of the odd problems if dealing with TP on the x86 -- and most compilers for that matter -- the newer ones often make optimizations that let your code fit better onto lesser systems, while they themselves do not fit on those systems.

NOT that this is anything new in compilers -- it's long tradition that very rarely does anything low-level get written/compiled on the system it's for... see all those basic dialects for the 6809, 6502 and Z80 that Microsoft made almost entirely using ALTAIR's.

Like right now I'm developing with a 64k 8088 IBM 5150 CGA as my target, but I'm only using the real deal for testing while doing all my development using DosBox under Win7 on a i7 870. (and I'm editing all my code using Crimson editor native on the host machine)

Cheating? Maybe. But it's not like using a big expensive computer to develop for lesser machines is anything new.

Oh, and you CAN fit TP5.5 on a 360k floppy if you cut away the cruft. The .exe of 5.5 with the editor actually has most of the RTL units built into it. So long as you don't need graph or the TP3 legacy TPU's you're fine with just the .exe and .tpl file.

Re: Sound bits

PostPosted: Mon Jan 10, 2011 5:04 pm
by Vorticon
What are you developing?

Re: Sound bits

PostPosted: Mon Jan 10, 2011 7:06 pm
by deathshadow60
Vorticon wrote:What are you developing?

If that was directed at me, that would be my retrochallenge winter warm-up entry. ... -explained

Which is actually what led me to this site -- was searching for information about tandy sound AND on detecting PcJr/Tandy graphics, as I'm working on a sound module to go with the undocumented 160x100 mode ... I wasn't going to do sound until I realized that any game needs a good timer, and if you're gonna screw with the system timer you might as well go whole hog and do something with it while you're in there.

Right now I'm planning on a PC speaker driver for 3 voice square wave with 1 channel noise, 7 volume levels per channel (0..63 aka 6 bit output) -- pretty simple as I'm setting the timer to 18643khz (1/1024th the normal update) and then using the 8253's "interrupt on terminal count" mode on channel 2 to do the 'fake signal level' PWM stuff... but was thinking on Tandy hardware of using the in-built 3 channel voice data... I'm also probably going to output the synth to the soundblaster by just shifting the data two bits. (since I'm doing unsigned output).

Been a LONG time since I've played with the 8253 though.

MOST people usually try to set a frequency like 21096khz or thereabouts (PIT divider 54), but that isn't accurate for the system timer the machine either gaining or losing time while your code runs... Increasing the PIT divider to 64 drops the frequency to the edge of human hearing (which is bad) but makes the timer accurate (which is good). I could in theory go to a 32 divider for 37286.93khz, but that only leaves 127.92 clock cycles in-between sound output on a 4.77mhz system, and that's not enough to run the synth much less allow something like game code to run.

As it is even at that slow rate the result is going end up dragging the processor under like the video handler on a ZX-80.

Re: Sound bits

PostPosted: Wed Mar 09, 2011 3:00 pm
by Trixter
deathshadow60 wrote:MOST people usually try to set a frequency like 21096khz or thereabouts (PIT divider 54), but that isn't accurate for the system timer the machine either gaining or losing time while your code runs...

I don't follow you; can you explain this a bit more? Why would a non-power-of-two divisor make it not accurate?

Re: Sound bits

PostPosted: Thu Mar 10, 2011 7:39 am
by deathshadow60
Trixter wrote:I don't follow you; can you explain this a bit more? Why would a non-power-of-two divisor make it not accurate?

Because it doesn't divide evenly into the 18.2 whatever times a second the system clock expects it to fire. You have overflow/rounding differences with non power-of-two values. Even with the bit-width overflow method timer interrupts typically maintain you cannot get exactly 21096khz out of the timer.

Which is why many programs by the time of the 386 era started pulling the hardware time and syncing the software clock to that on exit.

Re: Sound bits

PostPosted: Thu Mar 10, 2011 8:39 am
by Trixter
My solution is easy: Don't call the 18.2 system routine :-)

For short bursts of calling the timer at 16K or higher for interfacing with hardware or playing digitized sound, where I really do need to hit my timer rate exactly without any interruptions, I don't even bother calling the system 18.2 routine. When my operation is complete, I calculate how many times the 18.2 system tick would have been called, and call it repeatedly until it's where it would have been had I not disabled it.

For ~1000 Hz or lower, where the length of the system 18.2 tick won't disrupt what I'm doing, I do this as part of the interrupt handler itself:

Code: Select all
  LongRec=packed record

{vars and setup code excluded for brevity, message me if you want the full source}

procedure MyHandler; Interrupt;
  {Perform actual interrupt operations here:}

  inc(PITCycles,Chan0Counter); {Keep track of how many PIT cycles have gone by}
  if longrec(PITCycles).hi <> 0 then begin {Did we roll over?  Is it time to call the 18.2Hz BIOS handler?}
    longrec(PITCycles).hi:=0; {Update our PIT cycles counter}
    asm pushf end; {simulate an interrupt by pushing flags, then CALLing handler in the statement below}
    BIOSTimerHandler; {this will acknowledge the interrupt}
    Port[$20] := $20; {send EndOfInterrupt to the PIC to ackn. the interrupt}