News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

midi sound in GoAsm program

Started by shankle, May 20, 2013, 01:51:51 AM

Previous topic - Next topic

shankle

      5-19-2013
; Been a long time since I wrote this system and can't for the life of me     
; remember how I arrived at the noteC3 thingie.
; Same for the Playnotes.
; This uses the Midi Disaster.

; When I wrote this system in Windows 98-32-bit, the sound worked just
; fine. It also worked in Vista 32-bit.
; It also works in Windows 7 32-bit using Masm32 on my HP Pavilion 64-bit
; puter.

; The sound doesn't work very well in my converted to GoAsm 32-bit
; version on the 64-bit Pavilion or on a Windows 7 32-bit puter.
; I created a 64-bit version of the GoAsm program and no sound emerges
; from it.
; Found two headers in Donkeys headers with Midi referenced in them -
; mmreg.h and mmsystem.h. I have no idea if they are included in my
; program at link time or if they work on my setup.

; In the (noteC3) definition I have no idea how I got the "7f" or the "90".
; The 3rd byte is the pitch of the note. Like "30" represents the note
; "C" 3rd octave.

lphmo            dq    0

; two octave scale C to C.
noteC3           dd    007f3090h
noteD3           dd    007f3290h
noteE3           dd    007f3490h
noteF3           dd    007f3590h
noteG3           dd    007f3790h
noteA3           dd    007f3990h
noteB3           dd    007f3b90h
noteC4           dd    007f3c90h
noteD4           dd    007f3e90h
noteE4           dd    007f4090h
noteF4           dd    007f4190h
noteG4           dd    007f4390h
noteA4           dd    007f4590h
noteB4           dd    007f4790h
noteC5           dd    007f4890h

duration         dd   00000226h
tc                  dd   0
noteX            dd   0

     lea eax,[noteC3] etc.
     mov [noteX],eax             
     invoke PlayNotes, [noteX]                        ;Play C3           

; other code

PlayNotes:
    FRAME noteX
      invoke midiOutOpen, offset lphmo, -1, NULL, 0, CALLBACK_NULL
     
    ; ecx points to notes
    ; edx points to the duration of the note
      mov ecx,[noteX]
      lea edx,duration                  ; duration of note
      push ecx
      push edx
      invoke midiOutShortMsg, [lphmo],[ecx]        ; varying notes     
      pop edx
      pop ecx
      push ecx
      push edx         
      invoke GetTickCount   ; get a time reference
      pop edx
      pop ecx
      mov [tc],eax
      mov eax,[edx]
      add [tc],eax
.TimeCount
      push ecx
      push edx
      invoke GetTickCount
      pop edx
      pop ecx
      cmp [tc],eax
       jg <.TimeCount
      invoke midiOutReset, [lphmo]         
     invoke midiOutClose, [lphmo]
      ret
ENDF

Hope somebody has some ideas on this subject.



japheth

Quote from: shankle on May 20, 2013, 01:51:51 AM
Hope somebody has some ideas on this subject.

Try to simplify your proggie.

Here's a sample ( Masm ) that plays 3 chords - it works:


.386
.Model flat, stdcall
option casemap:none

WIN32_LEAN_AND_MEAN equ 1
.nolist
.nocref
include windows.inc
include mmsystem.inc
.list
.cref

CStr macro text:vararg
local xxx
.const
xxx db text,0
.code
exitm <offset xxx>
endm

.data

g_hConOut dd 0

.code

;--- printf emulation

printf proc c pszText:dword, parms:VARARG

local dwWritten:dword
local szText[128]:byte

invoke wvsprintf, addr szText, pszText, addr parms
lea ecx, dwWritten
invoke WriteConsole, g_hConOut, addr szText, eax, ecx, 0
ret
printf endp

main proc c

local hMidiOut:HANDLE

invoke GetStdHandle, STD_OUTPUT_HANDLE
mov g_hConOut, eax

invoke midiOutGetNumDevs
.if (!eax)
invoke printf, CStr(<"midiOutGetNumDevs() returned 0",10>)
jmp @exit
.endif

Invoke midiOutOpen, addr hMidiOut, MIDI_MAPPER, NULL, NULL, CALLBACK_NULL
push eax
.if (eax != MMSYSERR_NOERROR)
invoke printf, CStr(<"midiOutOpen() failed [%u]",10>), eax
.else
invoke printf, CStr(<"midiOutOpen() ok",10>)
.endif
pop eax
.if (eax != MMSYSERR_NOERROR)
jmp @exit
.endif

