runRawdioIn
  :: FilePath -- ^ A directory for temporary files.
  -> Rawdio -- ^ Audio expression to evaluate.
  -> IO FilePath -- ^ The output file, which will be in the temporary directory.
runRawdioIn tempdir = go where

  new :: IO FilePath
  new = do
    (fp, h) <- openTempFile tempdir "scissors.wav"
    hClose h
    return fp

  go x = case x of
    Silence rate chans -> do
      output <- new
      sox
        [ "-n"
        , output
        , "trim", "0", "0"
        , "rate", show rate
        , "channels", show chans
        ]
      return output
    File input -> do
      output <- new
      case map toLower $ takeExtension input of
        ".mp3" -> callProcess "lame" ["--decode", input, output]
        _      -> sox [input, output]
      return output
    Concatenate auds -> combine "concatenate" auds
    Merge auds -> combine "merge" auds
    Mix auds -> combine "mix" auds
    Resample aud rate -> do
      input <- go aud
      output <- new
      sox [input, output, "rate", show rate]
      return output
    Pad    Front len aud -> transform aud ["pad", showTime len]
    Pad    Back  len aud -> transform aud ["pad", "0", showTime len]
    Trim   Front len aud -> transform aud ["trim", showTime len]
    Trim   Back  len aud -> transform aud ["trim", "0", '-' : showTime len]
    Cutoff Front len aud -> transform aud ["trim", "0", showTime len]
    Cutoff Back  len aud -> transform aud ["trim", '-' : showTime len]

  showTime :: Time -> String
  showTime (Seconds d) = show d
  showTime (Samples d) = show d ++ "s"

  transform :: Rawdio -> [String] -> IO FilePath
  transform aud args = do
    input <- go aud
    output <- new
    sox $ input : output : args
    return output

  combine :: String -> [(Double, Rawdio)] -> IO FilePath
  combine _ [] = error "runAudio: can't combine 0 audio files"
  combine _ [(v, aud)] = do
    input <- go aud
    output <- new
    sox ["-v", show v, input, output]
    return output
  combine method vauds = do
    inputs <- forM vauds $ T.mapM go
    output <- new
    sox
      $ ["--combine", method]
      ++ (inputs >>= \(v, f) -> ["-v", show v, f])
      ++ [output]
    return output
runRawdioIn
  :: FilePath -- ^ A directory for temporary files.
  -> Rawdio -- ^ Audio expression to evaluate.
  -> IO FilePath
runRawdioIn tempdir = go where

  new :: IO FilePath
  new = do
    (fp, h) <- openTempFile tempdir "scissors.wav"
    hClose h
    return fp

  go x = case x of
    Silence rate chans -> do
      output <- new
      sox
        [ "-n"
        , output
        , "trim", "0", "0"
        , "rate", show rate
        , "channels", show chans
        ]
      return output
    File input -> do
      output <- new
      case map toLower $ takeExtension input of
        ".mp3" -> callProcess "lame" ["--decode", input, output]
        _      -> sox [input, output]
      return output
    Concatenate auds -> combine "concatenate" auds
    Merge auds -> combine "merge" auds
    Mix auds -> combine "mix" auds
    Resample aud rate -> do
      input <- go aud
      output <- new
      sox [input, output, "rate", show rate]
      return output
    Pad    Front len aud -> transform aud ["pad", showTime len]
    Pad    Back  len aud -> transform aud ["pad", "0", showTime len]
    Trim   Front len aud -> transform aud ["trim", showTime len]
    Trim   Back  len aud -> transform aud ["trim", "0", '-' : showTime len]
    Cutoff Front len aud -> transform aud ["trim", "0", showTime len]
    Cutoff Back  len aud -> transform aud ["trim", '-' : showTime len]

  showTime :: Time -> String
  showTime (Seconds d) = show d
  showTime (Samples d) = show d ++ "s"

  transform :: Rawdio -> [String] -> IO FilePath
  transform aud args = do
    input <- go aud
    output <- new
    sox $ input : output : args
    return output

  combine :: String -> [(Double, Rawdio)] -> IO FilePath
  combine _ [] = error "runAudio: can't combine 0 audio files"
  combine _ [(v, aud)] = do
    input <- go aud
    output <- new
    sox ["-v", show v, input, output]
    return output
  combine method vauds = do
    inputs <- forM vauds $ T.mapM go
    output <- new
    sox
      $ ["--combine", method]
      ++ (inputs >>= \(v, f) -> ["-v", show v, f])
      ++ [output]
    return output
runRawdioIn tempdir = go where

  new :: IO FilePath
  new = do
    (fp, h) <- openTempFile tempdir "scissors.wav"
    hClose h
    return fp

  go x = case x of
    Silence rate chans -> do
      output <- new
      sox
        [ "-n"
        , output
        , "trim", "0", "0"
        , "rate", show rate
        , "channels", show chans
        ]
      return output
    File input -> do
      output <- new
      case map toLower $ takeExtension input of
        ".mp3" -> callProcess "lame" ["--decode", input, output]
        _      -> sox [input, output]
      return output
    Concatenate auds -> combine "concatenate" auds
    Merge auds -> combine "merge" auds
    Mix auds -> combine "mix" auds
    Resample aud rate -> do
      input <- go aud
      output <- new
      sox [input, output, "rate", show rate]
      return output
    Pad    Front len aud -> transform aud ["pad", showTime len]
    Pad    Back  len aud -> transform aud ["pad", "0", showTime len]
    Trim   Front len aud -> transform aud ["trim", showTime len]
    Trim   Back  len aud -> transform aud ["trim", "0", '-' : showTime len]
    Cutoff Front len aud -> transform aud ["trim", "0", showTime len]
    Cutoff Back  len aud -> transform aud ["trim", '-' : showTime len]

  showTime :: Time -> String
  showTime (Seconds d) = show d
  showTime (Samples d) = show d ++ "s"

  transform :: Rawdio -> [String] -> IO FilePath
  transform aud args = do
    input <- go aud
    output <- new
    sox $ input : output : args
    return output

  combine :: String -> [(Double, Rawdio)] -> IO FilePath
  combine _ [] = error "runAudio: can't combine 0 audio files"
  combine _ [(v, aud)] = do
    input <- go aud
    output <- new
    sox ["-v", show v, input, output]
    return output
  combine method vauds = do
    inputs <- forM vauds $ T.mapM go
    output <- new
    sox
      $ ["--combine", method]
      ++ (inputs >>= \(v, f) -> ["-v", show v, f])
      ++ [output]
    return output