Author Topic: music player  (Read 6049 times)

Offline angela

  • Jr. Member
  • *
  • Posts: 9
music player
« 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:
Code: [Select]
; 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
« Last Edit: February 08, 2013, 07:31:59 PM by Frank Kotler »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2358
  • Country: us
Re: music player
« Reply #1 on: February 08, 2013, 08:05:04 PM »
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...(?)
Code: [Select]
; 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...
Code: [Select]
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


Offline angela

  • Jr. Member
  • *
  • Posts: 9
Re: music player
« Reply #2 on: February 12, 2013, 12:45:26 PM »
j
« Last Edit: February 12, 2013, 01:01:09 PM by angela »

Offline angela

  • Jr. Member
  • *
  • Posts: 9
Re: music player
« Reply #3 on: February 12, 2013, 12:50:29 PM »
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

Code: [Select]
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
;--------------------------------------

Offline angela

  • Jr. Member
  • *
  • Posts: 9
Re: music player
« Reply #4 on: February 12, 2013, 01:03:24 PM »
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

Code: [Select]
;----------------------------------------------------------
;                       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


Code: [Select]
%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
« Last Edit: February 12, 2013, 01:09:13 PM by angela »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2358
  • Country: us
Re: music player
« Reply #5 on: February 12, 2013, 11:10:25 PM »
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

Code: [Select]
; 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



Offline avcaballero

  • Full Member
  • **
  • Posts: 126
  • Country: es
    • Abre los Ojos al Ensamblador
Re: music player
« Reply #6 on: February 13, 2013, 04:53:41 PM »
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.

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2358
  • Country: us
Re: music player
« Reply #7 on: February 14, 2013, 11:39:32 AM »
Well... I rebooted into dos. I forget how to do this! I made some modifications to your file:
Code: [Select]
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:

Code: [Select]
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



Offline avcaballero

  • Full Member
  • **
  • Posts: 126
  • Country: es
    • Abre los Ojos al Ensamblador
Re: music player
« Reply #8 on: February 14, 2013, 03:09:14 PM »
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.

Offline angela

  • Jr. Member
  • *
  • Posts: 9
Re: music player
« Reply #9 on: February 16, 2013, 05:55:42 PM »
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
Code: [Select]
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

Offline angela

  • Jr. Member
  • *
  • Posts: 9
Re: music player
« Reply #10 on: February 16, 2013, 05:59:30 PM »
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

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2358
  • Country: us
Re: music player
« Reply #11 on: February 16, 2013, 06:08:20 PM »
What's the format of the "txt" file? If it's like "1234", you'll need to convert text to number, probably...

Best,
Frank


Offline angela

  • Jr. Member
  • *
  • Posts: 9
Re: music player
« Reply #12 on: February 16, 2013, 07:05:55 PM »
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.
« Last Edit: February 16, 2013, 07:42:46 PM by angela »

Offline angela

  • Jr. Member
  • *
  • Posts: 9
Re: music player
« Reply #13 on: February 16, 2013, 07:46:05 PM »
i want instead of mov si,melody that is on your code
to write mov si,iobuf  (take the melody from a buffer)

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2358
  • Country: us
Re: music player
« Reply #14 on: February 16, 2013, 09:02:24 PM »
Quote
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