; int 3
Invoke midiOutShortMsg, hMidiOut, 7F3C90h
Invoke midiOutShortMsg, hMidiOut, 7F4090h
Invoke midiOutShortMsg, hMidiOut, 7F4390h

invoke Sleep, 200

Invoke midiOutShortMsg, hMidiOut, 003C90h
Invoke midiOutShortMsg, hMidiOut, 004090h
Invoke midiOutShortMsg, hMidiOut, 004390h

invoke Sleep, 20

Invoke midiOutShortMsg, hMidiOut, 7F4190h
Invoke midiOutShortMsg, hMidiOut, 7F4590h
Invoke midiOutShortMsg, hMidiOut, 7F4890h

invoke Sleep, 200

Invoke midiOutShortMsg, hMidiOut, 004190h
Invoke midiOutShortMsg, hMidiOut, 004590h
Invoke midiOutShortMsg, hMidiOut, 004890h

invoke Sleep, 20

Invoke midiOutShortMsg, hMidiOut, 7F4390h
Invoke midiOutShortMsg, hMidiOut, 7F4790h
Invoke midiOutShortMsg, hMidiOut, 7F4A90h

invoke Sleep, 500

Invoke midiOutShortMsg, hMidiOut, 004390h
Invoke midiOutShortMsg, hMidiOut, 004790h
Invoke midiOutShortMsg, hMidiOut, 004A90h

invoke midiOutClose, hMidiOut
invoke printf, CStr(<"midiOutClose()=%X",10>), eax
@exit:
ret

main endp

start:
invoke main
invoke ExitProcess, 0

end start


dedndave

also - be sure to check your midi device volume
i don't know how many times i have found it set to 0   :P

dedndave

hiya Jack
as you know, i am not much of a GoAsm guy   :P
but, this seems to work ok using MASM Syntax
;###############################################################################################

        .XCREF
        .NoList
        INCLUDE    \Masm32\Include\Masm32rt.inc
        INCLUDE    \Masm32\Include\WinMm.inc
        INCLUDELIB \Masm32\Lib\WinMm.lib
        .List

;###############################################################################################

PlayNotes PROTO  :LPVOID,:DWORD

;###############################################################################################

        .DATA

noteC3  dd 7f3090h   ;two octave scale C to C
noteD3  dd 7f3290h
noteE3  dd 7f3490h
noteF3  dd 7f3590h
noteG3  dd 7f3790h
noteA3  dd 7f3990h
noteB3  dd 7f3b90h
noteC4  dd 7f3c90h
noteD4  dd 7f3e90h
noteE4  dd 7f4090h
noteF4  dd 7f4190h
noteG4  dd 7f4390h
noteA4  dd 7f4590h
noteB4  dd 7f4790h
noteC5  dd 7f4890h
termin  dd 0         ;terminate list with a 0

;***********************************************************************************************

;        .DATA?

;###############################################################################################

        .CODE

;***********************************************************************************************

_main   PROC

        INVOKE  PlayNotes,offset noteC3,550
        INVOKE  ExitProcess,0

_main   ENDP

;***********************************************************************************************

PlayNotes PROC  lpNoteList:LPVOID,dwDuration:DWORD

;--------------------------------------------------

        LOCAL   hMidiOut  :HANDLE

;--------------------------------------------------

        INVOKE  midiOutOpen,addr hMidiOut,MIDI_MAPPER,NULL,0,CALLBACK_NULL
        cmp     eax,MMSYSERR_NOERROR
        jnz     PlayN2

        push    esi
        mov     esi,lpNoteList
        jmp short PlayN1

PlayN0: INVOKE  midiOutShortMsg,hMidiOut,eax
        INVOKE  Sleep,dwDuration
        INVOKE  midiOutReset,hMidiOut

PlayN1: lodsd
        or      eax,eax
        jnz     PlayN0

        INVOKE  midiOutClose,hMidiOut
        pop     esi

PlayN2: ret

PlayNotes ENDP

;###############################################################################################

        END     _main

shankle

Thanks Guys for responding.
The system has been working in MASM32 for years.
Here are the files included in the MASM32 relevant program.
Something is either missing in the GoAsm files or it's something to
do with the 64-bit HP puter or both.
I'm still to green in GoAsm to know where to start looking for the problem.

include \masm32\include\windows.inc
(many equates referring to MIDI in here)

include \masm32\include\gdi32.inc - nothing here
include \masm32\include\user32.inc - nothing here
include \masm32\include\kernel32.inc - nothing here
include \masm32\include\winmm.inc
(Many references in here  - some are proto statements)

