chjmartin2 Posted February 22, 2012 Author Share Posted February 22, 2012 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. Here is a view of the inital 84 samples, close to 450 microseconds. Quote Link to comment Share on other sites More sharing options...
intvnut Posted February 22, 2012 Share Posted February 22, 2012 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. Here is a view of the inital 84 samples, close to 450 microseconds. 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. Quote Link to comment Share on other sites More sharing options...
chjmartin2 Posted February 22, 2012 Author Share Posted February 22, 2012 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. Quote Link to comment Share on other sites More sharing options...
intvnut Posted February 22, 2012 Share Posted February 22, 2012 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. Quote Link to comment Share on other sites More sharing options...
chjmartin2 Posted February 22, 2012 Author Share Posted February 22, 2012 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. Quote Link to comment Share on other sites More sharing options...
Aquaman Posted February 22, 2012 Share Posted February 22, 2012 Of course we are still looking forward to any new developments you make regarding the digitized sound you get out of this little machine. Keep us posted!! Quote Link to comment Share on other sites More sharing options...
jaybird3rd Posted February 23, 2012 Share Posted February 23, 2012 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. Quote Link to comment Share on other sites More sharing options...
chjmartin2 Posted February 24, 2012 Author Share Posted February 24, 2012 I see what you mean now about only having one filter. I tried to put the circuit we spoke about in the simulator: And then sent a square wave into it: 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... Quote Link to comment Share on other sites More sharing options...
intvnut Posted February 24, 2012 Share Posted February 24, 2012 (edited) I see what you mean now about only having one filter. I tried to put the circuit we spoke about in the simulator: And then sent a square wave into it: 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 February 24, 2012 by intvnut Quote Link to comment Share on other sites More sharing options...
intvnut Posted February 24, 2012 Share Posted February 24, 2012 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. :-) Quote Link to comment Share on other sites More sharing options...
chjmartin2 Posted February 24, 2012 Author Share Posted February 24, 2012 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. Quote Link to comment Share on other sites More sharing options...
chjmartin2 Posted February 24, 2012 Author Share Posted February 24, 2012 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! Quote Link to comment Share on other sites More sharing options...
chjmartin2 Posted February 24, 2012 Author Share Posted February 24, 2012 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? Quote Link to comment Share on other sites More sharing options...
intvnut Posted February 24, 2012 Share Posted February 24, 2012 (edited) 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 February 24, 2012 by intvnut Quote Link to comment Share on other sites More sharing options...
chjmartin2 Posted February 24, 2012 Author Share Posted February 24, 2012 (edited) Nice! Back to excited again... Edited February 24, 2012 by chjmartin2 Quote Link to comment Share on other sites More sharing options...
chjmartin2 Posted February 25, 2012 Author Share Posted February 25, 2012 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. Quote Link to comment Share on other sites More sharing options...
intvnut Posted February 25, 2012 Share Posted February 25, 2012 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.) Quote Link to comment Share on other sites More sharing options...
+thegoldenband Posted February 25, 2012 Share Posted February 25, 2012 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...? Quote Link to comment Share on other sites More sharing options...
intvnut Posted February 25, 2012 Share Posted February 25, 2012 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. 1 Quote Link to comment Share on other sites More sharing options...
chjmartin2 Posted February 25, 2012 Author Share Posted February 25, 2012 (edited) 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 February 25, 2012 by chjmartin2 Quote Link to comment Share on other sites More sharing options...
intvnut Posted February 25, 2012 Share Posted February 25, 2012 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. Quote Link to comment Share on other sites More sharing options...
chjmartin2 Posted February 26, 2012 Author Share Posted February 26, 2012 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. Quote Link to comment Share on other sites More sharing options...
+thegoldenband Posted February 26, 2012 Share Posted February 26, 2012 That's insane -- I can't believe how clear that sounds! Bravo. Quote Link to comment Share on other sites More sharing options...
intvnut Posted February 26, 2012 Share Posted February 26, 2012 jungletease.wav 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. That sounds pretty nice. Bravo! I'm glad I could help. :-) Quote Link to comment Share on other sites More sharing options...
chjmartin2 Posted February 26, 2012 Author Share Posted February 26, 2012 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!) Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.