commit c390792a038b9dda8b6650036aa21e072def7a05 Author: cybernesto Date: Sun Oct 22 18:46:06 2017 +0200 Electric Duet player sources - electricduet.asm is the original source code published by Paul Lutus. - PLAYER.ED.S is a commented source in french written by Deckard - MOCKINGDUET.S is an ED player for a Mockingboard installed on Slot 4. - CRICKETDUET.S is an ED player for an Apple //c with a Cricket! from Street Electronics. diff --git a/README.md b/README.md new file mode 100644 index 0000000..4862f1a --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# electric-mock +## Apple II Electric Duet player for the Mockingboard and the Cricket! + +*Electric Duet* is probably the most popular music format in the Apple II world. +Unfortunately the sound quality of the internal speaker of the Apple II does not do much justice to the songs written with ED. On certain Apple II models like the //c the sound circuitry does not cut off the modulation frequency very well producing a high pitched background noise. + +This motivated me to write my own routines to play ED songs using a sound card to produce pure tones with much higher quality. I chose the Cricket! because I own one and there is not much software compatible with it. A Mockingboard ED Player is also included for the expandable Apple IIs with a Mockingboard Sound, A or C on Slot 4. + +I wanted to keep the player as small as the original one so that it could be handled the same way. This limited a bit the amount of code that I could use, so even though the Cricket! version is able to play in stereo, the Mockingboard version is not. + +A compromise was done for the frequency calculation where only a simple factor is used. A frequency table would have provided more accurate notes, but it would have made the player way bigger, so that it could not be used as a direct replacement. + +The src directory includes the original assembly code as made available by [Paul Lutus](https://arachnoid.com/electric_duet/index.html), as well as the commented source in french written by [Deckard](http://boutillon.free.fr). Also a clean crack of the Electric Duet disk including tools for composing original scores is in the dsk directory. + +The CRICKETDUET.S and MOCKINGDUET.S sources were assembled with Merlin. The binaries are available in *The Music Disk* image which also includes some classical pieces put together with a nice menu system written by Walt Marcinko Jr. + + + + + diff --git a/dsk/Electric Duet (clean crack).dsk b/dsk/Electric Duet (clean crack).dsk new file mode 100644 index 0000000..9714be9 Binary files /dev/null and b/dsk/Electric Duet (clean crack).dsk differ diff --git a/dsk/The Music Disk for Mockingboard and Cricket.dsk b/dsk/The Music Disk for Mockingboard and Cricket.dsk new file mode 100755 index 0000000..0a3ff04 Binary files /dev/null and b/dsk/The Music Disk for Mockingboard and Cricket.dsk differ diff --git a/src/CRICKETDUET.S b/src/CRICKETDUET.S new file mode 100644 index 0000000..23a9a96 --- /dev/null +++ b/src/CRICKETDUET.S @@ -0,0 +1,128 @@ +*ELECTRIC DUET MUSIC PLAYER FOR THE CRICKET + +CHN = $1D +SONG = $1E +LEFTCHN = $10 +RIGHTCHN = $20 +ENAREG = $07 +VOL_A = $08 +TONE = $06 +DURATION = $08 + +ACIACMD2 = $C0AA +ACIACTL2 = $C0AB +ACIAST2 = $C0A9 +ACIARXTX2 = $C0A8 + + ORG $300 + + JSR INIT + JSR RESET + LDA #LEFTCHN + STA CHN + JSR ENACHN + LDA #RIGHTCHN + STA CHN + JSR ENACHN + JMP LOOP + +SETVOL NOP +NEXT LDA SONG + CLC + ADC #$03 + STA SONG + BCC LOOP + INC SONG+1 +LOOP LDY #$00 + LDA (SONG),Y + CMP #$01 + BEQ SETVOL + BPL SETNOTE ;SET DURATION +END JSR RESET + RTS + +SETNOTE STA DURATION + LDA #LEFTCHN +SEND STA CHN + JSR OUT + INY + LDA (SONG),Y + BEQ SKIP ;IF 0 KEEP LTTSA + JSR CONVFREQ +SKIP LDA TONE + JSR OUT + INC CHN + LDA CHN + JSR OUT + LDA TONE+1 + JSR OUT + LDA #RIGHTCHN + STA CHN + CPY #$02 + BNE SEND + LDX DURATION +W1 LDY TEMPO +W2 DEC TEMP + BNE W2 + DEY + BNE W2 + DEX + BNE W1 + BIT $C000 + BMI END + JMP NEXT + +CONVFREQ LDX OCTAVE + INX + PHA + LDA #$00 + STA TONE+1 + PLA +DECOCT DEX + BMI LOBYTE + ASL + ROL TONE+1 + JMP DECOCT +LOBYTE STA TONE + RTS + + +INIT LDA #$0B + STA ACIACMD2 + LDA #$9E + STA ACIACTL2 + RTS + +OUT PHA ;SAVE BYTE TO SEND OUT +WT LDA ACIAST2 ;READ STATUS OF SERIAL PORT + AND #$10 ;SEE IF IT'S READY TO RECEIVE A BYTE + BEQ WT ;NOT READY, WAIT + PLA ;REGET BYTE TO SEND OUT + STA ACIARXTX2 ;SEND IT + RTS + +IN LDA ACIAST2 ;IS THERE A BYTE TO GET YET? + AND #$08 + BEQ IN ;NOPE, WAIT FOR IT + LDA ACIARXTX2 ;GET INCOMING BYTE + RTS + +RESET LDA #$A1 + JSR OUT + RTS + +ENACHN LDA #ENAREG + ORA CHN + JSR OUT + LDA #%00111110 + JSR OUT + LDA #VOL_A + ORA CHN + JSR OUT + LDA #$0F + JSR OUT + RTS + +OCTAVE DFB 1 +TEMPO DFB 8 +TEMP DFB 0 diff --git a/src/MOCKINGDUET.S b/src/MOCKINGDUET.S new file mode 100644 index 0000000..080a297 --- /dev/null +++ b/src/MOCKINGDUET.S @@ -0,0 +1,137 @@ +*ELECTRIC DUET MUSIC PLAYER FOR THE MOCKINGBOARD +*COPYRIGHT 2014 CYBERNESTO + +CHN = $1D +SONG = $1E +LEFTCHN = $00 +RIGHTCHN = $02 +ENAREG = $07 +VOL_A = $08 +VOL_B = $09 +TONE = $06 +DURATION = $08 + + + ORG $300 + + JSR INIT + JSR RESET + JSR ENACHN + JMP LOOP + +SETVOL +NEXT LDA SONG + CLC + ADC #$03 + STA SONG + BCC LOOP + INC SONG+1 +LOOP LDY #$00 + LDA (SONG),Y + CMP #$01 + BEQ SETVOL + BPL SETNOTE ;SET DURATION +END JSR RESET + RTS + +SETNOTE STA DURATION + LDA #LEFTCHN +SEND STA CHN + STA $C401 + JSR SETREG1 + INY + LDA (SONG),Y + BEQ SKIP ;IF 0 KEEP LTTSA + JSR CONVFREQ +SKIP LDA TONE + STA $C401 + JSR WRDATA1 + INC CHN + LDA CHN + STA $C401 + JSR SETREG1 + LDA TONE+1 + STA $C401 + JSR WRDATA1 + LDA #RIGHTCHN + STA CHN + CPY #$02 + BNE SEND + LDX DURATION +W1 LDY TEMPO +W2 DEC TEMP + BNE W2 + DEY + BNE W2 + DEX + BNE W1 + BIT $C000 + BMI END + JMP NEXT + +CONVFREQ LDX OCTAVE + INX + PHA + LDA #$00 + STA TONE+1 + PLA +DECOCT DEX + BMI LOBYTE + ASL + ROL TONE+1 + JMP DECOCT +LOBYTE STA TONE + RTS + + +RESET LDA #$00 + STA $C400 + STA $C480 + LDA #$04 + STA $C400 + STA $C480 + RTS + +INIT LDA #$FF + STA $C403 + STA $C483 + LDA #$07 + STA $C402 + STA $C482 + RTS + +SETREG1 LDA #$07 + STA $C400 + LDA #$04 + STA $C400 + RTS + +WRDATA1 LDA #$06 + STA $C400 + LDA #$04 + STA $C400 + RTS + +ENACHN LDA #ENAREG + STA $C401 + JSR SETREG1 + LDA #%00111100 + STA $C401 + JSR WRDATA1 + LDA #VOL_A + STA $C401 + JSR SETREG1 + LDA #$0F + STA $C401 + JSR WRDATA1 + LDA #VOL_B + STA $C401 + JSR SETREG1 + LDA #$0F + STA $C401 + JSR WRDATA1 + RTS + +OCTAVE DFB 1 +TEMPO DFB 8 +TEMP DFB 0 diff --git a/src/PLAYER.ED.S b/src/PLAYER.ED.S new file mode 100644 index 0000000..1412a68 --- /dev/null +++ b/src/PLAYER.ED.S @@ -0,0 +1,264 @@ + + LST OFF + DSK /HD1/DCKDLIB/LNK/MUSIC/PLAYER.ED + REL + +******************************** +* * +* Source: ELECTRIC DUET * +* interruptible pour intros * +* * +******************************** + +* Utilisation: LDA #ED_TBL +* JSR PLAYER_ED +* +* ED_TBL DA adresse datas musique +* DFB flag interruption [0=oui,1=non] +* DA adresse interruption (0 si non inter) +* DA liste des touches autoris{es en sortie +* DFB flag inter clavier [0=temporaire,1=fin] +* DA adresse sortie key temporaire +* DFB arrete @ la fin du morceau [0=oui,1=non] +* +* Au retour d'une sortie par touche: +* carry=0 -> reprise +* carry=1 -> force sortie d{finitive +* +* Utilisation page 0: +* $06/$07/$08/$09/$1D/$1E/$1F/$4E/$4F + +******************************** + +PLAYER_ED ENT + STA $06 ; sauve pointeur table + STY $07 + +* Lecture table + + LDY #10 ; place en pile 11 octets table +:1 LDA ($06),Y + PHA + DEY + BPL :1 + + PLA + STA ED_DATA ; adr datas low + PLA + STA ED_DATA+1 ; adr datas high + PLA + STA ED_FLAG ; flag interruption + PLA + STA ED_INTER+1 ; adr low inter + PLA + STA ED_INTER+2 ; adr high inter + PLA + STA ED_KEYL+1 ; adr low liste touches + PLA + STA ED_KEYL+2 ; adr high liste touches + PLA + STA ED_FLAGK ; flag interruption clavier + PLA + STA ED_INTERK+1 ; adr low inter clavier + PLA + STA ED_INTERK+2 ; adr high inter clavier + PLA + STA ED_AGAIN+1 ; recommence du d{but ou arrete + + +* Player + +ED_M LDA ED_DATA + STA $1E + LDA ED_DATA+1 + STA $1F + + LDA #1 + STA $09 + STA $1D + + PHA + PHA + PHA + BNE H0A2B + +H0A16 INY + LDA ($1E),Y + STA $09 + INY + LDA ($1E),Y + STA $1D + +H0A20 LDA $1E + CLC + ADC #$03 + STA $1E + BCC H0A2B + INC $1F + +H0A2B LDY #$00 + LDA ($1E),Y + CMP #$01 + BEQ H0A16 + BCS H0A45 + + PLA + PLA + PLA +ED_AGAIN LDA #$FF ; [0=fin,1=recommence] + BNE ED_M ; reprise du d{but + RTS ; fin + +H0A38 LDX #$49 + INY + LDA ($1E),Y + BNE :1 + LDX #$C9 +:1 RTS + +H0A45 STA $08 + JSR H0A38 + STX H0A94 + STA $06 + LDX $09 +:1 LSR + DEX + BNE :1 + STA H0A8C+1 + JSR H0A38 + STX H0ACC + STA $07 + LDX $1D +:2 LSR + DEX + BNE :2 + STA H0AC4+1 + +******************************** + +* Interruption par JSR autoris{e ici + + LDA ED_FLAG + BNE ED_NOINTER + +ED_INTER JSR $FFFF ; adr interruption + +******************************** + +ED_NOINTER PLA + TAY + PLA + TAX + PLA + BNE H0A76 + +H0A73 BIT $C030 +H0A76 CMP #0 + BMI H0A7D + NOP + BPL H0A80 + +H0A7D BIT $C030 + +H0A80 STA $4E + BIT $C000 + BPL NOKEY + + JSR ED_KEY ; test touche autoris{e + BCS NOKEY ; non. Pas de prise en compte + + LDA ED_FLAGK ; arret d{finitif? + BNE ED_FIN ; oui + + STX ED_X ; sauve registres + STY ED_Y + LDA ED_KEYINTER ; touche enfonc{e + +ED_INTERK JSR $FFFF ; interruption touche + BCS ED_FIN ; the end (forc{) + + LDX ED_X + LDY ED_Y + JMP NOKEY ; reprise comme si de rien n'{tait + +ED_FIN RTS + +NOKEY DEY + BNE H0A8C + BEQ H0A92 + +H0A8C CPY #$36 + BEQ H0A94 + BNE H0A96 + +H0A92 LDY $06 +H0A94 EOR #$40 +H0A96 BIT $4E + BVC H0AA1 + BVS H0A9C +H0A9C BPL H0AA7 + NOP + BMI H0AAA +H0AA1 NOP + BMI H0AA7 + NOP + BPL H0AAA + +H0AA7 CMP $C030 +H0AAA DEC $4F + BNE H0ABF + DEC $08 + BNE H0ABF + BVC H0AB7 + BIT $C030 +H0AB7 PHA + TXA + PHA + TYA + PHA + JMP H0A20 + +H0ABF DEX + BNE H0AC4 + BEQ H0ACA + +H0AC4 CPX #$0C + BEQ H0ACC + BNE H0ACE + +H0ACA LDX $07 +H0ACC EOR #$80 +H0ACE BVS H0A73 + NOP + BVC H0A76 + RTS + +* Test autorisation touche + +ED_KEY STY ED_Y ; sauve Y + LDY #0 +ED_KEYL LDA $FFFF,Y + BEQ :1 ; fin des touches autoris{es + CMP $C000 + BEQ :2 ; found! + INY ; next + BNE ED_KEYL + +:2 STA ED_KEYINTER + CLC + DFB $24 ; bit + +:1 SEC ; bad key + BIT $C010 + LDY ED_Y + RTS + +******************************** + +ED_FLAG DFB 0 ; flag interruption +ED_FLAGK DFB 0 ; flag interruption clavier +ED_KEYINTER DFB 0 ; touche ayant provoqu{e l'inter +ED_DATA DFB 0,0 ; adr datas +ED_Y DFB 0 ; sauvegarde registre Y +ED_X DFB 0 ; sauvegarde registre X diff --git a/src/electricduet.asm b/src/electricduet.asm new file mode 100644 index 0000000..0a43f6f --- /dev/null +++ b/src/electricduet.asm @@ -0,0 +1,129 @@ +/*************************************************************************** + * Copyright (C) 1979-2015 by Paul Lutus * + * http://arachnoid.com/administration * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +/* Electric Duet Player Routine circa 1980 */ + +$0900> A9 01: LDA #$01 ; 2 *!* +$0902> 85 09: STA $09 ; 3 +$0904> 85 1D: STA $1D ; 3 +$0906> 48: PHA ; 3 +$0907> 48: PHA ; 3 +$0908> 48: PHA ; 3 +$0909> D0 15: BNE $0920 ; 4 *!* +$090B> C8: INY ; 2 +$090C> B1 1E: LDA ($1E),Y ; 5 *!* +$090E> 85 09: STA $09 ; 3 +$0910> C8: INY ; 2 +$0911> B1 1E: LDA ($1E),Y ; 5 *!* +$0913> 85 1D: STA $1D ; 3 +$0915> A5 1E: LDA $1E ; 3 *!* +$0917> 18: CLC ; 2 +$0918> 69 03: ADC #$03 ; 2 *!* +$091A> 85 1E: STA $1E ; 3 +$091C> 90 02: BCC $0920 ; 4 *!* +$091E> E6 1F: INC $1F ; 5 +$0920> A0 00: LDY #$00 ; 2 *!* +$0922> B1 1E: LDA ($1E),Y ; 5 *!* +$0924> C9 01: CMP #$01 ; 2 +$0926> F0 E3: BEQ $090B ; 4 *!* +$0928> B0 0D: BCS $0937 ; 4 *!* +$092A> 68: PLA ; 4 +$092B> 68: PLA ; 4 +$092C> 68: PLA ; 4 +$092D> A2 49: LDX #$49 ; 2 *!* +$092F> C8: INY ; 2 +$0930> B1 1E: LDA ($1E),Y ; 5 *!* +$0932> D0 02: BNE $0936 ; 4 *!* +$0934> A2 C9: LDX #$c9 ; 2 *!* +$0936> 60: RTS ; 6 +$0937> 85 08: STA $08 ; 3 +$0939> 20 2D09: JSR $092D ; 6 +$093C> 8E 8309: STX $0983 ; 4 +$093F> 85 06: STA $06 ; 3 +$0941> A6 09: LDX $09 ; 3 *!* +$0943> 4A: LSR A ; 2 +$0944> CA: DEX ; 2 +$0945> D0 FC: BNE $0943 ; 4 *!* +$0947> 8D 7C09: STA $097C ; 4 +$094A> 20 2D09: JSR $092D ; 6 +$094D> 8E BB09: STX $09BB ; 4 +$0950> 85 07: STA $07 ; 3 +$0952> A6 1D: LDX $1D ; 3 *!* +$0954> 4A: LSR A ; 2 +$0955> CA: DEX ; 2 +$0956> D0 FC: BNE $0954 ; 4 *!* +$0958> 8D B409: STA $09B4 ; 4 +$095B> 68: PLA ; 4 +$095C> A8: TAY ; 2 +$095D> 68: PLA ; 4 +$095E> AA: TAX ; 2 +$095F> 68: PLA ; 4 +$0960> D0 03: BNE $0965 ; 4 *!* +$0962> 2C 30C0: BIT $C030 ; 4 +$0965> C9 00: CMP #$00 ; 2 +$0967> 30 03: BMI $096C ; 4 *!* +$0969> EA: NOP ; 2 +$096A> 10 03: BPL $096F ; 4 *!* +$096C> 2C 30C0: BIT $C030 ; 4 +$096F> 85 4E: STA $4E ; 3 +$0971> 2C 00C0: BIT $C000 ; 4 +$0974> 30 C0: BMI $0936 ; 4 *!* +$0976> 88: DEY ; 2 +$0977> D0 02: BNE $097B ; 4 *!* +$0979> F0 06: BEQ $0981 ; 4 *!* +$097B> C0 00: CPY #$00 ; 2 +$097D> F0 04: BEQ $0983 ; 4 *!* +$097F> D0 04: BNE $0985 ; 4 *!* +$0981> A4 06: LDY $06 ; 3 *!* +$0983> 49 40: EOR #$40 ; 2 *!* +$0985> 24 4E: BIT $4E ; 3 +$0987> 50 07: BVC $0990 ; 4 *!* +$0989> 70 00: BVS $098B ; 4 *!* +$098B> 10 09: BPL $0996 ; 4 *!* +$098D> EA: NOP ; 2 +$098E> 30 09: BMI $0999 ; 4 *!* +$0990> EA: NOP ; 2 +$0991> 30 03: BMI $0996 ; 4 *!* +$0993> EA: NOP ; 2 +$0994> 10 03: BPL $0999 ; 4 *!* +$0996> CD 30C0: CMP $C030 ; 4 +$0999> C6 4F: DEC $4F ; 5 +$099B> D0 11: BNE $09AE ; 4 *!* +$099D> C6 08: DEC $08 ; 5 +$099F> D0 0D: BNE $09AE ; 4 *!* +$09A1> 50 03: BVC $09A6 ; 4 *!* +$09A3> 2C 30C0: BIT $C030 ; 4 +$09A6> 48: PHA ; 3 +$09A7> 8A: TXA ; 2 +$09A8> 48: PHA ; 3 +$09A9> 98: TYA ; 2 +$09AA> 48: PHA ; 3 +$09AB> 4C 1509: JMP $0915 ; 3 +$09AE> CA: DEX ; 2 +$09AF> D0 02: BNE $09B3 ; 4 *!* +$09B1> F0 06: BEQ $09B9 ; 4 *!* +$09B3> E0 00: CPX #$00 ; 2 +$09B5> F0 04: BEQ $09BB ; 4 *!* +$09B7> D0 04: BNE $09BD ; 4 *!* +$09B9> A6 07: LDX $07 ; 3 *!* +$09BB> 49 80: EOR #$80 ; 2 *!* +$09BD> 70 A3: BVS $0962 ; 4 *!* +$09BF> EA: NOP ; 2 +$09C0> 50 A3: BVC $0965 ; 4 *!* \ No newline at end of file