Jump to content

Metronome doesn't work


Recommended Posts

Today I thought I'd make a metronome. I know my script is a bit primative and probably incorrect.

#include <Sound.au3>
$wait = InputBox("Miliseconds to Wait", "Enter a number greater than zero.")
While 1
_SoundPlay("metro.wav", 1)
Sleep($wait)
WEnd

The problem I am having is that as soon as another process does anything, the metronome slows down. Is there a way that I can force it to keep a regular beat? Or do I have to forget using Sleep() and try another approach?

Link to comment
Share on other sites

Today I thought I'd make a metronome. I know my script is a bit primative and probably incorrect.

#include <Sound.au3>
$wait = InputBox("Miliseconds to Wait", "Enter a number greater than zero.")
While 1
_SoundPlay("metro.wav", 1)
Sleep($wait)
WEnd

The problem I am having is that as soon as another process does anything, the metronome slows down. Is there a way that I can force it to keep a regular beat? Or do I have to forget using Sleep() and try another approach?

Your call to _SoundPlay() takes time to load/unload at each loop. Better to dig into the Sound.au3 listing and tease out the object creation/dll call so it only has to be done once.

You might want to use AdLibEnable(), or maybe TimerInit()/TimerDiff() instead of Sleep().

Also, throw in a little math to get "Beats per minute (BPM)" vice time in miliseconds. Much more useful for a metronome functions.

:)

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

Your call to _SoundPlay() takes time to load/unload at each loop. Better to dig into the Sound.au3 listing and tease out the object creation/dll call so it only has to be done once.

You might want to use AdLibEnable(), or maybe TimerInit()/TimerDiff() instead of Sleep().

Also, throw in a little math to get "Beats per minute (BPM)" vice time in miliseconds. Much more useful for a metronome functions.

:)

I thought there would be some way around this. New territory for me to explore: AdLibEnable(), TimerInit()/TimerDiff(). :P

Of course I was intending to use bpm. I only threw in the input box at the last minute. I was just concerned that the method I was using was not the best. Thanks for your suggestions.

Link to comment
Share on other sites

Hmmm...I wonder if you could use MIDI through some kind of API or DLL programming? (Just thinking out loud. Might be something interesting to look into.)

Obviously what I thought might be a simple script writing exercise seems to be less straight forward than I first thought. I will look into it later. I am writing some other scripts at the moment, which are more important to me than a desktop metronome. I would like to have one however, so if anyone is looking for a project :) If not I'll try and get my head around it. A lot of this stuff is new to me. I think I need to absorb some new methods and ideas. Thanks for the response.

Edited by czardas
Link to comment
Share on other sites

ProcessSetPriority ( @autoitpid, 5) might help too

Now that sounds like the kind of thing that I was originally thinking of. Still there is an issue with time taken to load the wav file. This limits the bpm, so I will probably have to combine all your answers to get a efficient application. :)

Link to comment
Share on other sites

I don't actually use AdLibEnable much, and this seemed like a good experiment with switching AdLibEnable on/off based on an input, so I did a demo:

#include <guiconstants.au3>

Opt("GuiOnEventMode", 1)
Global $BEAT_NUM = 0, $BEAT_CNT = 1

; Create GUI
$hGUI = GUICreate("AutoIt Metronome", 300, 170)
GUISetOnEvent($GUI_EVENT_CLOSE, "_Quit")

; Add controls
GUICtrlCreateLabel("The AutoIt Metronome", 10, 10, 280, 30, $SS_CENTER)
GUICtrlSetFont(-1, 12, 600)
GUICtrlCreateLabel("Beats Per Minute:", 10, 50, 135, 20, $SS_RIGHT)
$BeatsPerMin = GUICtrlCreateInput("60", 155, 50, 50, 20)
GUICtrlCreateUpdown(-1)
GUICtrlSetLimit(-1, 240, 1)
GUICtrlCreateLabel("Beats Per Bar:", 10, 80, 135, 20, $SS_RIGHT)
$BeatsPerBar = GUICtrlCreateInput("0", 155, 80, 50, 20)
GUICtrlCreateUpdown(-1)
GUICtrlSetLimit(-1, 64, 0)
$Start_Button = GUICtrlCreateButton("START", 50, 120, 75, 30)
GUICtrlSetOnEvent(-1, "_ButtonHit")
$Stop_Button = GUICtrlCreateButton("STOP", 175, 120, 75, 30)
GUICtrlSetOnEvent(-1, "_ButtonHit")

; Await user actions
GUISetState()
While 1
    Sleep(20)
WEnd

