开发者

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

When I run R scripts I go 开发者_C百科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?


I have a package (beepr) with the sole purpose of making notification sounds in R which should work cross-platform. Run the following to install beepr and make a sound:

install.packages("beepr")
library(beepr)
beep()

More info at github: https://github.com/rasmusab/beepr


alarm()

The alarm function. It works by sending \a to the console


On MacOSX you can let the computer speak:

system("say Just finished!")

and you can also change the artificial voice that will speak:

system("say -v Kathy Just finished!")

You can pick any voice that is available on your computer. On Yosemite you can see which voices are installed in System Preferences -> Dictation & Speech -> Text to Speech.


You should have it tweet when it's done: http://cran.r-project.org/web/packages/twitteR/index.html


alarm doesn't work on my Windows machine so I created a function that does actually make noise.

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

This clearly could only work on Windows but I don't guarantee it will even run on an arbitrary Windows computer. I've only tested it on my machine but I figured I'd post it in case anybody has the same problem with alarm that I do.


cat('Hello world!\a')


How about something reasonably OS independent for OSes with GUIs and web-browsers? It even works on RStudio Server!

browseURL('https://www.youtube.com/watch?v=QH2-TGUlwu4')


Not only that, you can also also put some epic music from Youtube when the program is done looping :) (For Ubuntu/Debian:)

system("xdg-open 'http://www.youtube.com/watch?v=9jK-NcRmVcw'")


UPDATE:

With macOS 10.9 (Mavericks) and later, you can post notifications using plain AppleScript:

theTitle <- "A Title"
theMsg <- "A message here"

cmd <- paste("osascript -e ", "'display notification ", '"', theMsg, '"', ' with title ', '"', theTitle, '"', "'", sep='')
system(cmd)

This removes the need to install terminal-notifier, referenced below.

--

I've got terminal-notifier installed on my Mac to get desktop notifications from the command line. You can then wrap up a call to the system() command like this (change the path, obviously):

notify <- function(msgString='Message from R', titleString='Message from R', speakIt=FALSE) {
    cmd <- paste('~/terminal-notifier/terminal-notifier.app/Contents/MacOS/terminal-notifier -message ', '"', msgString, '"  -title "', titleString, '"', sep='')
    system(cmd)

    if (speakIt) {
        system(paste('say', msgString))
    }

}

You can call the function like this

notify("R is done", "Message from R", speakIt=TRUE)

to get a message like this:

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

Update: Included @VLC's say command.


Please use shell.exec("url") to open some YouTube clip on Windows


Or if you're using GNU/Linux distro and have pcspkr module blacklisted (PC speaker was always annoying me), try combining system with some auditive/visual notification, e.g.

system("aplay -t wav /usr/share/sounds/phone.wav") # for auditive bell (an I mean it literary)
system("zenity --title=\"R script info\" --text=\"Script has finished with zero exit status\" --info") # for GTK dialog

You can check zenity manual if you prefer alert in, say, notification area... But, with system function, you can do pretty much anything: send an email, run some other script, reboot the machine, sudo rm -rf *.*, etc. anything... and I mean it.

But this stands only IF you're running GNU/Linux (or UNIX) distribution, otherwise, stick to Windows specific commands, though in that case, I can't give you much info...


Inspired by beepr, this is the function I'm currently using for these kind of problems :D

work_complete <- function() {
  cat("Work complete. Press esc to sound the fanfare!!!\n")
  on.exit(beepr::beep(3))

  while (TRUE) {
    beepr::beep(4)
    Sys.sleep(1)
  }
}


How about playing some music?

shell.exec("foo/Born.to.be.wild.mp3")


take a look at this package: RPushBullet

An R interface to the Pushbullet messaging service which provides fast and efficient notifications (and file transfer) between computers, phones and tablets

RPushbullet is completely free and multi platform. As for your question, you can use this library to send a Push to your browser, but obviously it becomes amazing when you need something than can notify you while you are away. Moreover, the creator of the R package is the same of the well known Rcpp, Dirk Eddelbuettel. I'd say it's worth a shot!


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"))


You can use notify-send command:

system("notify-send \"R script finished running\"")


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.


Combining some ideas on the thread, I implement this:

options(error = function() {
    if (interactive()) {
        # require("beepr"); beep(10)
        system("mplayer /usr/share/sounds/freedesktop/stereo/dialog-warning.oga ")
        system("notify-send -u normal 'R session' 'An error occured!'")
    }
})

I regularly use stop() on interactive session like Rstudio, on scripts I am working and want to re-run to a point. This way I can switch to another desktop while waiting. I may test it to '.Rprofile'

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