AI That Plays Melodies
Now that I was able to generate note messages, I asked ChatGPT to create a program that plays a melody.
I followed these steps to make the request:
- As in the previous attempt, I asked ChatGPT to generate a program in Z80 assembler to produce note signals. This time, I specified both the address of the ACIA status register and the data register.
- Since the A register was being overwritten in the MIDI transmission subroutine, I asked ChatGPT to fix this issue.
- I requested a modification to store the pitch information in a table format.
- I then asked ChatGPT to generate the pitch sequence for "Greensleeves" in the table. (It seems that ChatGPT couldn’t generate it correctly.)
- Since the instruction
IN A, (B)
was being generated, I requested a correction.
With these steps, the assembler program was created, which I downloaded to my computer and generated a HEX file. Although it wasn’t "Greensleeves," I was able to play some melody.
https://chatgpt.com/share/67026d7d-ab60-8003-9f54-4ff0b840cc6b
ORG $8000 ; Program starts at address $8000
START:
LD HL, NOTE_TABLE ; Point HL to the start of the note table
NEXT_NOTE:
LD A, (HL) ; Load the next note number from the table
CP 0 ; Check if the note number is 0 (end of the table)
JR Z, DONE ; If 0, end the program
CALL SEND_NOTE_ON ; Send Note-On message for this note
CALL LONG_DELAY ; Long delay before sending Note-Off
CALL SEND_NOTE_OFF ; Send Note-Off message for this note
INC HL ; Move to the next note in the table
JR NEXT_NOTE ; Repeat for the next note
DONE:
RET ; Return to the caller when done
; Subroutine to send a Note-On message
SEND_NOTE_ON:
LD A, $90 ; Load Note-On status byte (channel 1, note-on)
CALL SEND_MIDI ; Send the status byte
LD A, (HL) ; Load the note number from the table
CALL SEND_MIDI ; Send the note number
LD A, $7F ; Load velocity (127, maximum)
CALL SEND_MIDI ; Send the velocity
RET ; Return to the main routine
; Subroutine to send a Note-Off message
SEND_NOTE_OFF:
LD A, $80 ; Load Note-Off status byte (channel 1, note-off)
CALL SEND_MIDI ; Send the status byte
LD A, (HL) ; Load the note number from the table
CALL SEND_MIDI ; Send the note number
LD A, $00 ; Load velocity (0, note-off)
CALL SEND_MIDI ; Send the velocity
RET ; Return to the main routine
; Subroutine to send a MIDI byte, preserving A
SEND_MIDI:
PUSH AF ; Preserve register A by pushing AF to the stack
WAIT_READY:
IN A, ($A0) ; Read the status register from address $A0
BIT 1, A ; Check if transmit data register empty (bit 1 = 1)
JR Z, WAIT_READY ; Wait until the data register is ready
POP AF ; Restore A from the stack
OUT ($A1), A ; Send the byte to the data register at address $A1
RET ; Return to the main routine
; Long delay routine (for longer duration between notes)
LONG_DELAY:
LD BC, $FFFF ; Load a larger value into BC for longer delay
DELAY_LOOP:
DEC BC ; Decrement BC
LD A, B ; Check upper byte
OR C ; Combine upper and lower bytes
JR NZ, DELAY_LOOP ; Continue looping until BC = 0
RET ; Return after delay
; Data table of MIDI note numbers for "Greensleeves" melody (0 terminates the table)
NOTE_TABLE:
DB $40, $43, $45, $47, $45, $43, $40 ; A3, C#4, E4, F#4, E4, C#4, A3
DB $40, $43, $45, $47, $45, $43, $40 ; Repeat similar phrase
DB $45, $47, $48, $47, $45, $43, $40 ; E4, F#4, G#4, F#4, E4, C#4, A3
DB 0 ; End of the table
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.