dedndave

i am with Japheth
simplify your code
no need for all those pointers to pointers   :P

you include winmm.inc, you may also need to includelib winmm.lib
(not sure how GoAsm works, in that respect)

wjr

The "9nh" is the MIDI status byte for Note On on channel n (0-F). You have the Note Number right. The next byte "vvh" is the attack velocity (01-7F, with 00 another way for Note Off).

You use ecx as a pointer to the note, so in the call to midiOutShortMsg you should use [ecx]. That should fix things on the 32-bit side.

If you are using Donkey's headers, then mmsystem.h will be included (from windows.h as long as you have not defined WIN_LEAN_AND_MEAN), and this then also adds instructions for the linker to include winmm.dll (if you have defined LINKFILES, otherwise you need to add this dll to the GoLink command line).

shankle

Thank you WJR for responding.
The 1st two paragraphs I think I understand.

I am using Donkey's headers.
I have no idea what "WIN_LEAN_AND _MEAN" is.
Am I correct in saying that this will not solve the 64-bit
problem? Or are the Headers the same for both?
I have two of these, one for 32bits and one for 64bits.
Is this what you mean?

#define LINKFILES
#define codejps
#define WIN64
#INCLUDE windows.h

dedndave

this one does not use midiOutReset
instead, it sets the "note off" status and resends it if it's a note
if it's not a note, it skips the wait period and goes to the next message
this allows you to select different instruments (or send other command messages) in the data stream

if we wanted to get fancy, we would use the multi-media timer, rather than Sleep
we could also allow for multiple notes to play chords, etc

;###############################################################################################

        .XCREF
        .NoList
        INCLUDE    \Masm32\Include\Masm32rt.inc
        INCLUDE    \Masm32\Include\WinMm.inc
        INCLUDELIB \Masm32\Lib\WinMm.lib
        .List

;###############################################################################################

PlayNotes PROTO  :LPVOID,:DWORD

;###############################################################################################

        .DATA

noteC3  dd 7f3090h   ;two octave scale C to C
instr01 dd 1C0h
noteD3  dd 7f3290h
instr02 dd 2C0h
noteE3  dd 7f3490h
instr03 dd 3C0h
noteF3  dd 7f3590h
instr04 dd 4C0h
noteG3  dd 7f3790h
instr05 dd 5C0h
noteA3  dd 7f3990h
instr06 dd 6C0h
noteB3  dd 7f3b90h
instr07 dd 7C0h
noteC4  dd 7f3c90h
instr08 dd 8C0h
noteD4  dd 7f3e90h
instr09 dd 9C0h
noteE4  dd 7f4090h
instr10 dd 0AC0h
noteF4  dd 7f4190h
instr11 dd 0BC0h
noteG4  dd 7f4390h
instr12 dd 0CC0h
noteA4  dd 7f4590h
instr13 dd 0DC0h
noteB4  dd 7f4790h
instr14 dd 0EC0h
noteC5  dd 7f4890h
termin  dd 0         ;terminate list with a 0

;***********************************************************************************************

;        .DATA?

;###############################################################################################

        .CODE

;***********************************************************************************************

_main   PROC

        INVOKE  PlayNotes,offset noteC3,550
        INVOKE  ExitProcess,0

_main   ENDP

;***********************************************************************************************

PlayNotes PROC  lpNoteList:LPVOID,dwDuration:DWORD

;--------------------------------------------------

        LOCAL   hMidiOut  :HANDLE

;--------------------------------------------------

        INVOKE  midiOutOpen,addr hMidiOut,MIDI_MAPPER,NULL,0,CALLBACK_NULL
        cmp     eax,MMSYSERR_NOERROR
        jnz     PlayN2

        push    esi
        push    ebx
        mov     esi,lpNoteList
        jmp short PlayN1

PlayN0: mov     ebx,eax
        INVOKE  midiOutShortMsg,hMidiOut,eax
        mov     al,bl
        and     al,0F0h
        and     bl,0Fh
        cmp     al,90h                       ;is it "note on" ?
        jnz     PlayN1                       ;no - next msg

        or      bl,80h                       ;yes - set "note off"
        INVOKE  Sleep,dwDuration             ;after wait period
        INVOKE  midiOutShortMsg,hMidiOut,ebx

PlayN1: lodsd
        or      eax,eax
        jnz     PlayN0

        INVOKE  midiOutClose,hMidiOut
        pop     ebx
        pop     esi

