Is there a way to make R beep/play a sound at the end of a script?

Viewed 53646

When I run R scripts I go do something else on a different desktop. If I don't check frequently, I never know when something is finished. Is there a way to invoke a beep (like a system beep) or get R to play a sound or notify growl via some code at the end of my script?

20 Answers

Do this:

song <- function() {
    for(i in 1:2) {
        for(i in 1:4) {
            for(i in 1:4) {
                beep(7)
                Sys.sleep(0.25)
                beep()
                Sys.sleep(0.22)
            }
            beep(2)
        }
        beep(11)
    }
    beep(4)
} 

song()

You can jam out to it.

How about using Windows SpeechSynthesizer?

message <- "job done!"

system2(command = "PowerShell", 
        args = c("-Command", 
                 "\"Add-Type -AssemblyName System.Speech;",
                  "$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;",
                  paste0("$speak.Speak('", message, "');\"")
        ))
                                               

This may by nicely used in iterating operations and read something like "First job done", "Second job done" etc.:

say_something <- function(message) {
    
     message <- paste0("$speak.Speak('", message, "');\"")
    
     system2(command = "PowerShell", 
             args = c("-Command", 
                       "\"Add-Type -AssemblyName System.Speech;",
                       "$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;",
                                    
                       message
            ))
  }

operations <- c("1st.", "2nd.", "3rd.")
lapply(operations, function(x) say_something(message=paste(x, "job done")))

 

*Note, that this uses system defaul language settings. The example is based on english lector, it can be changed using SelectVoice method. To check available lectors use:

  system2(command = "PowerShell", 
        args = c("-Command", 
                 "\"Add-Type -AssemblyName System.Speech;",
                  "$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;",
                 "$speak.GetInstalledVoices().VoiceInfo")
        )

That gives:

    Gender                : Female
Age                   : Adult
Name                  : Microsoft Paulina Desktop
Culture               : pl-PL
Id                    : TTS_MS_PL-PL_PAULINA_11.0
Description           : Microsoft Paulina Desktop - Polish
SupportedAudioFormats : {}
AdditionalInfo        : {[Age, Adult], [Gender, Female], [Language, 415], [Name, Microsoft Paulina Desktop]...}

Gender                : Male
Age                   : Adult
Name                  : Microsoft David Desktop
Culture               : en-US
Id                    : TTS_MS_EN-US_DAVID_11.0
Description           : Microsoft David Desktop - English (United States)
SupportedAudioFormats : {}
AdditionalInfo        : {[Age, Adult], [Gender, Male], [Language, 409], [Name, Microsoft David Desktop]...}

Finally a function to select the lector by his "name" like "David", "Paulina" or "Hazel":

say_something <- function(message , voice) {
        
  voice <- paste0("\"$speak.SelectVoice('Microsoft ", voice, " Desktop');" )
  message <- paste0("$speak.Speak('", message, "');\"")
      
  system2(command = "PowerShell", 
          args = c("-Command", 
                    "\"Add-Type -AssemblyName System.Speech;",
                    "$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;",
                    voice,
                    message
          ))
}


operations <- c("1st.", "2nd.", "3rd.")

lapply(operations, function(x) say_something(message=paste(x, "job done"), voice="David"))

Because of these many ideas, I have created a solution without Internet access, because I work with a VPN client with Windows. So it plays a typical Windows sound, which is usually on any Windows operating system.

#Function with loop, press Esc to stopp      
    alarm2 <- function(){
      while(TRUE){
        system("cmd.exe",input="C:/Windows/WinSxS/amd64_microsoft-windows-shell-sounds_31bf3856ad364e35_10.0.17134.1_none_fc93088a1eb3fd11/tada.wav")
        Sys.sleep(1)
      }
    }

Function without loop

    alarm3 <- function(){
        system("cmd.exe",input="C:/Windows/WinSxS/amd64_microsoft-windows-shell-sounds_31bf3856ad364e35_10.0.17134.1_none_fc93088a1eb3fd11/tada.wav")
        Sys.sleep(1)
    }

The following code produces a beep and does not depend on a .mp3 or .wav file:

switch(Sys.info()[['sysname']],
Linux = {
    system('play -n synth 0.1 tri  1000.0')}
)

Dason's answer is great, obviously, because it will work on basically any Windows machine without requiring anything except R itself.

But one thing I have been wondering is how to make these functions actually beep after a code is run.

If you do something like this:

beepR <- function(x, n = 3){
  for(i in seq(n)){
    system("rundll32 user32.dll,MessageBeep -1")
    Sys.sleep(.5)
  }
    return(x)
}

You can just pipe anything to it and it will return whatever you piped, so you can do like. See the example below.

fa <- psych::fa(x, 1) |> beepR()

I'm using here the native pipe |> that was introduced in R 4.1, but you can use the %>% pipe from the maggitr package if you like; they work the exact same way. Anyway, that will beep as soon as the analysis ends, and the variable fa will contain the results of the factor analysis.

Of course, here I used the beep function that Dason provided you, but you could just as easily add anything where I indicated below.

beepR <- function(x){
        # your code here #
        return(x)
    }

If you wish to add that function every time RStudio opens, refer to RStudio's Managing R with .Rprofile, .Renviron, Rprofile.site, Renviron.site, rsession.conf, and repos.conf to learn how to use a .Rprofile file.

Related