NASM - The Netwide Assembler
NASM Forum => Programming with NASM => Topic started by: angela on February 08, 2013, 05:58:24 PM
-
Hello,
i need to make a music player with assembly nasm which will open an existing file with a melody and will play that melody with pc speaker.
i took this code:
; read the file back into a buffer
mov ah,03Dh ; the open-existing-file function
mov al,0 ; open moppde 0=read,1=write,2=both
mov dx,filename ; address of zero-terminated string
int 021h ; call on Good Old Dos
mov [filehndl],ax ; we'll reuse the filehndl variable,
; but use a different one if you open
; more than one :)
mov ah,03Fh ; the read-from-a-file function
mov bx,[filehndl] ; our new (same as old, probably) file handle
mov cx,0FFh ; max bytes to read
mov dx,iobuf ; address of a buffer to read into
int 021h ; call on Good Old Dos
mov [read_len],ax ; save the number of bytes read
mov ah,03Eh ; close the file
mov bx,[filehndl] ; yeah, file handle in bx
int 021h ; call on Good Old Dos
which reads from a file, and i want to put the content of the file into a register so as to pass it to the "music piece" of my code.
i understand that the content of the file is in the iobuf
but i can't pass it to a register
Thanx
-
I'm not sure I understand the question. You've got 255 bytes (or less?) of this "melody" file in "inbuf". You could pass the "[contents]" one byte at a time, or two bytes, or four bytes(?) to your "music" routine. I think more likely what you want to do is pass the address of "inbuf" to your routine, and pick it apart there. I'm guessing the contents of your melody file is "tone", "duration", "pause length" and repeat...(?)
; read file...
mov si, inbuf ; address of our buffer
; maybe "mov cx, [read_length]"
call play_music
;...
play_music:
lodsb ; "tone" in al
out 42h, al
; etc...
Perhaps word (lodsw) for better resolution...
lodsw
out 42h, al
mov al, ah
out 42h, al
...
But perhaps I don't understand what you're trying to do... I've got a crude "beep the speaker" program for dos (you sure you want to do this for dos?) but the "tune" is hard-coded into it, not read from file. I can post it if you think it'll help...
Best,
Frank
-
j
-
thank you very much for the reply.
what i need to do is to have a txt file which will contain the frequencies and the durations of the notes and the program will read from this file and play the beeps.
My problem is that whatever i put into the file, it is displayed on the screen but it does not affect the beap
here is my code
org 100h
;--------------------------------------------------
section .data
filename db 'testtext.txt',0
print_start: dw 160
;--------------------------------------------------
section .bss
textbuf resb 0100h
iobuf resb 0100h
text_len resw 01h
read_len resw 01h
filehndl resw 01h
note_num resw 01h
note resw 01h
note_len resw 01h
;--------------------------------------------------
vidmem equ 0xb800 ; Start of VGA text-memory
scrw equ 80*25 ; Size of video memory in words
eom equ 0 ; end of message (\0, null character like C)
;--------------------------------------------------
section .text
; read the file back into a buffer
mov ah,03Dh ; the open-existing-file function
mov al,0 ; open moppde 0=read,1=write,2=both
mov dx,filename ; address of zero-terminated string
int 021h ; call on Good Old Dos
mov [filehndl],ax ; we'll reuse the filehndl variable,
; but use a different one if you open
; more than one :)
mov ah,03Fh ; the read-from-a-file function
mov bx,[filehndl] ; our new (same as old, probably) file handle
mov cx,0FFh ; max bytes to read
mov dx,iobuf ; address of a buffer to read into
int 021h ; call on Good Old Dos
mov [read_len],ax ; save the number of bytes read
mov ah,03Eh ; close the file
mov bx,[filehndl] ; yeah, file handle in bx
int 021h ; call on Good Old Dos
; and write it out to already-open standard output
mov ah,040h ; write-to-a-file
mov bx,1 ; file handle for standard output
mov cx,[read_len] ; bytes to write - same number we read :)
mov dx,iobuf ; buffer to write from
int 021h ; call on Good Old Dos
;--------------------------------------------------------------------
mov si,iobuf
; mov dl,2
music:
mov al, 182 ; Prepare the speaker for the
out 43h, al ; note.
mov ax, 5000 ; Frequency number (in decimal)
; for middle C.
out 42h, al ; Output low byte.
mov al, ah ; Output high byte.
out 42h, al
in al, 61h ; Turn on note (get value from
; port 61h).
or al, 00000011b ; Set bits 1 and 0.
out 61h, al ; Send new value.
mov bx, 25 ; Pause for duration of note.
pause1:
mov cx, 65535
pause2:
dec cx
jne pause2
dec bx
jne pause1
in al, 61h ; Turn off note (get value from
; port 61h).
and al, 11111100b ; Reset bits 1 and 0.
out 61h, al ; Send new value.
mov bx, 25 ; Pause for duration of note.
pause3:
mov cx, 65535
pause4:
dec cx
jne pause4
dec bx
jne pause3
ret
; dec dl
; jnz loop
;--------------------------------------
-
The code above is a sample to see if i can make my pc beep
My professor gave me this code below, but even this has a problem with the timer on the delay loop. Could you help me with this too?
Thanx in advance
;----------------------------------------------------------
; CONSTANTS
;----------------------------------------------------------
;------------ freqs.asm gives pairs of frequencies to notes
%include "freqs.asm"
;----------------------------------------------------------
; Note lengths
whole equ 0
half equ 1
quarter equ 2
eighth equ 3
sixteenth equ 4
;----------------------------------------------------------
; DATA
; Description:
; Here we define and reserve all of our global variables
;
;----------------------------------------------------------
[SECTION .data]
ticks_whole: db 0
ticks_half: db 0
ticks_quarter: db 0
ticks_eighth: db 0
ticks_sixteenth: db 0
tempo: dw 120
;----------------------------------------------------------
; TEXT
; Description:
; The part of the file containing the code
; Functions:
; enable_speaker -> enables the speaker
; disable_speaker -> disables the speaker
; init_tempo -> initializes note durations
; play_note -> plays a frequency for a specific amount of time
; play_tune -> plays a frequency through the speaker
; play_delay -> delays for a specific amount of time
;----------------------------------------------------------
[SECTION .text]
[BITS 32]
;----------------------------------------------------------
; Procedure void soundtest()
; performs the exhibition of the driver
; * It 's a working paradigm of the procedures that were
; * implemented
; Arguments:
; none
; Local Variables:
; none
; Returns:
; nothing
;----------------------------------------------------------
soundtest:
push ebp
mov ebp, esp
push edx
push ecx
push ebx
push word [tempo]
call init_tempo
add sp, 2
call enable_speaker
; Here Starts the main part of the routine
; where most of the functionality should be implemented
;---------------------------------------------
soundtest_loop:
mov ecx, 0xfffff
mov ebx,oct4_g ; load note
mov edx,eighth ; load duration
push edx
push ebx
call play_note
add sp,8
mov ebx,oct2_g ; load note
mov edx,quarter ; load duration
push edx
push ebx
call play_note
add sp,8
loop soundtest_loop
;---------------------------------------------
; Exit Point
call disable_speaker
pop ebx
pop ecx
pop edx
pop ebp
ret
;----------------------------------------------------------
; Procedure void enable_speaker()
; Enables the speaker and let it waiting for tunes to be played
; Arguments:
; none
; Local Variables:
; none
; Returns:
; nothing
;----------------------------------------------------------
enable_speaker:
push eax
; tell cpu to connect the speaker with timer 2.
; by doing this, every time timer 2 oscillates,
; so does the speaker, producing a "click"
in ax,0x61
or ax,0x3
out 0x61,ax
pop eax
ret
;----------------------------------------------------------
; Procedure void disable_speaker()
; Disables the speaker
; Arguments:
; none
; Local Variables:
; none
; Returns:
; nothing
;----------------------------------------------------------
disable_speaker:
push eax
; disconnecting speaker from timer 2
in ax,0x61
and ax,252
out 0x61,ax
pop eax
ret
;----------------------------------------------------------
; Procedure void init_tempo(int *ptempo)
; Initializes various note lengths
; As each note duration corresponds to a specific value
; of timer ticks, we must adjust each of the durations
; to that proper value
; Arguments:
; int *ptempo: a pointer to some tempo value
; Local Variables:
; none
; Returns:
; nothing
;----------------------------------------------------------
init_tempo:
push ebp
mov ebp,esp
push eax
push ebx
; calculating quarter
mov ax,1080
mov bx,[ebp + 8]
div bl
; calculating sixteenth and adjusting all
; other durations based on the value of it
shr al,2
mov [ticks_sixteenth],al
shl al,1
mov [ticks_eighth],al
shl al,1
mov [ticks_quarter],al
shl al,1
mov [ticks_half],al
shl al,1
mov [ticks_whole],al
pop ebx
pop eax
pop ebp
ret
;----------------------------------------------------------
; Procedure void play_note(int freq, int duration)
; Plays a note
; Arguments:
; int freq: the frequency to be played
; int duration: the duration of note to be played
; Local Variables:
; none
; Returns:
; nothing
;----------------------------------------------------------
play_note:
push ebp
mov ebp,esp
push eax
push ebx
mov ebx,[ebp + 8] ; preparing bx for play_tune()
call play_tune
mov eax,[ebp + 12] ; preparing ax for delay()
call play_delay
pop ebx
pop eax
pop ebp
ret
;----------------------------------------------------------
; Procedure void play_tune()
; Plays a tune the frequency of which is stored in bx.
; Bx used instead of stack as this function was not meant
; to be used but from within a wrapper
; Arguments:
; none
; Local Variables:
; none
; Returns:
; nothing
; Uses:
; bx: frequency to be played
;----------------------------------------------------------
play_tune:
push edx
push eax
; telling timer 2 we are about to send a
; new countdown value
mov al,0xb6
out 0x43,al
; calculating in al the proper countdown
; value for frequency in bx. 0x1234DC is
; the frequency of main system oscillator
mov ax,0x34DC
mov dx,0x12
div bx
; sending countdown value to timer 2
out 0x42,al
shr ax,8
out 0x42,al
pop eax
pop edx
ret
;----------------------------------------------------------
; Procedure void play_delay()
; Delays doing a loop of a predifined duration which
; is stored in al
; Arguments:
; none
; Local Variables:
; none
; Returns:
; nothing
; Uses:
; al: one of the following predifined durations:
; [ whole, half, quarter, eighth, sixteenth ]
;----------------------------------------------------------
play_delay:
push eax ; in fact, we care only about ah
push ebx
mov ebx, [timer]
; switch (al) // note duration
cmp al,eighth ; case (eighth):
jz is_eighth ; jmp is_eighth
cmp al,quarter ; case (quarter):
jz is_quarter ; jmp is_quarter
cmp al,half ; case (half):
jz is_half ; jmp is_half
cmp al,sixteenth ; case (sixteenth)
jz is_sixteenth ; jmp is_sixteenth
cmp al,whole ; case (whole)
jz is_whole ; jmp is_whole
is_sixteenth: xor eax, eax
mov al,[ticks_sixteenth]
add ebx,eax
jmp delay_loop
is_eighth: xor eax, eax
mov al,[ticks_eighth]
add ebx,eax
jmp delay_loop
is_quarter: xor eax, eax
mov al,[ticks_quarter]
add ebx,eax
jmp delay_loop
is_half: xor eax, eax
mov al,[ticks_half]
add ebx,eax
jmp delay_loop
is_whole: xor eax, eax
mov al,[ticks_whole]
add ebx,eax
jmp delay_loop
delay_loop: cmp dword [timer],ebx
jb delay_loop
pop ebx
pop eax
ret
%ifndef FREQUENCES_ASM
%define FREQUENCES_ASM
silence equ 65535
oct1_e equ 21
oct1_f equ 22
oct1_f# equ 23
oct1_g equ 24
oct1_g# equ 26
oct1_a equ 27
oct1_a# equ 29
oct1_b equ 31
oct2_c equ 33
oct2_c# equ 35
oct2_d equ 37
oct2_d# equ 39
oct2_e equ 41
oct2_f equ 44
oct2_f# equ 46
oct2_g equ 49
oct2_g# equ 52
oct2_a equ 55
oct2_a# equ 58
oct2_b equ 62
oct3_c equ 65
oct3_c# equ 69
oct3_d equ 73
oct3_d# equ 78
oct3_e equ 82
oct3_f equ 87
oct3_f# equ 92
oct3_g equ 98
oct3_g# equ 104
oct3_a equ 110
oct3_a# equ 116
oct3_b equ 123
oct4_c equ 131
oct4_c# equ 139
oct4_d equ 147
oct4_d# equ 155
oct4_e equ 165
oct4_f equ 175
oct4_f# equ 185
oct4_g equ 196
oct4_g# equ 208
oct4_a equ 220
oct4_a# equ 233
oct4_b equ 245
oct5_c equ 262
oct5_c# equ 277
oct5_d equ 294
oct5_d# equ 311
oct5_e equ 330
oct5_f equ 349
oct5_f# equ 370
oct5_g equ 392
oct5_g# equ 415
oct5_a equ 440
oct5_a# equ 466
oct5_b equ 494
oct6_c equ 523
oct6_c# equ 554
oct6_d equ 587
oct6_d# equ 622
oct6_e equ 659
oct6_f equ 698
oct6_f# equ 740
oct6_g equ 784
oct6_g# equ 831
oct6_a equ 880
oct6_a# equ 932
oct6_b equ 988
oct7_c equ 1046
oct7_c# equ 1109
oct7_d equ 1175
oct7_d# equ 1244
oct7_e equ 1328
oct7_f equ 1397
oct7_f# equ 1480
oct7_g equ 1568
oct7_g# equ 1661
oct7_a equ 1760
oct7_a# equ 1865
oct7_b equ 1975
oct8_c equ 2093
oct8_c# equ 2217
oct8_d equ 2349
oct8_d# equ 2489
oct8_e equ 2637
oct8_f equ 2794
oct8_f# equ 2960
oct8_g equ 3136
oct8_g# equ 3322
oct8_a equ 3520
oct8_a# equ 3729
oct8_b equ 3951
%endif
-
This is going to require some study, and I've got company right now so I'll have to get back to it. I may have to actually boot to dos and try it.
Initial observations: your .com file looks good, as far as it goes. I'm not sure you've got the delay right. Looping for a delay is unreliable anyway - plays at different speeds on different machines. There's a bios interrupt that might be better...
Your professor's code says "bits 32", which is not going to play nicely with your .com file. Looks like a strange mixture of 32- and 16-bit code. I think I understand what he/she is doing, but I don't quite see where "timer" is defined. I'm not sure how the frequency equates are intended to be used.
What do you see when you print the file? Garbage, which would indicate a binary file, or text like "oct1_e", or text like "1234"?
I'll have to get back to you on this. Here's an example that used to work, to "play" with... I don't even remember how it works, at the moment. :)
Later,
Frank
; Plays a tune, of sorts - sound, anyway.
; It is said that I'm not artistic.
;
; nasm -f bin -o play.com play.asm
;
; or add proprietary junk as required
org 100h ; we are a .com file
; (nasm defaults to "section .text")
; set up PIT
mov al, 10111110b
;.......|------ binary 16-bit counter
;....|||------- square wave generator
;..||---------- r/w bits 0-7, then 8-15
;||------------ select counter 2
out 43h, al
mov si, melody ; "offset" - if p.j.
playit_sam: ; if she can take it, so can I.
in al, 61h ; enable speaker
or al, 00000011b
;.......|------- enable speaker on timer 2 gate
;......|-------- enable speaker data
out 61h, al
lodsw ; get a note
or ax, ax ; check for zero
jz egress ; coda
out 42h, al ; play it
mov al, ah
out 42h ,al
lodsw ; for this long
call delay
in al, 61h ; Turn Speaker OFF
and al, 11111100b
out 61h, al
lodsw ; for this long
call delay
jmp short playit_sam ; play more
egress:
in al, 61h
and al, 0FCh ; Turn Speaker OFF. Please.
out 61h, al
ret
;------------------
;------------------
delay:
mov cx, ax ; this trashes ax, cx, dx, too :)
cmp cx, byte 1 ; special case, no delay
jz no_delay
shr cx, 3 ; because it sounds okay :)
xor dx, dx
mov ah, 86h ; bios delay - cx:dx microseconds
int 15h
no_delay:
ret
;------------------
; Some equates, for your compositional assistance
; It is said that I'm not artistic.
A0 equ 21728
B0 equ 19328
C0 equ 18244
D0 equ 16144
E0 equ 14080
F0 equ 13668
G0 equ 12176
A1 equ 10864
B1 equ 9664
C1 equ 9122
D1 equ 8072
E1 equ 7040
F1 equ 6834
G1 equ 6088
A2 equ 5432
B2 equ 4832
C2 equ 4561
D2 equ 4063
E2 equ 3520
F2 equ 3417
G2 equ 3044
A3 equ 2712
B3 equ 2416
C3 equ 2280
D3 equ 2032
E3 equ 1810
F3 equ 1708
G3 equ 1522
A4 equ 1356
B4 equ 1208
C4 equ 1140
D4 equ 1016
E4 equ 905
F4 equ 854
G4 equ 762
A5 equ 678
B5 equ 604
C5 equ 558
; Some "durations"
Z equ 1
S equ 10
Q equ 20
P equ 40
R equ 80
L equ 320
; The opus itself.
;
; It is said that I'm not artistic.
;
; Format is "note", "duration", "pause", "note", ... , 0
; Write your own!
melody:
%if 1
dw G2, P, Z, E2, Q, Z, G2, Q, Q, G1, Q, Q
dw G1, Q, Q, C2, Q, Q, B2, Q, Z, C2, Q, Z
dw D2, Q, Q, G2, Q, Q, A3, Q, Z, G2, Q, Z
dw A3, Q, Q, A2, Q, Q, A2, Q, Q, G2, Q, Q
dw E2, Q, Z, G2, Q, Z, F2, Q, Z
dw E2, Q, Z, D2, Q, Q, F2, Q, Z, G2, Q, Z
dw A3, Q, Z, G2, Q, Z, F2, Q, Z, E2, Q, Z
dw F2, Q, Z, E2, Q, Z, D2, Q, Z, B2, Q, Z
dw C2, Q, Z, D2, Q, Z, E2, Q, Z, C2, Q, Z
dw D2, Q, Q, G3, Q, Z, F3, Q, Z, E3, Q, Z
dw D3, Q, Z, C3, Q, Z, B3, Q, Z, A3, Q, Z
dw B3, Q, Z, C3, Q, Z, D3, Q, Z, B3, Q, Q
dw G0, Q, Q, G0, R, Z, 0
%endif
dw C5, R, Q, A0, R, Z, 0
-
Hello, here it is a program I wrote sometime ago, it's about a piano that you can play with the cursor of your mouse. There're some macros that it uses that I don't have at this moment, but I can provide you if you are really interested in it. Regards.
-
Well... I rebooted into dos. I forget how to do this! I made some modifications to your file:
org 100h
;--------------------------------------------------
section .data
filename db 'testtext.txt',0
print_start: dw 160
; lacking the file...
; this is note, duration, pause, zero-terminated
dummybuf dw 5000, 20, 10, 7000, 10, 5, 4000, 10, 4
dw 1000, 30, 10, 8000, 40, 10 , 0, 0, 0
;--------------------------------------------------
section .bss
textbuf resb 0100h
iobuf resb 0100h
text_len resw 01h
read_len resw 01h
filehndl resw 01h
note_num resw 01h
note resw 01h
note_len resw 01h
;--------------------------------------------------
vidmem equ 0xb800 ; Start of VGA text-memory
scrw equ 80*25 ; Size of video memory in words
eom equ 0 ; end of message (\0, null character like C)
;--------------------------------------------------
section .text
; lacking the file...
jmp testbeep
; read the file back into a buffer
mov ah,03Dh ; the open-existing-file function
mov al,0 ; open moppde 0=read,1=write,2=both
mov dx,filename ; address of zero-terminated string
int 021h ; call on Good Old Dos
mov [filehndl],ax ; we'll reuse the filehndl variable,
; but use a different one if you open
; more than one :)
mov ah,03Fh ; the read-from-a-file function
mov bx,[filehndl] ; our new (same as old, probably) file handle
mov cx,0FFh ; max bytes to read
mov dx,iobuf ; address of a buffer to read into
int 021h ; call on Good Old Dos
mov [read_len],ax ; save the number of bytes read
mov ah,03Eh ; close the file
mov bx,[filehndl] ; yeah, file handle in bx
int 021h ; call on Good Old Dos
; and write it out to already-open standard output
mov ah,040h ; write-to-a-file
mov bx,1 ; file handle for standard output
mov cx,[read_len] ; bytes to write - same number we read :)
mov dx,iobuf ; buffer to write from
int 021h ; call on Good Old Dos
testbeep:
;--------------------------------------------------------------------
; mov si,iobuf
; lacking the file...
mov si, dummybuf
music:
mov al, 182 ; Prepare the speaker for the
out 43h, al ; note.
top:
lodsw
test ax, ax
jz exit
out 42h, al ; Output low byte.
mov al, ah ; Output high byte.
out 42h, al
in al, 61h ; Turn on note (get value from
; port 61h).
or al, 00000011b ; Set bits 1 and 0.
out 61h, al ; Send new value.
lodsw
mov cx, ax
xor dx, dx
mov ah, 86h
int 15h
in al, 61h ; Turn off note (get value from
; port 61h).
and al, 11111100b ; Reset bits 1 and 0.
out 61h, al ; Send new value.
lodsw
mov cx, ax
xor dx, dx
mov ah, 86h
int 15h
jmp top
exit:
ret
;--------------------------------------
It's a long way from what you want, but at least it makes some beeps. My example that "used to work" plays much faster than I remember. That's not right either. I couldn't get any sound out of Alfonso's "piano". That could be a mouse issue - my mouse (trackball) is pretty beat. Pretty much a total loss!
Your professor's code specifies "bits 32" and then does "add sp, 8" and such. That'll "probably" work, but it's begging for trouble! then it does:
soundtest_loop:
mov ecx, 0xfffff
mov ebx,oct4_g ; load note
mov edx,eighth ; load duration
push edx
push ebx
call play_note
add sp,8
mov ebx,oct2_g ; load note
mov edx,quarter ; load duration
push edx
push ebx
call play_note
add sp,8
loop soundtest_loop
That's going to loop a long time! I don't think this code is "good to go". There may be examples of how to do some of the things you'll need to do, but I don't think you can use much of it as-is.
Who provides the file you're reading in? What's its format? I can see that the equates your professor provided might come in handy if you need to create it... make a "source code" file for it using the equates, and "assemble" it into a binary file that your code reads... ?
You seem to be able to read the file. Really ought to check for error (jc error) to make sure that the open succeeds before proceeding. (might be my error... that code looks a little familiar). And your "beep" seems to work. So it's "just" a question of interpreting the file and converting it to notes and durations. We need to know more about the file...
Best,
Frank
-
I couldn't get any sound out of Alfonso's "piano".
It works for me, cmd in WXP and dosbox... of course you have to hold down the left button of the mouse to get any sound... inside the frame of the "piano". Regards.
-
Thanks for the reply,
I tried your (first) code and it did work. the example the professor gave is to be used as reference probably. anyway the thing missing is if i could have the label you use "melody" and save its offset in SI register, but instead of having it in the code, i want to read the melody from a file (txt).
i have been able to read a file into iobuf and then read it back byte by byte but when i try it with your code for music it doesnt work
I really thank you for your time
org 100h ; we are a .com file
; (nasm defaults to "section .text")
mov ah,03Dh ; the open-existing-file function
mov al,0 ; open moppde 0=read,1=write,2=both
mov dx,filename ; address of zero-terminated string
int 021h ; call on Good Old Dos
mov [filehndl],ax ; we'll reuse the filehndl variable,
; but use a different one if you open
; more than one :)
mov ah,03Fh ; the read-from-a-file function
mov bx,[filehndl] ; our new (same as old, probably) file handle
mov cx,0FFh ; max bytes to read
mov dx,iobuf ; address of a buffer to read into
int 021h ; call on Good Old Dos
mov [read_len],ax ; save the number of bytes read
mov ah,03Eh ; close the file
mov bx,[filehndl] ; yeah, file handle in bx
int 021h ; call on Good Old Dos
; set up PIT
mov al, 10111110b
;.......|------ binary 16-bit counter
;....|||------- square wave generator
;..||---------- r/w bits 0-7, then 8-15
;||------------ select counter 2
out 43h, al
mov si, iobuf ; "offset" - if p.j.
playit_sam: ; if she can take it, so can I.
in al, 61h ; enable speaker
or al, 00000011b
;.......|------- enable speaker on timer 2 gate
;......|-------- enable speaker data
out 61h, al
lodsw ; get a note
or ax, ax ; check for zero
jz egress ; coda
out 42h, al ; play it
mov al, ah
out 42h ,al
lodsw ; for this long
call delay
in al, 61h ; Turn Speaker OFF
and al, 11111100b
out 61h, al
lodsw ; for this long
call delay
jmp short playit_sam ; play more
egress:
in al, 61h
and al, 0FCh ; Turn Speaker OFF. Please.
out 61h, al
ret
;------------------
;------------------
delay:
mov cx, ax ; this trashes ax, cx, dx, too :)
cmp cx, byte 1 ; special case, no delay
jz no_delay
shr cx, 3 ; because it sounds okay :)
xor dx, dx
mov ah, 86h ; bios delay - cx:dx microseconds
int 15h
no_delay:
ret
;------------------
; Some equates, for your compositional assistance
; It is said that I'm not artistic.
A0 equ 21728
B0 equ 19328
C0 equ 18244
D0 equ 16144
E0 equ 14080
F0 equ 13668
G0 equ 12176
A1 equ 10864
B1 equ 9664
C1 equ 9122
D1 equ 8072
E1 equ 7040
F1 equ 6834
G1 equ 6088
A2 equ 5432
B2 equ 4832
C2 equ 4561
D2 equ 4063
E2 equ 3520
F2 equ 3417
G2 equ 3044
A3 equ 2712
B3 equ 2416
C3 equ 2280
D3 equ 2032
E3 equ 1810
F3 equ 1708
G3 equ 1522
A4 equ 1356
B4 equ 1208
C4 equ 1140
D4 equ 1016
E4 equ 905
F4 equ 854
G4 equ 762
A5 equ 678
B5 equ 604
C5 equ 558
; Some "durations"
Z equ 1
S equ 10
Q equ 20
P equ 40
R equ 80
L equ 320
; The opus itself.
;
; It is said that I'm not artistic.
;
; Format is "note", "duration", "pause", "note", ... , 0
; Write your own!
melody:
%if 1
dw G2, P, Z, E2, Q, Z, G2, Q, Q, G1, Q, Q
dw G1, Q, Q, C2, Q, Q, B2, Q, Z, C2, Q, Z
dw D2, Q, Q, G2, Q, Q, A3, Q, Z, G2, Q, Z
dw A3, Q, Q, A2, Q, Q, A2, Q, Q, G2, Q, Q
dw E2, Q, Z, G2, Q, Z, F2, Q, Z
dw E2, Q, Z, D2, Q, Q, F2, Q, Z, G2, Q, Z
dw A3, Q, Z, G2, Q, Z, F2, Q, Z, E2, Q, Z
dw F2, Q, Z, E2, Q, Z, D2, Q, Z, B2, Q, Z
dw C2, Q, Z, D2, Q, Z, E2, Q, Z, C2, Q, Z
dw D2, Q, Q, G3, Q, Z, F3, Q, Z, E3, Q, Z
dw D3, Q, Z, C3, Q, Z, B3, Q, Z, A3, Q, Z
dw B3, Q, Z, C3, Q, Z, D3, Q, Z, B3, Q, Q
dw G0, Q, Q, G0, R, Z, 0
%endif
dw C5, R, Q, A0, R, Z, 0
section .data
filename db 'testtext.asm',0
;--------------------------------------------------
section .bss
iobuf resb 0100h
read_len resw 01h
filehndl resw 01h
-
avcaballero your piano seems really interesting but i cant use it without the macros.
as long as i finish with this project i am into, i will check it out for sure
-
What's the format of the "txt" file? If it's like "1234", you'll need to convert text to number, probably...
Best,
Frank
-
there is no restriction for that. i guess it will be something like 10461010 (note,duration,delay)
or if i define that for example the frequency 1046 is the note c, then in the txt it will be written cd#f....
Actually the format can be of my choosing as long as it is, to some degree, understandable and customisable. it could be like your melody format ( G0, SI, Q, F2...-g note for sixteenth, the pause for quarter etc..) . i tried adding a read-from-file code to the top of your music player and have melody on a different file but all i get is a looooong beep.
-
i want instead of mov si,melody that is on your code
to write mov si,iobuf (take the melody from a buffer)
-
Actually the format can be of my choosing as long as it is, to some degree, understandable and customisable.
Well... there's the rub. Understandable to a computer program is not understandable to a human... and that's who I assume you're targetting. If you want to use "names" like "G0" or "oct1_g", you're going to have to do some "string matching" and assign a number to each. Since this will involve only a relatively few "patterns" to match, this might not be too difficult - probably won't even have to cut down the delay!
If you can live with having the human customize a "source code" file of sorts, and processing that into a binary file that your program actually reads, you could use Nasm for the "processing", and simplify your player.
Some humans can "read music" - a bunch of lines with blobs on 'em. I despair of ever getting a computer program to do that. But... within limits... how simple do you want to make it for the human "composer"?
Best,
Frank
-
i see what you mean, since there is no restriction and i want to start finishing this thing i would say a very simple format like G0,SI,F#2,EI,S,Q (Gnote,length(sixteenth), f#,length(eighth) and S for silence something like that.