PlayN2: ret

PlayNotes ENDP

;###############################################################################################

        END     _main

shankle

Thanks much WJR.
The 32-bit program is now working.
The 64-bit program is also working.
All caused by [ecx].
I've got a long way to go with GoAsm.....

The program in this thread is now working Dave,
so you have what you asked for.

dedndave

yes   :t

i would like to figure out which instrument to use to get a straight beep tone
it would be nice if i could use this method for morse code 

shankle

Hi Dave,
I would like the Congo drums used in the old Tarzan movies.... :biggrin:

dedndave

Piano

    1 Acoustic Grand Piano
    2 Bright Acoustic Piano
    3 Electric Grand Piano
    4 Honky-tonk Piano
    5 Electric Piano 1
    6 Electric Piano 2
    7 Harpsichord
    8 Clavinet

Chromatic Percussion

    9 Celesta
    10 Glockenspiel
    11 Music Box
    12 Vibraphone
    13 Marimba
    14 Xylophone
    15 Tubular Bells
    16 Dulcimer

Organ

    17 Drawbar Organ
    18 Percussive Organ
    19 Rock Organ
    20 Church Organ
    21 Reed Organ
    22 Accordion
    23 Harmonica
    24 Tango Accordion

Guitar

    25 Acoustic Guitar (nylon)
    26 Acoustic Guitar (steel)
    27 Electric Guitar (jazz)
    28 Electric Guitar (clean)
    29 Electric Guitar (muted)
    30 Overdriven Guitar
    31 Distortion Guitar
    32 Guitar Harmonics

Bass

    33 Acoustic Bass
    34 Electric Bass (finger)
    35 Electric Bass (pick)
    36 Fretless Bass
    37 Slap Bass 1
    38 Slap Bass 2
    39 Synth Bass 1
    40 Synth Bass 2

Strings

    41 Violin
    42 Viola
    43 Cello
    44 Contrabass
    45 Tremolo Strings
    46 Pizzicato Strings
    47 Orchestral Harp
    48 Timpani

Ensemble

    49 String Ensemble 1
    50 String Ensemble 2
    51 Synth Strings 1
    52 Synth Strings 2
    53 Choir Aahs
    54 Voice Oohs
    55 Synth Choir
    56 Orchestra Hit

Brass

    57 Trumpet
    58 Trombone
    59 Tuba
    60 Muted Trumpet
    61 French Horn
    62 Brass Section
    63 Synth Brass 1
    64 Synth Brass 2

Reed

    65 Soprano Sax
    66 Alto Sax
    67 Tenor Sax
    68 Baritone Sax
    69 Oboe
    70 English Horn
    71 Bassoon
    72 Clarinet

Pipe

    73 Piccolo
    74 Flute
    75 Recorder
    76 Pan Flute
    77 Blown Bottle
    78 Shakuhachi
    79 Whistle
    80 Ocarina

Synth Lead

    81 Lead 1 (square)
    82 Lead 2 (sawtooth)
    83 Lead 3 (calliope)
    84 Lead 4 (chiff)
    85 Lead 5 (charang)
    86 Lead 6 (voice)
    87 Lead 7 (fifths)
    88 Lead 8 (bass + lead)

Synth Pad

    89 Pad 1 (new age)
    90 Pad 2 (warm)
    91 Pad 3 (polysynth)
    92 Pad 4 (choir)
    93 Pad 5 (bowed)
    94 Pad 6 (metallic)
    95 Pad 7 (halo)
    96 Pad 8 (sweep)

Synth Effects

    97 FX 1 (rain)
    98 FX 2 (soundtrack)
    99 FX 3 (crystal)
    100 FX 4 (atmosphere)
    101 FX 5 (brightness)
    102 FX 6 (goblins)
    103 FX 7 (echoes)
    104 FX 8 (sci-fi)

Ethnic

    105 Sitar
    106 Banjo
    107 Shamisen
    108 Koto
    109 Kalimba
    110 Bagpipe
    111 Fiddle
    112 Shanai

Percussive

    113 Tinkle Bell
    114 Agogo
    115 Steel Drums
    116 Woodblock
    117 Taiko Drum
    118 Melodic Tom
    119 Synth Drum

Sound effects

    120 Reverse Cymbal
    121 Guitar Fret Noise
    122 Breath Noise
    123 Seashore
    124 Bird Tweet
    125 Telephone Ring
    126 Helicopter
    127 Applause
    128 Gunshot


let's try the Taiko Drums   :biggrin: