Seamless Looping of Audio

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
PuzzledGreatly
Posts: 1303
Joined: 29 Sep 2013, 22:18

Seamless Looping of Audio

17 Nov 2013, 00:36

With Flash I could loop audio seamlessly. Is this at all possible with AHK? The following code repeats a wav file but there is a noticeable gap before it repeats:

Code: Select all

SetWorkingDir %A_ScriptDir%  	; Ensures a consistent starting directory.

f5::

LoopFile = %A_WorkingDir%\Loopy.wav
mciSendString("open " """" LoopFile """" " type mpegvideo Alias WAV01")
mciSendString("play WAV01 repeat")

return

esc:: exitapp

mciSendString(Command) {
  Return, DllCall("winmm.dll\mciSendString", Str,Command, Str,"", Int,0, Int,0)
}
Is there any way to get a seamless loop? Thanks
User avatar
ErrorOnLine2
Posts: 16
Joined: 31 Oct 2013, 18:54

Re: Seamless Looping of Audio

17 Nov 2013, 04:35

Maybe you can do something with Skan's code posted here.

http://www.autohotkey.com/board/topic/2 ... st-access/

I have a version of it, and if memory serves, it worked for me, but I don't have speakers hooked up to my 8 year old Gateway computer at the moment, so I can't retest it.
User avatar
PuzzledGreatly
Posts: 1303
Joined: 29 Sep 2013, 22:18

Re: Seamless Looping of Audio

17 Nov 2013, 05:16

Thanks for the link, unfortunately I could get neither version of the code posted by Skan to do anything.
User avatar
PuzzledGreatly
Posts: 1303
Joined: 29 Sep 2013, 22:18

Re: Seamless Looping of Audio

17 Nov 2013, 08:04

I've discovered that if I use SoundPlay I can get much better results:

Code: Select all

replay:
soundplay, Loopy.wav, wait
goto replay
However, in order to use this I have to put it in a separate ahk file and use run, otherwise the wait pauses my script. This means I have to hard code the sound file. Ideally I'd like to keep it in a function inside my main file. Not sure.
Guest

Re: Seamless Looping of Audio

17 Nov 2013, 09:27

There should be options to hardcoding: For example, changing and reading a plain text or ini file with the name of the sound file, or an "invisible" text control that you can read with the soundplaying script or even some more advanced interscript communication techniques.

P.s.: If you are ok to use an external dll-file, you could use the bass-dll (see "old" forum). It has much better sound playing abilities than 'soundfile', but it's more complicated. Perhaps, it'a a bit overkill, if you just want to loop a file... :geek:
User avatar
PuzzledGreatly
Posts: 1303
Joined: 29 Sep 2013, 22:18

Re: Seamless Looping of Audio

17 Nov 2013, 16:08

Thanks for the suggestion about bass.dll. I have ended up using a text file but would be very interested to know more about advanced interscript communication techniques. Where might I find out about those?
User avatar
PuzzledGreatly
Posts: 1303
Joined: 29 Sep 2013, 22:18

Re: Seamless Looping of Audio

17 Nov 2013, 17:25

Further investigation has revealed that the results obtained by using SoundPlay are less seamless than I thought and not good enough. I'll Start looking at Bass.dll but if anyone knows of an alternative I'd be grateful to hear about it. Thanks.
User avatar
FanaticGuru
Posts: 1906
Joined: 30 Sep 2013, 22:25

Re: Seamless Looping of Audio

18 Nov 2013, 19:46

PuzzledGreatly wrote:Thanks for the link, unfortunately I could get neither version of the code posted by Skan to do anything.
It might have just been the errant color coding the other forum adds.

This Skan script works for me.

Code: Select all

#SingleInstance, Force
SetWorkingDir %A_ScriptDir%  

MySoundFile1 = %SystemRoot%\Media\tada.wav
MySoundFile2 = %SystemRoot%\Media\chimes.wav

FileRead, Sound1, *c %MySoundFile1%
FileRead, Sound2, *c %MySoundFile2%

PlaySound( Sound1 )
PlaySound( Sound2 )

Return

PlaySound( ByRef Sound ) {
 Return DllCall( "winmm.dll\PlaySound" ( A_IsUnicode ? "W" : "A" ), UInt,&Sound, UInt,0
               , UInt, ((SND_MEMORY:=0x4)|(SND_NODEFAULT:=0x2)) )
}


Don't know if it will help with making the loop any smoother but you can try it.

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
User avatar
PuzzledGreatly
Posts: 1303
Joined: 29 Sep 2013, 22:18

Re: Seamless Looping of Audio

18 Nov 2013, 22:49

Thanks, the code does work but unfortunately doesn't make the looping any smoother.
just me
Posts: 9449
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Seamless Looping of Audio

19 Nov 2013, 01:39

Code: Select all

#NoEnv
Sound := A_WinDir . "\Media\tada.wav"
SoundPlay, %Sound%
Return
; ======================================================================================================================
^!p:: ; start playing
   SoundLoop(Sound)
Return
^!s:: ; stop playing
   SoundLoop("")
Return
Esc:: ; ExitApp
   SoundLoop("")
ExitApp
; ======================================================================================================================
SoundLoop(File := "") {
   ; http://msdn.microsoft.com/en-us/library/dd743680(v=vs.85).aspx
   ; SND_ASYNC       0x00000001  /* play asynchronously */
   ; SND_NODEFAULT   0x00000002  /* silence (!default) if sound not found */
   ; SND_LOOP        0x00000008  /* loop the sound until next sndPlaySound */
   ; SND_NOWAIT      0x00002000  /* don't wait if the driver is busy */
   ; SND_FILENAME    0x00020000  /* name is file name */
   ; --------------- 0x0002200B
   Static AW := A_IsUnicode ? "W" : "A"
   Return DllCall("Winmm.dll\PlaySound" . AW, "Ptr", File = "" ? 0 : &File, "Ptr", 0, "UInt", 0x0002200B)
}
?
User avatar
PuzzledGreatly
Posts: 1303
Joined: 29 Sep 2013, 22:18

Re: Seamless Looping of Audio

19 Nov 2013, 08:41

Brilliant! That works perfectly. Where did you get the information about the 0x numbers from and how can I learn about them? I've been trying out different ideas for several days now and kept drawing a blank. Thanks very much.
just me
Posts: 9449
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Seamless Looping of Audio

19 Nov 2013, 09:37

The numeric values of Windows constants can be found in the C/C++ header files included in the SDK's and/or the free 'express' editions of MS Visual Studio C++: :arrow: MSDN
User avatar
PuzzledGreatly
Posts: 1303
Joined: 29 Sep 2013, 22:18

Re: Seamless Looping of Audio

20 Nov 2013, 09:58

Thanks for the link, now to try and make sense of the info.
william_ahk
Posts: 486
Joined: 03 Dec 2018, 20:02

Re: Seamless Looping of Audio

19 Feb 2023, 03:37

@just me PlaySound does loop the audio seamlessly, but it doesn't expose any option to set the volume. Is there anything I can use to loop an audio file and set its volume as well? (I'm trying to make an ambience script)
just me
Posts: 9449
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Seamless Looping of Audio

