Jump to content
IGNORED

Digitized Sound on Aquarius


Recommended Posts

Here is a copy of the waveforms. I am not sure if I have them perfectly aligned and when the signal level is changing very quickly, it may be quantization error, or slight timing differences.

 

post-20571-0-87236700-1329879977_thumb.jpg

 

Here is a view of the inital 84 samples, close to 450 microseconds.

 

post-20571-0-17141400-1329879992_thumb.jpg

 

Ok, yeah, that looks pretty balanced. And it would appear that there's actually both a high pass and a low pass filter. I forgot about the fact it probably blocks DC from the RF modulator. :-)

 

So does anyone have a link to a schematic? There is apparently one in the file area on the Yahoo group I'm not a member of.

 

Link to comment
Share on other sites

I pulled this schematic from the yahoo group...

 

ScanMEKO.PDF

 

Look at the PLA IC, the Cass Out is the sound output pin (they share a common port.) Anyway, the cass out heads through a 10k resistor and to the cassette output pin and also heads through what is labelled as a 4u7 capacitor (no voltage indicated) and then a 4k7 resistor. My guess is that the 4u7 is a 4.7 uf cap and a 4.7k resistor. If you follow the schematic, you'll find the common SND trace, which then goes to the #2 pin of the cartridge port (I am guessing that is how the miniexpander sends out its audio) and also goes to the modulator. The fun part here is that there is a 12V source routed through another 4K7 resistor (again, guessing 4.7k) and into the RF modulator.

 

I have no idea what happens inside the RF modulator, and no idea why an additional 12V source is needed.

 

Insight would be great, because if I had a continuous function to define the pulse response I would be in great shape. Right now I will have to use my sampled signals and adjust according to my target sample rates.

Link to comment
Share on other sites

First off... yes, 4K7 means 4.7K, and 4u7 means 4.7µ.

 

Ok, looking near J5, I see both a 10K and a "270E"... I suspect that's just a straight 270Ω resistor, so you have a 10.27KΩ resistor to ground on that path. And then there's the 4.7µF blocking capacitor.

 

If I remember my EE205, the resistance "seen" by the capacitance will be (10.27KΩ || (4.7KΩ + 4.7KΩ)) which is approx 4.9KΩ. The RC time constant, then should be about 0.023 seconds, or about 43Hz. That seems pretty decent for a DC blocking circuit, and it roughly jibes with the primary response in your graph. The overshoot suggests there's another large capacitor lurking about, perhaps in the modulator itself.

 

I assume the Aquarius uses a similar modulator to the Intellivision's UM1285. If so, this is its (rather unenlightening) datasheet: http://console5.com/techwiki/images/2/21/Astec_UM-1285-8.pdf

 

The 4.7KΩ pullup to +12V on the audio seems strange. Seems like this should actually be a pulldown, although either would work if there's a second blocking cap inside the RF modulator. The +12V rail may be cleaner than GND, too. You're tempting me to take a screwdriver to my Aquarius...

 

So, the schematic analysis doesn't really cover the high end response, though, which you measured at around 192kHz. That seems way to high a bandwidth to send over the air. I'm going to guess that the audio response is bandlimited further in the RF modulator, though. I couldn't find anything authoritative, but looking around, it appears that the audio channel for TV maxes out at around 15kHz maximum bandwidth. I guess the only way you'll really find out is to measure the full response from the Aquarius through a TV. Ick.

 

 

Link to comment
Share on other sites

These outputs are coming from my composite and audio mod (made for the Intellivision by the way) and so the audio is a tap off of the RF modulator input. (At least I think that is what it is...)

 

I obviously didn't pay enough attention to the time domain during my education because I am a bit lost. The other thing I don't know is if my sound card is doing anything to the signal during the digitization as well.

 

I can hook it up through the RF modulator into a TV and take the TV sound output, but who knows what they use for filtering there either.

 

My question is still this. If I know that the actual time-based output will simply be the summation of the high and low pulses, then can't I manipulate the input stream in order to minimize the error in the output stream.

 

