Playing Audio Files Made in the App with the Audio Package in ShinyDashboard

Hello,
So in my shinydashboard I create a sound file that is dependent on user defined inputs, and I would like that file to then be played by clicking an action button which triggers it to play. I have basically done this outside of shiny in a regular r script using the audio package, but for some reason when I turn it into a shiny app it won't work.

I am aware of the shiny tags::audio option, but the problem with that is that that is playing a sound file in the www folder that exists already, I am trying to play a file which I create in the app and which essentially only exists inside the app.

Thank you so much, any help is much appreciated!

Hello @Matthewh19, could you make a minimal REPRoducible EXample (reprex) about your issue?
Here is a very useful guide about how to make a reprex for a shiny app

Here is an example of the part of my app that I am having trouble with. Everything works except this very last part where it is supposed to play the new file. I would of course in the real thing have various controls that the user can set which will manipulate the resulting sound file, but for this I just exported an example with the default settings as this final part is the place where I am having a problem. In order for this to work you need the data set to play which I have put on google drive and is accessible at this link:

https://drive.google.com/file/d/12A-ENf1V8udN_B2IiLQhBpgpZQQ20cYm/view?usp=sharing


library(shiny)
library(shinydashboard)

Soundfile <- read_csv("Soundfile.csv")

ui <- dashboardPage(
  dashboardHeader(title = "Example Audio Play"),
  
  dashboardSidebar(
    sidebarMenu(
      menuItem("Play Audio", tabName = "playaudio", icon = icon("dashboard"))
    )),
  
  dashboardBody(
    tabItems(
      tabItem(tabName = "playaudio",
              fluidRow(
                box(title = "Controls", width = 4,
                    actionButton("playsound", label = "Play The Rebuilt Sound!"))
              )
      )
    )
  )
)

server <- function(input, output) {
  
  AudioFile <- reactive({
    Sound <- Soundfile()
    
    AudioFile <- structure(Sound, class = "note")
    
    return(AudioFile)
  })
  
  eventReactive(input$playsound, {
    audio::play(AudioFile())
  })
  
}


shinyApp(ui, server)



Also, for context, I don't know if this matters, but I am a high school student and I am doing this as a part of an independent study at my school that I am doing on Fourier Analysis. In this part of the project I am analyzing short instrument recordings, finding the frequencies that make up the sound and then rebuilding the sound. You would then be able to play that rebuilt sound, and that is where I am stuck. Some example controls that I have are that you can control the length of the final sound, the amount of peaks / frequencies used to rebuild the sound, etc.

I also am aware that most people use tags::audio() for playing sound files in shiny, but that requires that you are playing a pre existing file in a www folder, not a file that you made in the app.

Thank you for helping me with this!

1 Like

I did some initial research on this and here are my initial thoughts:

  • I haven't used the audio before, but I tried running your app code on my Linux laptop running R on Kubuntu 18.04 and I was not able to get any drivers to appear when running audio::audio.drivers(). If your app is to be deployed on a Shiny server or shinyapps.io, I am fairly certain you won't be able to get playback to work since those would run on top of Linux too.
  • If you are able to write out the processed audio as an audio file (WAV, MP3, etc), you could always write the file to the www directory of your app and try using tags$audio with that dynamically generated file.
  • There may be an opportunity to play the file as a base64-encoded object directly in javascript per this post:

Thank you for the ideas! I will look into what you talked about. If you have any other ideas please tell me!

Here is an update - I tried exporting the file then using tags to play it. I think that the export works because I did that in a regular r script and it exported and I could play it on my computer, so there must be a problem with the tags$audio.

library(shiny)
library(shinydashboard)
library(readr)
library(tuneR)
library(seewave)

Soundfile <- read_csv("Soundfile.csv")

ui <- dashboardPage(
  dashboardHeader(title = "Example Audio Play"),
  
  dashboardSidebar(
    sidebarMenu(
      menuItem("Play Audio", tabName = "playaudio", icon = icon("dashboard"))
    )),
  
  dashboardBody(
    tabItems(
      tabItem(tabName = "playaudio",
              fluidRow(
                box(title = "Controls", width = 4,
                    actionButton("playsound", label = "Play The Rebuilt Sound!"))
              )
      )
    )
  )
)

server <- function(input, output) {
    Soundwav <- Wave(left = Soundfile, samp.rate = 44100, bit = 32)
    savewav(Soundwav, filename = "www\\Soundwavexported.wav")
    
  
   eventReactive(input$playsound, {
    tags$audio(src = "Soundwavexported.wav", type = "audio/wav", autoplay = TRUE, controls = TRUE)
  })
  
}


shinyApp(ui, server)


Thanks!

I forgot to mention earlier that you may need to change your trigger for playing the audio file from eventReactive to observeEvent. I was not able to enter that block of processing in my prototype until I made that change.

I have made progress - I have gotten it to work in this example with the following code, but the problem is that when I put it in my app it doesn't work, and the only thing that has to be changed is that now the code that converts the file to .wav has to be reactive and the code that saves it to the file must use observe() so that it automatically completes the task, it isn't lazy like reactive({}), it must become:

Soundwav <- reactive({
    Wave(left = Soundfile(), samp.rate = 44100, bit = 32)
  })
  
  observe(
    savewav(Soundwav(), filename = "www/Soundwavexported.wav")
  )

And suddenly it stops working again. I checked to see if it is because when I use read_csv it imports as a data frame, and when it is in the main app it is a numeric, but the package says that it supports numerics.

Here is my solution for the example:

library(shiny)
library(shinydashboard)
library(readr)
library(tuneR)
library(seewave)

Soundfile <- read_csv("Soundfile.csv")
class(Soundfile)
ui <- dashboardPage(
  dashboardHeader(title = "Example Audio Play"),
  
  dashboardSidebar(
    sidebarMenu(
      menuItem("Play Audio", tabName = "playaudio", icon = icon("dashboard"))
    )),
  
  dashboardBody(
    tabItems(
      tabItem(tabName = "playaudio",
              fluidRow(
                box(title = "Controls", width = 4,
                    actionButton("playsound", label = "Play The Rebuilt Sound!"))
              )
      )
    )
  )
)

server <- function(input, output) {
    Soundwav <- Wave(left = Soundfile, samp.rate = 44100, bit = 16)
    savewav(Soundwav, filename = "www\\Soundwavexported.wav")
    
  
  observeEvent(input$playsound, {
    insertUI(selector = "#playsound",
             where = "afterEnd",
             ui = tags$audio(src = "Soundwavexported.wav", type = "audio/wav", autoplay = NA, controls = NA, style="display:none;")
  )
    })
  
}


shinyApp(ui, server)

Thanks!

1 Like

Thank you so much! It turned out that the last problem in my code was just a little mistake and once I fixed it, that last update that I posted about using reactive({}) and observe() stuff works! This has been great, thank you!

I hope that anyone else who tries to do this will find this whole thing helpful in the future.

Excellent job @Matthewh19! As someone who produces audio content, this will be something I play with in the near future. Since you've found the solution, would you mind choosing your own solution? That will help others find it more effectively. Here’s how to do it:

1 Like

This topic was automatically closed 54 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.