Func _ButtonHit()
    Local $Input, $BEAT_TIME
    Switch @GUI_CtrlId
        Case $Start_Button
            $Input = GUICtrlRead($BeatsPerMin)
            If StringIsInt($Input) And $Input >= 1 And $Input <= 240 Then
                $BEAT_TIME = Int(60000 / $Input)
                $Input = GUICtrlRead($BeatsPerBar)
                If StringIsInt($Input) And $Input >= 0 And $Input <= 64 Then
                    $BEAT_NUM = 1
                    $BEAT_CNT = $Input
                    AdlibEnable("_Beat", $BEAT_TIME)
                Else
                    GUICtrlSetData($BeatsPerBar, 0)
                EndIf
            Else
                GUICtrlSetData($BeatsPerMin, 60)
            EndIf
            
        Case $Stop_Button
            AdlibDisable()
    EndSwitch
EndFunc   ;==>_ButtonHit

Func _Beat()
    Local $BeepFreq = 2000, $BeepTime = 10
    If $BEAT_CNT > 0 Then
        If $BEAT_NUM = 1 Then
            $BeepFreq = 1000
            $BeepTime = 25
        EndIf
        $BEAT_NUM += 1
        If $BEAT_NUM > $BEAT_CNT Then $BEAT_NUM = 1
    EndIf
    Beep($BeepFreq, $BeepTime)
EndFunc   ;==>_Beat

Func _Quit()
    Exit
EndFunc   ;==>_Quit

:)

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

I don't actually use AdLibEnable much, and this seemed like a good experiment with switching AdLibEnable on/off based on an input, so I did a demo:

Sorry it took so long for me to respond. I wrote a lengthy reply to this the other day, but for some reason the post failed and I did not have time to rewrite it. Firstly I wanted to thank you for having spent the time to make this. However I can't actually use it because it is too quiet. Unfortunately I don't know why, and I am at a loss to fix it. I could amplify the signal, but that would mean carrying an amplifier and speakers around with my laptop. Not very practical. :)

The second part of my original response was about the beats per bar idea. I like the idea, and I have thought of several improvements. I will post these ideas in detail within the next day or two, if anyone is interested. I do not want anyone to think that I am after free code. It's just that I find this project a bit tricky. I think that it is worth the effort to make this thing, because I am sure that it will get used, and it's a nice thing to share.

Please check back in a day or two, as I need to study your code and gather my thoughts about additional features, namely programmable accents, musical symbols on the interface and standard time signature settings.

Thanks again,

Czardas

Link to comment
Share on other sites

If you are going to use Sound.au3 vice Beep, then you could make it smoother with the following:

Break down the code in Sound.au3 to get info needed to do these things:

1. Open the DLL only once with DllOpen(), saving the handle at the begining, and close it at the end. This avoids repeated open/close cycles every time you do DllCall() to play the sound.

2. Do $oSnd.Open only once, saving the alias, so you don't have to open the WAV file over and over again.

3. Do the DllCall() for play with your own line of code. Don't use _SoundPlay() because it will reintroduce the inefficiency you correct with 1 and 2 above.

4. Find a way to introduce an altenate volume level, or an alternate sound, or both so you can have a "down beat" that sounds different than the "beat".

5. Either use .wav files other people already have, or post them for use in testing (i.e. I don't have "metro.wav" that you used before).

:)

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

I modified PsaltyDS' metronome code above to make a MIDI metronome. MIDI UDF required: http://www.autoitscript.com/forum/index.ph...mp;#entry385157

#include <guiconstants.au3>
#include <midiudf.au3>

Opt("GuiOnEventMode", 1)

Global $BEAT_NUM = 0, $BEAT_CNT = 1, $open = _midiOutOpen ()

; Create GUI
$hGUI = GUICreate("AutoIt Metronome", 300, 170)
GUISetOnEvent($GUI_EVENT_CLOSE, "_Quit")

; Add controls
GUICtrlCreateLabel("The AutoIt Metronome", 10, 10, 280, 30, $SS_CENTER)
GUICtrlSetFont(-1, 12, 600)
GUICtrlCreateLabel("Beats Per Minute:", 10, 50, 135, 20, $SS_RIGHT)
$BeatsPerMin = GUICtrlCreateInput("120", 155, 50, 50, 20)
GUICtrlCreateUpdown(-1)
GUICtrlSetLimit(-1, 240, 40)
GUICtrlCreateLabel("Beats Per Bar:", 10, 80, 135, 20, $SS_RIGHT)
$BeatsPerBar = GUICtrlCreateInput("4", 155, 80, 50, 20)
GUICtrlCreateUpdown(-1)
GUICtrlSetLimit(-1, 64, 0)
$Start_Button = GUICtrlCreateButton("START", 50, 120, 75, 30)
GUICtrlSetOnEvent(-1, "_ButtonHit")
$Stop_Button = GUICtrlCreateButton("STOP", 175, 120, 75, 30)
GUICtrlSetOnEvent(-1, "_ButtonHit")

; Await user actions
GUISetState()
While 1
   Sleep(20)
WEnd