My vision is to use the pulse responses, pick a sample optimization window (256 samples, or 1024 samples, 65536 samples) and then cycle through all possible combinations of 1's and 0's (2^256, 2^1024, 2^65536) calculating the time based response and comparing the sum of the differences to the target wave, settling in on the lowest signal error. Because the pulses would last much more than my optimization window, whatever residual energy that is left after my window would be utilized in the next optimization window.

 

The other direction that my mind reaches for is to figure out the circuit and determine the response in the frequency domain. After I have that, then somehow convolve (or otherwise manipulate) the target audio output to spit back out an optimized square wave. This is beyond my understanding, but I know that audio programs all work in the frequency domain for a reason - the math has to be easier. I'm not sure how well I will do trying to figure this all out in the time domain.

Link to comment
Share on other sites

I've been very busy recently with other obligations, so I don't have much to add at this point except to say that I'm delighted to see the progress and that I'm following your work with interest. I plan to learn more about sound myself once I can find the time: it's easy to underestimate the importance of great sound and music in a video game, but I think it's even more important than having great graphics in certain ways, and it's certainly more difficult to achieve.

Link to comment
Share on other sites

I see what you mean now about only having one filter. I tried to put the circuit we spoke about in the simulator:

 

post-20571-0-41875600-1330057209_thumb.jpg

 

And then sent a square wave into it:

 

post-20571-0-82835900-1330057216_thumb.jpg

 

Doesn't look like my samples...

 

Either something is happening in the RF Modulator, or my sound card, or in the Mod that I installed to put an RCA jack audio out!

 

Arrrrg...

Link to comment
Share on other sites

I see what you mean now about only having one filter. I tried to put the circuit we spoke about in the simulator:

 

post-20571-0-41875600-1330057209_thumb.jpg

 

And then sent a square wave into it:

 

post-20571-0-82835900-1330057216_thumb.jpg

 

Doesn't look like my samples...

 

Either something is happening in the RF Modulator, or my sound card, or in the Mod that I installed to put an RCA jack audio out!

 

Arrrrg...

 

Well, your simulated plot looks like a nice single-order exponential decay response. Your measured response looks like a second-order exponential response, given the overshoot.

 

In the end, I really don't think it matters. You point out that most folks do this in the frequency domain, and I think it's for good reason -- if you know what the frequency response of the system is, then all you need to reason about is the set of frequency spectra of what you're putting into the system and the frequency response of the system itself. Then, the frequency spectrum of the result is just a point-wise multiplication of the two.

 

Human ears aren't generally sensitive to phase shifts (although some research suggests that's less true at lower frequencies than at higher frequencies), so most of the time you can just look at the amplitude frequency response of the system and get a really good idea what's going to happen, as long as the system is a linear, time invariant system (which is your starting assumption). (Note, if you work with the full complex frequency response, you get amplitude and phase, but that's kinda overkill for the point I'm trying to make.)

 

You have a 1-bit linear channel. Your measurements show it's fairly linear--it can pull up as quickly as it pulls down--so you don't actually have any non-linear effects to worry about there. There's some DC blocking that will block frequencies below 40Hz or so, and on the RF path there's probably a low-pass filter to keep your bandwidth narrow for the audio subcarrier. (Gonna guess it'll keep you narrower than 15kHz.)

 

You're trying to modulate PCM data onto that channel. Given that it's fairly linear, then your main goal should be to keep any harmonics you introduce above the roll-off frequency of any low-pass filters in your system. Your audio-mod doesn't have much of a low-pass effect on it (you measured 190kHz or something like that), but there's always some point in the system that imposes a low-pass, even if it's just your ears. The best human ears are good up to around 20kHz or so. Most of us hear far less.

 

I don't think you need to resort to complex time-domain approaches, since they won't actually buy you much. You're not trying to implement an open-loop controller, establishing exact amplitudes on the output. You're trying to get audio information through in a manner that preserves its human-perceived fidelity.

 

If it were me, I'd consider implementing a high-rate sigma-delta modulator (also called delta-sigma modulator). More info here: https://en.wikipedia.org/wiki/Delta-sigma_modulation Sigma-delta is nice because the math is super simple, and the results are actually very good. A sigma-delta conversion loop looks something like this:

 

   foreach sample:
       if sample > error then
           output = max
           error  = error + max - sample
       else
           output = min
           error  = error + min - sample
       endif

 

I've attached some sample C code that shows how to do an SDM. Edit: Apparently I can't upload C files. I'll put it on my webserver here: http://spatula-city.org/~im14u2c/dl/sdm.c

 

I apologize if some of this is a rehash of stuff you already know and may have been already covered in this thread.

Edited by intvnut
Link to comment
Share on other sites

Continuing the thought on SDMs... the main point of considering an SDM is that you can make the modulation loop really fast. Then, any harmonics you introduce are going to be at and above the frequency of the SDM modulation loop.

 

The oversampling factor is what determines where the modulation noise begins to appear. You may recall CD players advertising ever increasing oversampling factors. They were using SDMs, more than likely. :-)

Link to comment
Share on other sites

My previous converter worked more like this, in 8-bit unsigned digital:

 

for each sample(n):
   if sample(n)>128 then
		 output(n)=1
		 sample(n+1)=sample(n+1)+.5*(sample(n)-output(n)*255)
   else
		 output(n)=0
		 sample(n+1)=sample(n+1)+.5*(sample(n)-output(n)*255)
   end if

 

I'm not sure how the Sigma Delta Modulator differs.

 

One of the things that I am concerned about, and I really cannot test it, is if I am sending output bits much too fast. I can send 170,000 output bits per second in my current player. I thought I had implemented something like Sigma Delta, it appears I was mistaken. I'll take a look at the C code you posted.

Link to comment
Share on other sites

It is always an incredible feeling when something finally CLICKS in your head. I cannot wait to get home to implement a Sigma Delta Modulator for my Aquarius.

 

Click! Click! Click! Click! Click! I just didn't understand.

 

I was trying to distribute the error like I would for a picture, but the SDM continually distributes the error from sample to sample to sample...

 

W00t! This is going to sound awesome.

 

And - it won't take 37 hours to convert one sample.

 

We'll see how it goes!

Link to comment
Share on other sites

One more.... Ok, it looks like from when I send a 1 out of the Aquarius to when we hit peak amplitude is 250 microseconds to 340 microseconds or a response time of 90 microseconds...

 

I know that my program execute time and the number of bits I am sending equates to roughly 170,000 samples per second.

 

That means that I am sending a sample every 5.8 microseconds - but if I do not get a response for 90 microseconds, aren't I over modulating?

Link to comment
Share on other sites

No, i

One more.... Ok, it looks like from when I send a 1 out of the Aquarius to when we hit peak amplitude is 250 microseconds to 340 microseconds or a response time of 90 microseconds...

 

I know that my program execute time and the number of bits I am sending equates to roughly 170,000 samples per second.

 

That means that I am sending a sample every 5.8 microseconds - but if I do not get a response for 90 microseconds, aren't I over modulating?

 

Assuming that the 90µs is the response time of the RC stuff outside the PLA, that should be fine. It *starts* switching, but the low-pass nature of the system will just integrate all your 1/0 changes into a slower-changing, smoother curve. This is exactly what you want in a SDM.

 

Now if the PLA only copies your input to the output every 90µs, then yeah, you have a problem. But, if I understood correctly, it switches when you write to it, and then the analog stuff just takes a while to charge/discharge fully. Like I said, that's exactly what you want.

 

EDIT: An example: Suppose you output a 85kHz signal (1,0,1,0,1,0,1,0). You should see the output on the PLA side of the blocking capacitor converge to 0.5. (On the other side of the blocking capacitor, it'll drop to 0.)

Edited by intvnut
Link to comment
Share on other sites

I wrote a converter (using Wikipedia and your c-code.) I know that it works because the 1 bit audio square wave file that I make sounds incredible...

 

But the actual audio still has an incredible amount of noise.

 

I have two theories.

 

One) Something isn't right with my player or encoder

Two) The electrical system noise in the Aquarius is VERY high and it is puking all over the output signal.

 

I wonder if there is some way I could filter/modify the input audio so that it compensates for the system noise...

 

Top is the sampled output after using the Sigma Delta converter and player through the Aquarius (from my audio out on my composite mod)

 

Bottom is a 400 Hertz Sine Wave

 

Doesn't seem so simple anymore. :(

 

post-20571-0-93621100-1330153894_thumb.jpg

Link to comment
Share on other sites

Does the Aquarius insert any wait states on the CPU during display fetches? On the Intellivision, that's the main problem we've run into in playing back digitized samples via the PSG: The display fetch pauses the CPU periodically, stretching out individual samples.

 

Also, you might try outputting a handful of "DC calibration" waveforms... one each at -1, -0.5, 0, 0.5, 1 just to see what happens. With the DC blocking cap in there, all 5 should look like DC, but I imagine -0.5, 0 and 0.5 (all three of which should have a fair bit of switching) will look rather different than -1 and 1 (neither of which should have any switching).

 

(By -1, -0.5, 0, 0.5 and 1, I really mean -32768, -16384, 0, 16383 and 32767, of course, if you consider signed 16 bit source samples like my SDM code used.)

Link to comment
Share on other sites

Does the Aquarius insert any wait states on the CPU during display fetches? On the Intellivision, that's the main problem we've run into in playing back digitized samples via the PSG: The display fetch pauses the CPU periodically, stretching out individual samples.

 

Interesting -- I should've realized this, but didn't. What's the workaround? Do you disable the display fetch (i.e. a blank screen, as happens with most VCS games that use sample playback), or...?

Link to comment
Share on other sites

Interesting -- I should've realized this, but didn't. What's the workaround? Do you disable the display fetch (i.e. a blank screen, as happens with most VCS games that use sample playback), or...?

 

Yep, on the Intellivision we have to blank the display and mask interrupts to get perfectly clean playback. We have to be careful with the masked interrupts, though. If you mask them too long, the STIC loses its register contents.

  • Like 1
Link to comment
Share on other sites

No, the Aquarius doesn't steal cycles. My playback program is not perfectly cycle count balanced either.

 

I am guessing that I have to cycle count and balance but that is going to slow me way down.

 

I wonder if I could compensate in my processing by stretching out samples.

 

I forget that at these very high speeds the timing is incredibly critical.

 

I really didn't think it would matter this much though.

 

I am using a 16 bit signed waveform into my converter. It is not elegant like yours and it is in Freebasic.

 

#lang "fblite"
Screenres 1500,900,32: CLS
LOCATE 1, 1
FILENAME$ = "kicks.raw"
TOGGLE = 0
PAUSER = 400
randomize timer
samples = 458744
oversamprate = 1
dim audio(samples*oversamprate) as SHORT, audioout(samples*oversamprate) as SHORT, naudio(samples*oversamprate) as SHORT, ebitout(samples*oversamprate) as SHORT, noise(samples*oversamprate) as SHORT, shapenoise(samples) as SHORT
dim quanterror(samples*oversamprate) as SHORT, origaudio(samples*oversamprate) as SHORT
'input "How many levels?",levels
totalbitcount=samples*oversamprate
ebitcount=int(totalbitcount/8)
if totalbitcount mod 8>0 then ebitcount=ebitcount+1
dim bitaudioout(ebitcount) as UBYTE
OPEN filename$ FOR BINARY as #1
get #1,,audio()
close #1
bitcounter=0:outputbit$="":ebitcounter=0
cumerror=0
for j=1 to samples
origaudio(j)=audio(j)
pset (j/(samples/1500),100+audio(j)/128),rgb(255,255,255)
'Clip Check
'if audio(j)>32 then audio(j)=32767
'if audio(j)<0 then audio(j)=-32768
naudio(j)=audio(j)
'for i=1 to oversamprate
  
	'outj=(j-1)*oversamprate+i
	outj=j
	if audio(j)>cumerror then
 
		cumerror=cumerror+32767-audio(j)
		'audio(j)=32767
		audioout(outj)=1
		ebitout(outj)=32767
	else
 
		cumerror=cumerror-32768-audio(j)
		'audio(j)=-32768
		audioout(outj)=0
		ebitout(outj)=-32768
 
	end if
	pset (outj/(samples/1500),400+audioout(outj)*25),rgb(255,255,255)