19 Feb 2023, 06:29

@william_ahk,

did you try SoundSetWaveVolume or SoundSet?
william_ahk
Posts: 486
Joined: 03 Dec 2018, 20:02

Re: Seamless Looping of Audio

19 Feb 2023, 09:04

just me wrote:
19 Feb 2023, 06:29
did you try SoundSetWaveVolume or SoundSet?
Yes but I want to mix several sounds with a different volume for each, like this: https://asoftmurmur.com/
just me
Posts: 9449
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Seamless Looping of Audio

20 Feb 2023, 05:49

I don't know how to do that.
teadrinker
Posts: 4326
Joined: 29 Mar 2015, 09:41
Contact:

Re: Seamless Looping of Audio

20 Feb 2023, 06:04

Maybe like this:

Code: Select all

file1 := "C:\Windows\Media\Windows Feed Discovered.wav"
volume1 := 100
file2 := "C:\Windows\Media\Windows Information Bar.wav"
volume2 := 30

Loop 2
   ExecScript(GetCode(file%A_Index%, volume%A_Index%))

GetCode(file, volume) {
   code =
   (
      SetCurrentProcessVolume("%volume%")
      SoundLoop("%file%")
      
      Esc::ExitApp
      
      SoundLoop(File := "") {
         ; http://msdn.microsoft.com/en-us/library/dd743680(v=vs.85).aspx
         ; SND_ASYNC       0x00000001  /* play asynchronously */
         ; SND_NODEFAULT   0x00000002  /* silence (!default) if sound not found */
         ; SND_LOOP        0x00000008  /* loop the sound until next sndPlaySound */
         ; SND_NOWAIT      0x00002000  /* don't wait if the driver is busy */
         ; SND_FILENAME    0x00020000  /* name is file name */
         ; --------------- 0x0002200B
         Static AW := A_IsUnicode ? "W" : "A"
         Return DllCall("Winmm.dll\PlaySound" . AW, "Ptr", File = "" ? 0 : &File, "Ptr", 0, "UInt", 0x0002200B)
      }
      
      SetCurrentProcessVolume(volume) ; volume can be number 0 — 100 or "mute" or "unmute"
      {
         static MMDeviceEnumerator      := "{BCDE0395-E52F-467C-8E3D-C4579291692E}"
              , IID_IMMDeviceEnumerator := "{A95664D2-9614-4F35-A746-DE8DB63617E6}"
              , IID_IAudioClient        := "{1cb9ad4c-dbfa-4c32-b178-c2f568a703b2}"
              , IID_ISimpleAudioVolume  := "{87ce5498-68d6-44e5-9215-6da47ef883d8}"
              , eRender := 0, eMultimedia := 1, CLSCTX_ALL := 0x17
              , _ := OnExit( Func("SetCurrentProcessVolume").Bind(100) )
              
         IMMDeviceEnumerator := ComObjCreate(MMDeviceEnumerator, IID_IMMDeviceEnumerator)
         ; IMMDeviceEnumerator::GetDefaultAudioEndpoint
         DllCall(NumGet(NumGet(IMMDeviceEnumerator + 0) + A_PtrSize*4), "Ptr", IMMDeviceEnumerator, "UInt", eRender, "UInt", eMultimedia, "PtrP", IMMDevice)
         ObjRelease(IMMDeviceEnumerator)

         VarSetCapacity(GUID, 16)
         DllCall("Ole32\CLSIDFromString", "Str", IID_IAudioClient, "Ptr", &GUID)
         ; IMMDevice::Activate
         DllCall(NumGet(NumGet(IMMDevice + 0) + A_PtrSize*3), "Ptr", IMMDevice, "Ptr", &GUID, "UInt", CLSCTX_ALL, "Ptr", 0, "PtrP", IAudioClient)
         ObjRelease(IMMDevice)
         
         ; IAudioClient::GetMixFormat
         DllCall(NumGet(NumGet(IAudioClient + 0) + A_PtrSize*8), "Ptr", IAudioClient, "UIntP", pFormat)
         ; IAudioClient::Initialize
         DllCall(NumGet(NumGet(IAudioClient + 0) + A_PtrSize*3), "Ptr", IAudioClient, "UInt", 0, "UInt", 0, "UInt64", 0, "UInt64", 0, "Ptr", pFormat, "Ptr", 0)
         DllCall("Ole32\CLSIDFromString", "Str", IID_ISimpleAudioVolume, "Ptr", &GUID)
         ; IAudioClient::GetService
         DllCall(NumGet(NumGet(IAudioClient + 0) + A_PtrSize*14), "Ptr", IAudioClient, "Ptr", &GUID, "PtrP", ISimpleAudioVolume)
         ObjRelease(IAudioClient)
         if (volume + 0 != "")
            ; ISimpleAudioVolume::SetMasterVolume
            DllCall(NumGet(NumGet(ISimpleAudioVolume + 0) + A_PtrSize*3), "Ptr", ISimpleAudioVolume, "Float", volume/100, "Ptr", 0)
         else
            ; ISimpleAudioVolume::SetMute
            DllCall(NumGet(NumGet(ISimpleAudioVolume + 0) + A_PtrSize*5), "Ptr", ISimpleAudioVolume, "UInt", volume = "mute" ? true : false, "Ptr", 0)
         ObjRelease(ISimpleAudioVolume)
      }
   )
   Return code
}

