Título: 1 bit player Publicado por: Dioniso en 23 de Octubre de 2006, 12:38:01 pm Hello.
This is a small player to play songs through the 1-bit port $AA. The song I have chosen is the main title from Bubble Bobble though some notes don't correspond to the original one, I think ... ::) (I did it yesterday with a very big hang-over) The main routine (playit) has been taken/copied/ported from the "Assembly Listing of the Sea Change ROM". You'll see the t-states are wrong (you have to add 1). I just added some lines to maintain compatibility with the MSX (even reading the $aa port just to keep the first 6 bits and change only the 7th bit; otherwise you'll have strange effects, like turning on the CAPs light). The code has been compiled with TNIasm and the binary is just 384 bytes long. You can get it right HERE (http://www.geocities.com/dioniso072/songs/1bit.bin). The "replayer" is written in a very easy way. Don't complain :P This is not very useful, I know. More to come ... Código: ORG $9000 db $fe dw Start_Of_File, End_Of_File, Start_Of_File Start_Of_File: in a,($aa) ;If we don't do this we'll have and $ef ;problems when we read this port out ($aa),a ;later. nop nop ld hl,Pseudo_Tracker The_Loop: xor a cp (hl) ret z push hl ld a,(hl) add a,a add a,a ld h,0 ld l,a ld de,Notes_And_Length-4 add hl,de push hl pop ix ld e,(ix+0) ld d,(ix+1) ld l,(ix+2) ld h,(ix+3) call playit pop hl inc hl jr The_Loop Notes_And_Length: ;First 2 bytes = Length // Last 2 bytes = Note dw $68,$66b ;01 - c4 3822ms dw $75,$5b4 ;02 - d4 3405ms dw $83,$511 ;03 - e4 3033ms dw $8b,$4c7 ;04 - f4 2863ms dw $b0,$5b4 ;05 - d4 (longer 50%) dw $34,$66b ;06 - c4 (shorter 50%) dw $9c,$66b ;07 - c4 (longer 50%) dw $2e,$737 ;08 - a#3 (shorter 50%) dw $5c,$737 ;09 - a#3 4290ms dw $58,$7a6 ;10 - a3 4545ms dw $2c,$7a6 ;11 - a3 (shorter 50%) dw $27,$89a ;12 - g3 (shorter 50%) dw $45,$9ab ;13 - f3 5726ms dw $4e,$89a ;14 - g3 5102ms dw $84,$7a6 ;15 - a3 (longer 50%) dw $8a,$737 ;16 - a#3 (longer 50%) dw $138,$66b ;17 - c4 (longer 300%) dw $7c,$560 ;18 - d#4 3214ms dw $d1,$326 ;19 - c5 1911ms dw $eb,$2cb ;20 - d5 1702ms dw $f8,$2a1 ;21 - d#5 1607ms dw $107,$279 ;22 - e5 1516ms dw $117,$254 ;23 - f5 1431ms dw $139,$210 ;24 - g5 1275ms dw $b0,$3c4 ;25 - a4 2272ms dw $9c,$43e ;26 - g4 2551ms dw $22f,$38c ;27 - a#4 2145ms (longer 300%) dw $174,$38c ;28 - a#4 2145ms (longer 200%) dw $210,$3c4 ;29 - a4 (longer 300%) dw $1a3,$4c7 ;30 - f4 (longer 300%) dw $160,$3c4 ;31 - a4 (longer 200%) dw $1d6,$43e ;32 - g4 (longer 300%) dw $160,$5b4 ;33 - d4 (longer 300%) dw $2c1,$43e ;34 - g4 (longer 450%) dw $160,$1d3 ;35 - a5 1136ms dw $139,$66b ;36 - c4 (longer 300%) dw $274,$4c7 ;37 - f4 (longer 450%) Pseudo_Tracker: ;First part db 1,2,3,4,3,5,6,3,2,7,8,2,1,8,10,17 db 11,12,13,14,15,11,14,10,16,6,1,2,3,2,1 ;First part (repeat) db 1,2,3,4,3,5,6,3,2,7,8,2,1,8,10,17 db 11,12,13,14,15,11,14,10,16,6,1,2,3,2,1 ;Second part db 1,2,18,3,19,20,21,22,1,2,3,4,19,20,22,23 db 1,2,3,26,19,20,22,24,1,2,3,25,19,20,22,35 db 4,26,25,27,28,25,28,29,30,31,32,33,31,34 db 4,26,25,27,28,25,28,29,30,31,32,36,31,37 ;End and exit db 0 playit: di ld a,l ; srl l ; srl l ; L = medium part of tone period cpl ; and $03 ; A = 3 - fine part of tone period ld c,a ; ld b,$00 ; ld ix,BE_IX_p_3 ; Address: BE_IX+3 add ix,bc ; IX holds address of entry into the loop ; the loop will contain 0-3 NOPs, implementing ; the fine part of the tone period. in a,($aa) ;Let's be sure we just modify the 7th bit BE_IX_p_3: nop ;(4) optionally executed NOPs for small ; adjustments to tone period BE_IX_p_2: nop ;(4) BE_IX_p_1: nop ;(4) BE_IX_p_0: inc b ;(4) inc c ;(4) BE_H_L_LP: dec c ;(4) timing loop for duration of jr nz,BE_H_L_LP ;(12/7) high or low pulse of waveform ld c,$3f ;(7) dec b ;(4) jp nz,BE_H_L_LP ;(10) JUMP to BE_H&L_LP xor $80 ;(7) toggle output beep bit out ($aa),a ;(11) output pulse ld b,h ;(4) B = coarse part of tone period ld c,a ;(4) save port #AA output byte bit 4,a ;(8) if new output bit is high, go jr nz,BE_AGAIN ;(2/7) to BE_AGAIN ld a,d ;(4) one cycle of waveform has completed or e ;(4) (low->low). if cycle countdown = 0 jr z,BE_END ;(12/7) go to BE_END ld a,c ;(4) restore output byte for port #AA ld c,l ;(4) C = medium part of tone period dec de ;(6) decrement cycle count jp (ix) ;(8) do another cycle BE_AGAIN: ld c,l ;(4) C = medium part of tone period inc c ;(4) adds 16 cycles to make duration of high = duration of low jp (ix) ;(8) do high pulse of tone BE_END: ei ; Enable Interrupts ret ; End_Of_File: ; From the "Assembly Listing of the Sea Change ROM" ; Documented by Alvin Albrecht. ; ; ----------------------- ; THE 'BEEPER' SUBROUTINE ; ----------------------- ; Outputs a square wave of given duration and frequency ; to the loudspeaker. ; Enter with: DE = #cycles - 1 ; HL = tone period as described next ; ; The tone period is measured in T states and consists of ; three parts: a coarse part (H register), a medium part ; (bits 7..2 of L) and a fine part (bits 1..0 of L) which ; contribute to the waveform timing as follows: ; ; coarse medium fine ; duration of low = 118 + 1024*H + 16*(L>>2) + 4*(L&0x3) ; duration of hi = 118 + 1024*H + 16*(L>>2) + 4*(L&0x3) ; Tp = tone period = 236 + 2048*H + 32*(L>>2) + 8*(L&0x3) ; = 236 + 2048*H + 8*L = 236 + 8*HL ; ; As an example, to output five seconds of middle C (261.624 Hz): ; (a) Tone period = 1/261.624 = 3.822ms ; (b) Tone period in T-States = 3.822ms*fCPU = 13378 ; where fCPU = clock frequency of the CPU = 3.5MHz ; © Find H and L for desired tone period: ; HL = (Tp - 236) / 8 = (13378 - 236) / 8 = 1643 = 0x066B ; (d) Tone duration in cycles = 5s/3.822ms = 1308 cycles ; DE = 1308 - 1 = 0x051B ; ; The resulting waveform has a duty ratio of exactly 50%. ; ; --------------------- ; THE 'SEMI-TONE' TABLE ; --------------------- ; ; Holds frequencies corresponding to semitones in middle octave. ; To move n octaves higher or lower, frequencies are multiplied by 2^n. ; ;semi_tone: ; 261.625565290 C ; 277.182631135 C# ; 293.664768100 D ; 311.126983881 D# ; 329.627557039 E ; 349.228231549 F ; 369.994422674 F# ; 391.995436072 G ; 415.304697513 G# ; 440.000000000 A ; 466.163761616 A# ; 493.883301378 B Título: Re: 1 bit player Publicado por: pitpan en 23 de Octubre de 2006, 07:50:53 pm Congratulations, Dioniso. It's really cool and the sound quality is unbeliavable for the poor old 1-bit key-click generator. I guess that the MSX engineers did not think about this use ;)
I've just ported your code to asMSX syntax to make it easier for other users. .bios .org $9000 .basic .start INIT INIT: in a,[$aa] ;If we don't do this we'll have and $ef ;problems when we read this port out [$aa],a ;later. nop nop ld hl,Pseudo_Tracker The_Loop: xor a cp [hl] ret z push hl ld a,[hl] add a,a add a,a ld h,0 ld l,a ld de,Notes_And_Length-4 add hl,de push hl pop ix ld e,[ix+0] ld d,[ix+1] ld l,[ix+2] ld h,[ix+3] call playit pop hl inc hl jr The_Loop Notes_And_Length: ;First 2 bytes = Length // Last 2 bytes = Note dw $68,$66b ;01 - c4 3822ms dw $75,$5b4 ;02 - d4 3405ms dw $83,$511 ;03 - e4 3033ms dw $8b,$4c7 ;04 - f4 2863ms dw $b0,$5b4 ;05 - d4 [longer 50%] dw $34,$66b ;06 - c4 [shorter 50%] dw $9c,$66b ;07 - c4 [longer 50%] dw $2e,$737 ;08 - a#3 [shorter 50%] dw $5c,$737 ;09 - a#3 4290ms dw $58,$7a6 ;10 - a3 4545ms dw $2c,$7a6 ;11 - a3 [shorter 50%] dw $27,$89a ;12 - g3 [shorter 50%] dw $45,$9ab ;13 - f3 5726ms dw $4e,$89a ;14 - g3 5102ms dw $84,$7a6 ;15 - a3 [longer 50%] dw $8a,$737 ;16 - a#3 [longer 50%] dw $138,$66b ;17 - c4 [longer 300%] dw $7c,$560 ;18 - d#4 3214ms dw $d1,$326 ;19 - c5 1911ms dw $eb,$2cb ;20 - d5 1702ms dw $f8,$2a1 ;21 - d#5 1607ms dw $107,$279 ;22 - e5 1516ms dw $117,$254 ;23 - f5 1431ms dw $139,$210 ;24 - g5 1275ms dw $b0,$3c4 ;25 - a4 2272ms dw $9c,$43e ;26 - g4 2551ms dw $22f,$38c ;27 - a#4 2145ms [longer 300%] dw $174,$38c ;28 - a#4 2145ms [longer 200%] dw $210,$3c4 ;29 - a4 [longer 300%] dw $1a3,$4c7 ;30 - f4 [longer 300%] dw $160,$3c4 ;31 - a4 [longer 200%] dw $1d6,$43e ;32 - g4 [longer 300%] dw $160,$5b4 ;33 - d4 [longer 300%] dw $2c1,$43e ;34 - g4 [longer 450%] dw $160,$1d3 ;35 - a5 1136ms dw $139,$66b ;36 - c4 [longer 300%] dw $274,$4c7 ;37 - f4 [longer 450%] Pseudo_Tracker: ;First part db 1,2,3,4,3,5,6,3,2,7,8,2,1,8,10,17 db 11,12,13,14,15,11,14,10,16,6,1,2,3,2,1 ;First part [repeat] db 1,2,3,4,3,5,6,3,2,7,8,2,1,8,10,17 db 11,12,13,14,15,11,14,10,16,6,1,2,3,2,1 ;Second part db 1,2,18,3,19,20,21,22,1,2,3,4,19,20,22,23 db 1,2,3,26,19,20,22,24,1,2,3,25,19,20,22,35 db 4,26,25,27,28,25,28,29,30,31,32,33,31,34 db 4,26,25,27,28,25,28,29,30,31,32,36,31,37 ;End and exit db 0 playit: di ld a,l ; srl l ; srl l ; L = medium part of tone period cpl ; and $03 ; A = 3 - fine part of tone period ld c,a ; ld b,$00 ; ld ix,BE_IX_p_3 ; Address: BE_IX+3 add ix,bc ; IX holds address of entry into the loop ; the loop will contain 0-3 NOPs, implementing ; the fine part of the tone period. in a,[$aa] ;Let's be sure we just modify the 7th bit BE_IX_p_3: nop ;[4] optionally executed NOPs for small ; adjustments to tone period BE_IX_p_2: nop ;[4] BE_IX_p_1: nop ;[4] BE_IX_p_0: inc b ;[4] inc c ;[4] BE_H_L_LP: dec c ;[4] timing loop for duration of jr nz,BE_H_L_LP ;[12/7] high or low pulse of waveform ld c,$3f ;[7] dec b ;[4] jp nz,BE_H_L_LP ;[10] JUMP to BE_H&L_LP xor $80 ;[7] toggle output beep bit out [$aa],a ;[11] output pulse ld b,h ;[4] B = coarse part of tone period ld c,a ;[4] save port #AA output byte bit 4,a ;[8] if new output bit is high, go jr nz,BE_AGAIN ;[2/7] to BE_AGAIN ld a,d ;[4] one cycle of waveform has completed or e ;[4] [low->low]. if cycle countdown = 0 jr z,BE_END ;[12/7] go to BE_END ld a,c ;[4] restore output byte for port #AA ld c,l ;[4] C = medium part of tone period dec de ;[6] decrement cycle count jp [ix] ;[8] do another cycle BE_AGAIN: ld c,l ;[4] C = medium part of tone period inc c ;[4] adds 16 cycles to make duration of high = duration of low jp [ix] ;[8] do high pulse of tone BE_END: ei ; Enable Interrupts ret ; ; From the "Assembly Listing of the Sea Change ROM" ; Documented by Alvin Albrecht. ; ; ----------------------- ; THE 'BEEPER' SUBROUTINE ; ----------------------- ; Outputs a square wave of given duration and frequency ; to the loudspeaker. ; Enter with: DE = #cycles - 1 ; HL = tone period as described next ; ; The tone period is measured in T states and consists of ; three parts: a coarse part [H register], a medium part ; [bits 7..2 of L] and a fine part [bits 1..0 of L] which ; contribute to the waveform timing as follows: ; ; coarse medium fine ; duration of low = 118 + 1024*H + 16*[L>>2] + 4*[L&0x3] ; duration of hi = 118 + 1024*H + 16*[L>>2] + 4*[L&0x3] ; Tp = tone period = 236 + 2048*H + 32*[L>>2] + 8*[L&0x3] ; = 236 + 2048*H + 8*L = 236 + 8*HL ; ; As an example, to output five seconds of middle C [261.624 Hz]: ; [a] Tone period = 1/261.624 = 3.822ms ; Tone period in T-States = 3.822ms*fCPU = 13378 ; where fCPU = clock frequency of the CPU = 3.5MHz ; [c] Find H and L for desired tone period: ; HL = [Tp - 236] / 8 = [13378 - 236] / 8 = 1643 = 0x066B ; [d] Tone duration in cycles = 5s/3.822ms = 1308 cycles ; DE = 1308 - 1 = 0x051B ; ; The resulting waveform has a duty ratio of exactly 50%. ; ; --------------------- ; THE 'SEMI-TONE' TABLE ; --------------------- ; ; Holds frequencies corresponding to semitones in middle octave. ; To move n octaves higher or lower, frequencies are multiplied by 2^n. ; ;semi_tone: ; 261.625565290 C ; 277.182631135 C# ; 293.664768100 D ; 311.126983881 D# ; 329.627557039 E ; 349.228231549 F ; 369.994422674 F# ; 391.995436072 G ; 415.304697513 G# ; 440.000000000 A ; 466.163761616 A# ; 493.883301378 B Título: Re: 1 bit player Publicado por: Jon_Cortazar en 24 de Octubre de 2006, 06:46:41 am This is a small player to play songs through the 1-bit port $AA. When I grow up I want to be like you :god: :god: :god: :god: :god: :god: Título: Re: 1 bit player Publicado por: Dioniso en 24 de Octubre de 2006, 04:21:52 pm Thanks Robsy and Jon. Good idea to port it to asMSX syntax. Most of the people here use your assembler.
Título: Re: 1 bit player Publicado por: pitpan en 24 de Octubre de 2006, 07:16:11 pm Only minor changes indeed from your source:
- () indirections replaced by [] - BASIC header generated by asMSX directives (.BASIC, .START) Anyway, the thing is that using the 1-bit keyboard click port you can do now amazing things. What about a 1-bit tracker? I do not mean a full-sized application, but a simple Excel spreadsheet that converts notes (C, C#, etc) to your program values. It is just a simple idea. But it would be cool to make a PSGless MSX music mini-compo! Título: Re: 1 bit player Publicado por: SapphiRe en 24 de Octubre de 2006, 07:18:15 pm It is just a simple idea. But it would be cool to make a PSGless MSX music mini-compo! GRRRRRRRRRRRRRRREEEEEEEEEEEEEAAAT!! ;D This sounds me like: "hey! We have a PSG but we are the best and we don't need it to make music!" ;D ;D ;D ;D ;D Título: Re: 1 bit player Publicado por: pitpan en 24 de Octubre de 2006, 07:48:15 pm That's the thing: let's do it the hard way ;D
Título: Re: 1 bit player Publicado por: WYZ en 24 de Octubre de 2006, 09:24:12 pm So we have four channels to play music ;D. Really great Dioniso. ;)
Título: Re: 1 bit player Publicado por: jltursan en 24 de Octubre de 2006, 10:25:16 pm Yay!, sounds very convincing to be only a "beeper" ;). IIRC Dioniso already used this technique in some of their games, T-Virus maybe?. Great to create some extra SFX! :D
Título: Re: 1 bit player Publicado por: ARTRAG en 25 de Octubre de 2006, 12:07:37 am Great! it sound very well.
I remember that using SW synthesis on the zx spectrum, it was possible to have up to 6 channels on the PSG (again using 100 cpu). The idea was to generate two square waves per channes using counters - like now. Ok, now I remember, dioniso knows already the story :-) http://www.west.co.tt/matt/speccy/apology/ for details Título: Re: 1 bit player Publicado por: Dioniso en 25 de Octubre de 2006, 01:04:14 pm Anyway, the thing is that using the 1-bit keyboard click port you can do now amazing things. What about a 1-bit tracker? I do not mean a full-sized application, but a simple Excel spreadsheet that converts notes (C, C#, etc) to your program values. Not only that ;) It's just a question of time. I hope I can finish what I (still in my head) have for the MSXDev06 ... If I just had more time :'( Título: Re: 1 bit player Publicado por: WYZ en 06 de Enero de 2007, 09:34:26 pm Here is a previous port of ZX Wham! (2 channels without percussion)
Título: Re: 1 bit player Publicado por: Dioniso en 06 de Enero de 2007, 10:45:47 pm Wyz, aún recuerdo cuando te dije: "Hostias, mira que demo más guapa ha hecho Mr. Beep! (Beeper Demo)" y me contestaste: "No sé qué decir, no conozco ese chip de sonido" ;)
Lo mejor que hay ahora en música 1bit es Mr. Beep: Su web (http://republika.pl/mister_beep/) Lo único que ocurre con este chaval es que no sabe programar ... utiliza software ya creado para hacer música; pero es una pasada. Mi canción favorita (http://parishq.net/proposed//sound/mister_beep-shpyon.mp3) de Mr. Beep. Aunque hay una versión de Jet Set Willy (http://parishq.net/proposed//sound/zilog-jet_set_willy_cover.mp3) de otro compositor, Zilog, que quita el hipo :o El problema es que estas canciones ocupan un huevo. Título: Re: 1 bit player Publicado por: WYZ en 06 de Enero de 2007, 11:11:30 pm Y sigo si saber que es el beeper ;D. Esto que he colgado viene por una conversacion sobre los nuevos juegos de Na_th_an y su posible publicacion para MSX y en cinco mintillos ha surgido una version MSX a partir del una parte de codigo que me ha proporcionado Black Hole, del mundillo del ZX.
El Wham! es lo mas sencillo en editores de 1 bit, aunque se pueden conseguir efectos bastante buenos y es tremendo lo que se puede hacer con el simple beeper, al oido está, pero espero que no estes pensando en ... porque a mi ni se me ocurre ejecutar algo que suene como lo de Mr. Beeper en mis MSX. Ya me asusté mucho con el Beeper game. Ahps, si llevas algo mas avanzado en esto ya estas tardando en enviarme un algo a mail! Título: Re: 1 bit player Publicado por: Dioniso en 06 de Enero de 2007, 11:38:32 pm Y sigo si saber que es el beeper ;D. Esto que he colgado viene por una conversacion sobre los nuevos juegos de Na_th_an y su posible publicacion para MSX y en cinco mintillos ha surgido una version MSX a partir del una parte de codigo que me ha proporcionado Black Hole, del mundillo del ZX. Alguien de por aquí ya me ha comentado algo. Sigo ese tema desde "cerca" pero no me quiero involucrar. Por cierto, ese juego de Na_th_an (Phantomasa? ;) ) se ejecuta desde Basic (en Basic) pero utiliza el Wham (si no he oído mal) con música 1bit? La verdad es que no corre nada mal para estar en Basic. Citar El Wham! es lo mas sencillo en editores de 1 bit, aunque se pueden conseguir efectos bastante buenos y es tremendo lo que se puede hacer con el simple beeper, al oido está, pero espero que no estes pensando en ... porque a mi ni se me ocurre ejecutar algo que suene como lo de Mr. Beeper en mis MSX.:D Bueno ... no sé ... ::) No soy muy amigo del software que existe para Speccy. Lo que yo hice fue ... una putada para mí: -Ejecutar el BlueMSX. -Desde Basic y con un simple PLAY ejecutar dos octavas completas. -Capturar el audio. -Separar cada nota con el Goldwave. -Aplicar un poco de efecto "robot" ( :P) a cada nota y guardarlas en 8bit raw. -Pasarlas a 1bit con el software de Edu. -Editor hexadecimal y ver qué trozos se repetían en una misma nota para poder hacer el loop si se mantiene pulsada la tecla del piano. -Probar las 24 notas ... y volver a crear las notas que no sonaban bien ... (una pesadilla). Editor ... mi guitarra Beep con guitarra española de mala calidad (http://www.geocities.com/dioniso072/songs/beep.wma) ;D Título: Re: 1 bit player Publicado por: WYZ en 06 de Enero de 2007, 11:59:07 pm Citar ...Editor ... mi guitarra: Beep con guitarra española de mala calidad Juas! cada dia mas freaks. |