'locate 65,1:print "audio: ";audio(j);" - audioout: ";audioout(j)

	bitcounter=bitcounter+1
	outputbit$=outputbit$+str$(audioout(outj))
	if bitcounter/8=int(bitcounter/8) then

		ebitcounter=ebitcounter+1
		bitaudioout(ebitcounter)=128*val(mid$(outputbit$,2,1))+64*val(mid$(outputbit$,3,1))+32*val(mid$(outputbit$,4,1))+16*val(mid$(outputbit$,5,1))+8*val(mid$(outputbit$,6,1))+4*val(mid$(outputbit$,7,1))+2*val(mid$(outputbit$,8,1))+1*val(mid$(outputbit$,1,1))

		'locate 50,1:print outputbit$;" - ";bitaudioout(ebitcounter)
		outputbit$=""
	end if

'next i
 'pset (bitcounter/(totalbitcount/1500),400+levels+50+0),rgb(255,255,255)
next j
locate 70,1
print "bitcounter: ";bitcounter
print "ebitcounter: ";ebitcounter
print "ebitcount: ";ebitcount
print "totalbitcount: ";totalbitcount
print "samples: ";samples
input ggg$
open "OUTBIT.BIN" for BINARY AS #1
put #1,,bitaudioout()
close #1
open "OUTPUT.RAW" for BINARY AS #1
put #1,,ebitout()
close #1

 

And then the player:

 


; Program to Create Sound Using 1-BIT at 170,413 Hz (No Joke)
; Must be run on Actual Aquarius with Bank-Switching Capable Cartridge
; Requires 1016k of Audio Data to be loaded before execution code
.org $E000   
.db $b6, $b7, $24, $2a, $8d, $9c, $42, $b0
.db $53, $6c, $90, $64, $89, $a8, $f9, $70
bankmain:
ld  de, $c000	   ; load the target address into register DE
ld  a, 0			   ; load the target bank number into the accumulator
   ld  (de), a		     ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 1			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 2			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 3			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 4			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 5			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 6			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 7			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 8			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 9			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 10			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 11			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 12			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 13			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 14			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 15		       ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 16			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 17			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 18			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 19			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 20			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 21			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 22			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 23			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 24			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 25			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 26			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 27			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 28			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 29			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 30			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 31			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 32			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 33			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 34		       ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 35			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 36		       ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 37			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 38			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 39			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 40			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 41			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 42			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 43		       ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 44			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 45			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 46			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 47			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 48			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 49			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 50			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 51			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 52			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 53			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 54			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 55			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 56			     ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 57			    ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 58			     ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 59			     ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 60			     ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 61			     ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 62			    ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 63			     ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 64			    ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 65			    ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 66			     ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 67			     ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 68			    ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 69			    ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 70			     ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 71		       ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 72			     ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 73			     ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 74			     ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 75			     ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 76			    ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 77			     ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 78			    ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 79			    ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 80			     ; load the target bank number into the accumulator
    ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 81			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 82			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 83			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 84			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 85			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 86			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 87			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 88			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 89			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 90		       ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 91			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 92		       ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 93			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 94			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 95			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 96			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 97			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 98			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 99		       ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 100			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 101			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 102			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 103			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 104			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 105			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 106			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 107			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 108			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 109			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 110			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 111			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  a, 112			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 113			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 114			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 115			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 116			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 117			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  a, 118			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 119			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 120			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 121			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  a, 122			     ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 123			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 124			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  a, 125		       ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space;
call main	; call the drawing program
ld  de, $c000	    ; load the target address into register DE
ld  a, 126			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
ld  a, 127			    ; load the target bank number into the accumulator
   ld  (de), a		       ; write the bank number into the cartridge space
call main	; call the drawing program
;jp bankmain   
halt

main:
ld bc, 8192  ; (10) number of bytes of samples
ld hl, $C000 ; (10) Memory Location to ROM Sample

replay: 
ld a, (hl)  ; (7) load first sample set into A
out ($fc), a ; (11) send out the sample
rlca   ; (4) rotate the PWM model left
out ($fc), a ; (11) send out the sample
rlca   ; (4) rotate the PWM model left
out ($fc), a ; (11) send out the sample
rlca   ; (4) rotate the PWM model left
out ($fc), a ; (11) send out the sample
rlca   ; (4) rotate the PWM model left
out ($fc), a ; (11) send out the sample
rlca   ; (4) rotate the PWM model left
out ($fc), a ; (11) send out the sample
rlca   ; (4) rotate the PWM model left
out ($fc), a ; (11) send out the sample
rlca   ; (4) rotate the PWM model left
out ($fc), a ; (11) send out the sample
inc hl   ; (6) Move up the Rom sample location
dec bc   ; (6) Reduce the byte counter
ld a, b   ; grab the counter
or c   ; check if it is zero
jp nz, replay ; do it again until we are done!

FINISH:
;jp FINISH
ret






   ; Zero-Fill Remainder of Cartridge ROM
   .org    $FFFF
   .byte   $00
.end



Edited by chjmartin2
Link to comment
Share on other sites

Yeah, you'll probably have to pull all your loop-end instructions up into the loop in that replay loop. Something like this:

 


ld bc, 8191   ; (10) number of bytes of samples
ld hl, $C000  ; (10) Memory Location to ROM Sample

ld a, (hl)    ; (7) load first sample set into A

replay: 
out ($fc), a  ; (11) send out the sample
add a, a      ; (4) rotate the PWM model left

inc hl        ; (6) Move up the Rom sample location

out ($fc), a  ; (11) send out the sample
add a, a      ; (4) rotate the PWM model left

out ($fc), a  ; (11) send out the sample
add a, a      ; (4) rotate the PWM model left

dec bc        ; (6) Reduce the byte counter

out ($fc), a  ; (11) send out the sample
add a, a      ; (4) rotate the PWM model left

out ($fc), a  ; (11) send out the sample
add a, a      ; (4) rotate the PWM model left

ld  d, (hl)   ; (7) next first sample set into A

out ($fc), a  ; (11) send out the sample
add a, a      ; (4) rotate the PWM model left

out ($fc), a  ; (11) send out the sample
add a, a      ; (4) rotate the PWM model left

rlc b         ; ( see if loop counter went negative

out ($fc), a  ; (11) send out the sample

ld a, d       ; (4)  copy new sample to a

jp c, replay  ; (12) do it again until we are done!

 

Now I warn you, I'm not actually a Z-80 programmer, but that should spread out the noise a bit if it's correct.

Link to comment
Share on other sites

jungletease.wav

 

Here is a tease... but I managed to really balance the cycles between samples (except for when it goes through the large loop) and I cannot believe the quality of the result.

 

Code and longer examples, ALONG WITH A VIDEO CAP of actual TV output will follow.

 

Intvnut - I absolutely would not have gotten here without your help. We have implemented a Sigma Delta Modulator (or at least a Pulse Density Modulator) DAC on a Z80.

Link to comment
Share on other sites

Jungle_10000dither.wav

 

And now I have upgraded the converter to include Dither prior to Sigma Delta Modulation. I used 5,000 +/- dither, I picked this value by listening by ear.

 

The 1 meg roms are erasing, and I am going to build a wave file with all of the samples I have tried to convert, so we can hear them again. I'm also willing to take requests.

 

I will even try other video game console songs if you want to hear them. Last thing will be what sound do you want to hear on the actual TV that I record the ambient sound with the video camera with. (The screen won't do anything, but it will be solid proof!)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...