ExecScript(script, exePath := "") {
   (!exePath && exePath := A_AhkPath)
   shell := ComObjCreate("WScript.Shell")
   exec := shell.Exec(exePath . " *")
   exec.StdIn.Write(script)
   exec.StdIn.Close()
   return exec.ProcessID
}
william_ahk
Posts: 486
Joined: 03 Dec 2018, 20:02

Re: Seamless Looping of Audio

20 Feb 2023, 23:35

@teadrinker Nice!!! :clap: Thank you so much :thumbup:
User avatar
PuzzledGreatly
Posts: 1303
Joined: 29 Sep 2013, 22:18

Re: Seamless Looping of Audio

21 Feb 2023, 20:02

Is this code for AHK v2? I got this error message when I ran it with v1:
---------------------------
teadrinker Sound loop test.ahk
---------------------------
Error: 0x800A0005 -
Source: (null)
Description: (null)
HelpFile: (null)
HelpContext: 0

Specifically: Write

Line#
010: code = SetCurrentProcessVolume("%volume%")
SoundLoop("%file%")

Esc::ExitApp

SoundLoop(File := "") {
; http://msdn.microsoft.com/en-us/library/dd743680(v=vs.85).aspx
; SND_ASYNC 0x00000001 /* play asynchronously */
; SND_NODEFAULT 0x00000002 /* silence (!default) if sound not found */
; SND_LOOP 0x00000008 /* loop the sound until next sndPlaySound */
; SND_NOWAIT 0x00002000 /* don't wait if the driver
066: Return,code
067: }
069: {
070: (!exePath && exePath := A_AhkPath)
071: shell := ComObjCreate("WScript.Shell")
072: exec := shell.Exec(exePath . " *")
---> 073: exec.StdIn.Write(script)
074: exec.StdIn.Close()
075: Return,exec.ProcessID
076: }
077: Exit
078: Exit
078: Exit

Continue running the script?
---------------------------
Yes No
---------------------------

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: prototype_zero, ulysim and 317 guests