Func _ButtonHit()
   Local $Input, $BEAT_TIME
   Switch @GUI_CtrlId
      Case $Start_Button
         $Input = GUICtrlRead($BeatsPerMin)
         If StringIsInt($Input) And $Input >= 1 And $Input <= 240 Then
            $BEAT_TIME = Int(60000 / $Input)
            $Input = GUICtrlRead($BeatsPerBar)
            If StringIsInt($Input) And $Input >= 0 And $Input <= 64 Then
               $BEAT_NUM = 1
               $BEAT_CNT = $Input
               AdlibEnable("_Beat", $BEAT_TIME)
            Else
               GUICtrlSetData($BeatsPerBar, 0)
            EndIf
         Else
            GUICtrlSetData($BeatsPerMin, 60)
         EndIf
      Case $Stop_Button
         _MidiOutReset ($open)
         AdlibDisable()
   EndSwitch
EndFunc   ;==>_ButtonHit

Func _Beat()
   Local $Note = 0x99 + (77 * 256) + (127 * 0x10000) ;77 = Lo Woodblock
   If $BEAT_CNT > 0 Then
      If $BEAT_NUM = 1 Then $Note = 0x99 + (76 * 256) + (127 * 0x10000) ;76 = Hi Woodblock
      $BEAT_NUM += 1
      If $BEAT_NUM > $BEAT_CNT Then $BEAT_NUM = 1
   EndIf
   _MidiOutShortMsg ($open, $Note)
EndFunc   ;==>_Beat

Func _Quit()
   _MidiOutClose ($open)
   Exit
EndFunc   ;==>_Quit
Link to comment
Share on other sites

I modified PsaltyDS' metronome code above to make a MIDI metronome. MIDI UDF required: http://www.autoitscript.com/forum/index.ph...mp;#entry385157

Nicely done!

:)

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

Here's the wav file I was using. Sorry about the delay, I have been busy lately. I tried to post this a few days ago [see above], but something went wrong.

This business of using DLLcall: How do I know which DLL to call? I've never done it.

Edited by czardas
Link to comment
Share on other sites

I modified PsaltyDS' metronome code above to make a MIDI metronome. MIDI UDF required: http://www.autoitscript.com/forum/index.ph...mp;#entry385157

Thanks again to all. However I don't seem to get anything from this code. I have downloaded the midiUDF but I don't get a GUI? Nothing happens at all. Ok I should be able to figure it out, after all your efforts.

Edited by czardas
Link to comment
Share on other sites

Thanks again to all. However I don't seem to get anything from this code. I have downloaded the midiUDF but I don't get a GUI? Nothing happens at all. Ok I should be able to figure it out, after all your efforts.

GMK's version works great for me, and it doesn't need any external sound files, so it's a great solution.

When you run it from SciTE, to you get any errors on Syntax Check or in the console?

:)

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

GMK's version works great for me, and it doesn't need any external sound files, so it's a great solution.

When you run it from SciTE, to you get any errors on Syntax Check or in the console?

:)

The only thing I get is the task bar icon, which tells me that the script is running. It may have something to do with windows 2000 operating system, which I am using at the moment. I can try it on XP. Perhaps that's the problem? I'll let you know how I get on.

Actually yes there are errors See below:

>C:\Program Files\AutoIt3\SciTE\..\au3check.exe "C:\Documents and Settings\Administrator\My Documents\metro2.au3"

AutoIt3 Syntax Checker v1.54 Copyright © Tylo 2006

C:\Documents and Settings\Administrator\My Documents\midiudf.au3(34,104) : WARNING: $MIDI_UNCACHE: possibly used before declaration.

Const $MIDI_CACHE_VALID = ($MIDI_CACHE_ALL Or $MIDI_CACHE_BESTFIT Or $MIDI_CACHE_QUERY Or $MIDI_UNCACHE)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

~~~^

C:\Documents and Settings\Administrator\My Documents\midiudf.au3(1049,19) : WARNING: $getmmsyserr: possibly used before declaration.

if $getmmsyserr =

~~~~~~~~~~~~~~~~^

C:\Documents and Settings\Administrator\My Documents\midiudf.au3(1076,34) : ERROR: DllStructGetData() [built-in] called with wrong number of args.

$get = Dllstructgetdata($struct)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^

C:\Documents and Settings\Administrator\My Documents\midiudf.au3(1049,19) : ERROR: $getmmsyserr: undeclared global variable.

if $getmmsyserr =

~~~~~~~~~~~~~~~~^

C:\Documents and Settings\Administrator\My Documents\metro2.au3 - 2 error(s), 2 warning(s)

>Exit code: 2 Time: 0.449

Edited by czardas
Link to comment
Share on other sites

put the midiudf.au3 in the Autoit "Include" folder. Make sure that the includes are still at the top of the page. Make sure you are using the right include as well.

I included the midiudf.au3 that everybody is using as an attachment, I would suggest deleting the old one and using this one in case thats the issue.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...