packages feed

dobutokO2 0.10.1.0 → 0.11.0.0

raw patch · 5 files changed

+281/−186 lines, 5 filesnew-component:exe:O2help

Files

CHANGELOG.md view
@@ -105,3 +105,7 @@  * Tenth version revised A. Some documentation improvements. Some performance optimizations. +## 0.11.0.0 -- 2020-03-16++* Eleventh version. Added a second executable O2help that can be used to convert multiline Ukrainian text input to the needed String for the dobutokO2+program. Rewritten DobutokO.Sound.Executable module to provide more modularity. 
DobutokO/Sound/Executable.hs view
@@ -16,201 +16,253 @@   , recAndProcess ) where -import Numeric+import CaseBi (getBFst')+import Numeric (showFFloat) import Control.Exception (onException) import System.Environment (getArgs)-import Data.List (isPrefixOf,sort,sortBy)-import Data.Maybe (isJust,isNothing,fromJust)+import Data.List (isPrefixOf)+import Data.Maybe (fromJust) import Data.Char (isDigit) import System.Process-import EndOfExe--- import MMSyn7.Syllable --- import MMSyn7s+import EndOfExe (showE)+import qualified Data.Vector as V (fromList) import System.Directory import SoXBasics import Processing_mmsyn7ukr-import Melodics.Ukrainian import DobutokO.Sound hiding (dobutokO2, recAndProcess)--- import DobutokO.Sound.Functional   -- | Function that actually makes processing in the @dobutokO2@ executable. Please, check before executing -- whether there is no \"x.wav\", \"test*\", \"result*\" and \"end.wav\" files in the current directory, because they can be overwritten. dobutokO2 :: IO () dobutokO2 = do-  args <- getArgs-  let arg1 = concat . take 1 $ args-      file = concat . drop 1 . take 2 $ args+  arggs <- getArgs+  let arg1 = concat . take 1 $ arggs+      file = concat . drop 1 . take 2 $ arggs+      args = unwords . drop 2 $ arggs   exist2 <- doesFileExist file-  case arg1 of-    "1" -> do-      [_,_,octave,ampLS,time2] <- mapM (recAndProcess file) (if exist2 then [0,2,3,4,5] else [1..5])-      let octave1 = read octave::Int-          ampL = read ampLS::Double-          time3 = read time2::Double-      oberSoXSynthNGen file octave1 ampL time3 (unwords . drop 2 $ args)-    "2" -> do-      [_,_,octave,ampLS,time2,wws] <- mapM (recAndProcess file) (if exist2 then [0,2,3,4,5,6] else [1..6])-      let octave1 = read octave::Int-          ampL = read ampLS::Double-          time3 = read time2::Double-      uniqOberSoXSynthNGen file octave1 ampL time3 (unwords . drop 2 $ args) wws-    "3" -> do-      [_,_,octave,ampLS,time2,tts] <- mapM (recAndProcess file) (if exist2 then [0,2,3,4,5,7] else [1,2,3,4,5,7])-      let octave1 = read octave::Int-          ampL = read ampLS::Double-          time3 = read time2::Double-      oberSoXSynthNGen2 file octave1 ampL time3 (unwords . drop 2 $ args) tts-    "4" -> do-      [_,_,octave,ampLS,time2,wws,tts] <- mapM (recAndProcess file) (if exist2 then [0,2,3,4,5,6,7] else [1..7])-      let octave1 = read octave::Int-          ampL = read ampLS::Double-          time3 = read time2::Double-      uniqOberSoXSynthNGen3 file octave1 ampL time3 (unwords . drop 2 $ args) wws tts-    "5" -> do-      [_,_,octave,ampLS,time2,tts,dAmpl0,vs] <- mapM (recAndProcess file) (if exist2 then [0,2,3,4,5,7,8,9] else [1,2,3,4,5,7,8,9])-      let octave1 = read octave::Int-          ampL = read ampLS::Double-          time3 = read time2::Double-          dAmpl = read dAmpl0::Double-      oberSoXSynthNGen3 file octave1 ampL time3 dAmpl (unwords . drop 2 $ args) tts vs-    _   -> do-      [_,_,octave,ampLS,time2,wws,tts,dAmpl0,vs] <- mapM (recAndProcess file) (if exist2 then [0,2,3,4,5,6,7,8,9] else [1..9])-      let octave1 = read octave::Int-          ampL = read ampLS::Double-          time3 = read time2::Double-          dAmpl = read dAmpl0::Double-      uniqOberSoXSynthNGen4 file octave1 ampL time3 dAmpl (unwords . drop 2 $ args) wws tts vs+  getBFst' (dobutokO2H exist2 args file, V.fromList . fmap (\(xs, f) -> (xs,f exist2 args file)) $ [("1",dobutokO2H1),("2",dobutokO2H2),+    ("3",dobutokO2H3),("4",dobutokO2H4),("5",dobutokO2H5)]) arg1 +dobutokO2H1 :: Bool -> String -> FilePath -> IO ()+dobutokO2H1 exist2 args file = do+  [_,_,octave,ampLS,time2] <- mapM (recAndProcess file) (if exist2 then [0,2,3,4,5] else [1..5])+  let octave1 = read octave::Int+      ampL = read ampLS::Double+      time3 = read time2::Double+  oberSoXSynthNGen file octave1 ampL time3 args+{-# INLINE dobutokO2H1 #-}++dobutokO2H2 :: Bool -> String -> FilePath -> IO ()+dobutokO2H2 exist2 args file = do+  [_,_,octave,ampLS,time2,wws] <- mapM (recAndProcess file) (if exist2 then [0,2,3,4,5,6] else [1..6])+  let octave1 = read octave::Int+      ampL = read ampLS::Double+      time3 = read time2::Double+  uniqOberSoXSynthNGen file octave1 ampL time3 args wws+{-# INLINE dobutokO2H2 #-}++dobutokO2H3 :: Bool -> String -> FilePath -> IO ()+dobutokO2H3 exist2 args file = do+  [_,_,octave,ampLS,time2,tts] <- mapM (recAndProcess file) (if exist2 then [0,2,3,4,5,7] else [1,2,3,4,5,7])+  let octave1 = read octave::Int+      ampL = read ampLS::Double+      time3 = read time2::Double+  oberSoXSynthNGen2 file octave1 ampL time3 args tts+{-# INLINE dobutokO2H3 #-}++dobutokO2H4 :: Bool -> String -> FilePath -> IO ()+dobutokO2H4 exist2 args file = do+  [_,_,octave,ampLS,time2,wws,tts] <- mapM (recAndProcess file) (if exist2 then [0,2,3,4,5,6,7] else [1..7])+  let octave1 = read octave::Int+      ampL = read ampLS::Double+      time3 = read time2::Double+  uniqOberSoXSynthNGen3 file octave1 ampL time3 args wws tts+{-# INLINE dobutokO2H4 #-}++dobutokO2H5 :: Bool -> String -> FilePath -> IO ()+dobutokO2H5 exist2 args file = do+  [_,_,octave,ampLS,time2,tts,dAmpl0,vs] <- mapM (recAndProcess file) (if exist2 then [0,2,3,4,5,7,8,9] else [1,2,3,4,5,7,8,9])+  let octave1 = read octave::Int+      ampL = read ampLS::Double+      time3 = read time2::Double+      dAmpl = read dAmpl0::Double+  oberSoXSynthNGen3 file octave1 ampL time3 dAmpl args tts vs+{-# INLINE dobutokO2H5 #-}++dobutokO2H :: Bool -> String -> FilePath -> IO ()+dobutokO2H exist2 args file = do+  [_,_,octave,ampLS,time2,wws,tts,dAmpl0,vs] <- mapM (recAndProcess file) (if exist2 then [0,2,3,4,5,6,7,8,9] else [1..9])+  let octave1 = read octave::Int+      ampL = read ampLS::Double+      time3 = read time2::Double+      dAmpl = read dAmpl0::Double+  uniqOberSoXSynthNGen4 file octave1 ampL time3 dAmpl args wws tts vs+{-# INLINE dobutokO2H #-}++----------------------------------------------------------------------------------------------------------------------------------------------------+ -- | Function records and processes the sound data needed to generate the \"end.wav\" file in the 'dobutokO2' function. Please, check before executing -- whether there is no \"x.wav\" file in the current directory, because it can be overwritten.-recAndProcess :: String -> Int -> IO String-recAndProcess file x-  | x == 0 = onException (readProcessWithExitCode (fromJust (showE "sox")) [file, "x.wav", "-r22050", "channels", "1"] "" >> putStrLn "" >> return "") (do-     exist <- doesFileExist "x.wav"-     if exist then removeFile "x.wav"-     else putStr ""-     putStrLn ""-     putStr "The process was not successful may be because of the not valid data OR SoX cannot convert the given file to the .wav format. "-     putStrLn "Interrupt the program and start again with the valid file. "-     putStrLn "_______________________________________________________________________"-     recAndProcess file 0)-  | x == 1 = onException (do-     tempeRa 0-     putStrLn "Please, specify, how many seconds long sound data you would like to record."-     time <- getLine-     let time0 = read (filter (\t -> isDigit t || t == '.') $ time)::Double-     putStrLn "Please, wait for 0.5 second and produce the needed sound now."-     recA "x.wav" time0-     putStrLn ""-     return "") (do-       dir0 <- listDirectory "."-       let paths5 = filter (isPrefixOf "nx.") dir0-       mapM_ removeFile paths5-       putStrLn ""-       putStrLn "The process was not successful may be because of the not valid data. Please, specify the valid data as requested."-       putStrLn "_______________________________________________________________________"-       recAndProcess file 1)-  | x == 2 = onException (do     -     exist3 <- doesFileExist file-     if exist3 then return ""-     else do-       putStr "Please, specify the control parameter for the SoX \"noisered\" effect in the range from 0.0 to 1.0. "-       putStrLn "The greater value causes more reduction with possibly removing some important sound data. The default value is 0.5 "-       putStrLn "To use the default value, you can simply press Enter."-       ctrlN <- getLine-       let addit = dropWhile (/= '.') . filter (\t -> isDigit t || t == '.') $ ctrlN-           noiseP = if null ctrlN then ""-                    else tail addit-       controlNoiseReduction $ '0':noiseP -       norm "_x.wav" -       if isPrefixOf "nx." file -         then putStr "" -         else renameFile "8_x.wav" file -       removeFile "x.wav" -       removeFile "_x.wav" -       dir <- listDirectory "." -       let paths4 = filter (isPrefixOf "nx.") dir-       mapM_ removeFile paths4 -       putStrLn "" -       return "") (do-         putStrLn "The process was not successful may be because of the not valid data. Please, specify the valid data as requested."-         putStrLn "_______________________________________________________________________"-         recAndProcess file 2)-  | x == 3 = onException (do-     putStr "Please, specify the octave number, to which you would like all the main components (not taking into account their respective lower pure quints) "-     putStrLn "should belong. The number should be better in the range [1..8]"-     octave0 <- getChar-     let octave = (read [octave0]::Int) `rem` 9-     return $ show octave ) (do-       putStrLn "The process was not successful may be because of the not valid data. Please, specify the valid data as requested."-       putStrLn "_______________________________________________________________________"-       recAndProcess file 3)-  | x == 4 = onException (do-     putStr "Please, specify the amplitude for the generated obertones as an Int number in the range [0..99]. "-     putStrLn "The default one is 99"-     putStrLn "To use the default value, you can simply press Enter."-     amplOb0 <- getLine-     if null amplOb0 then return "1.0"-     else let amplOb = (read (take 2 . filter isDigit $ amplOb0)::Int) `rem` 100 in-          case amplOb of-            99 -> return "1.0"-            _ -> if compare (amplOb `quot` 9) 1 == LT then return $ "0.0" ++ show (amplOb + 1)-                 else return $ "0." ++ show (amplOb + 1)) (do-               putStrLn "The process was not successful may be because of the not valid data. Please, specify the valid data as requested."-               putStrLn "_______________________________________________________________________"-               recAndProcess file 4)-  | x == 5 = onException (do-     putStr "Please, specify the basic duration for the generated sounds as a Double number in the range [0.1..4.0]. "-     putStrLn "The default one is 0.5"-     putStrLn "To use the default value, you can simply press Enter."-     time0 <- getLine-     if null time0 then return "0.5"-     else let time1 = (read (filter (\z -> isDigit z || z == '.') $ time0)::Double) in-          if compare time1 0.1 /= LT && compare time1 4.0 /= GT then return (showFFloat (Just 4) time1 $ show 0)-          else let mantissa = time1 - (fromIntegral . truncate $ time1)-                   ceilP    = (truncate time1::Int) `rem` 4 in-               if ceilP == 0 then return ("0." ++ (showFFloat (Just 4) mantissa $ show 0))-               else return $ show ceilP ++ "." ++ (showFFloat (Just 4) mantissa $ show 0)) (do-               putStrLn "The process was not successful may be because of the not valid data. Please, specify the valid data as requested."-               putStrLn "_______________________________________________________________________"-               recAndProcess file 5)-  | x == 7 = onException (do-     putStrLn "Please, input the Ukrainian text that will be used to define signs for the harmonics coefficients to produce a special timbre for the notes: "-     tts <- getLine-     if null tts then return "або"-     else return tts) (do-       putStrLn "The process was not successful may be because of the not valid data. Please, specify the valid data as requested."-       putStrLn "_______________________________________________________________________"-       recAndProcess file 7)-  | x == 8 = onException (do-     putStr "Please, specify in how many times the amplitude for the second lower note (if any) is greater than the amplitude for the main note. "-     putStrLn "The number is in the range [0.1..2.0]. The default one is 1.0"-     putStrLn "To use the default value, you can simply press Enter."-     dAmpl0 <- getLine-     if null dAmpl0 then return "1.0"-     else let dAmpl1 = (read (filter (\z -> isDigit z || z == '.') $ dAmpl0)::Double) in-          if compare dAmpl1 0.1 /= LT && compare dAmpl1 2.0 /= GT then return (showFFloat (Just 4) dAmpl1 $ show 0)-          else let mantissa = dAmpl1 - (fromIntegral . truncate $ dAmpl1)-                   ceilP    = (truncate dAmpl1::Int) `rem` 2 in-               if ceilP == 0 then return ("0." ++ (showFFloat (Just 4) mantissa $ show 0))-               else return $ show ceilP ++ "." ++ (showFFloat (Just 4) mantissa $ show 0)) (do-               putStrLn "The process was not successful may be because of the not valid data. Please, specify the valid data as requested."-               putStrLn "_______________________________________________________________________"-               recAndProcess file 8)-  | x == 9 = onException (do-     putStrLn "Please, input the Ukrainian text that will be used to define intervals to be used to produce the lower note for the given main one. "-     putStrLn "The default one is \"й\". "-     putStrLn "To use the default value, you can simply press Enter."-     vs <- getLine-     if null vs then return "й"-     else return vs) (do-       putStrLn "The process was not successful may be because of the not valid data. Please, specify the valid data as requested."-       putStrLn "_______________________________________________________________________"-       recAndProcess file 9)-  | otherwise = onException (do-     putStrLn "Please, input the Ukrainian text that will be used to create a special timbre for the notes: "-     wws <- getLine-     return wws) (do-       putStrLn "The process was not successful may be because of the not valid data. Please, specify the valid data as requested."-       putStrLn "_______________________________________________________________________"-       recAndProcess file 100)+recAndProcess :: FilePath -> Int -> IO String+recAndProcess file x =+  getBFst' (processD, V.fromList [(0,processD0 file),(1,processD1),(2,processD2 file),(3,processD3),(4,processD4),(5,processD5),(7,processD7),+    (8,processD8),(9,processD9)]) x++processD0 :: FilePath -> IO String+processD0 file = onException (readProcessWithExitCode (fromJust (showE "sox")) [file, "x.wav", "-r22050", "channels", "1"] "" >> putStrLn "" >> return "") (do+  exist <- doesFileExist "x.wav"+  if exist then removeFile "x.wav"+  else putStr ""+  putStrLn ""+  putStr "The process was not successful may be because of the not valid data OR SoX cannot convert the given file to the .wav format. "+  putStrLn "Interrupt the program and start again with the valid file. "+  putStrLn "_______________________________________________________________________"+  processD0 file)+{-# INLINE processD0 #-}+  +processD1 :: IO String+processD1 = onException (do+  tempeRa 0+  putStrLn "Please, specify, how many seconds long sound data you would like to record."+  time <- getLine+  let time0 = read (filter (\t -> isDigit t || t == '.') $ time)::Double+  putStrLn "Please, wait for 0.5 second and produce the needed sound now."+  recA "x.wav" time0+  putStrLn ""+  return "") (do+    dir0 <- listDirectory "."+    let paths5 = filter (isPrefixOf "nx.") dir0+    mapM_ removeFile paths5+    putStrLn ""+    putStrLn "The process was not successful may be because of the not valid data. Please, specify the valid data as requested."+    putStrLn "_______________________________________________________________________"+    processD1)+{-# INLINE processD1 #-}++processD2 :: FilePath -> IO String+processD2 file = onException (do     +  exist3 <- doesFileExist file+  if exist3 then return ""+  else do+    putStr "Please, specify the control parameter for the SoX \"noisered\" effect in the range from 0.0 to 1.0. "+    putStrLn "The greater value causes more reduction with possibly removing some important sound data. The default value is 0.5 "+    putStrLn "To use the default value, you can simply press Enter."+    ctrlN <- getLine+    let addit = dropWhile (/= '.') . filter (\t -> isDigit t || t == '.') $ ctrlN+        noiseP = if null ctrlN then ""+                 else tail addit+    controlNoiseReduction $ '0':noiseP +    norm "_x.wav" +    if isPrefixOf "nx." file +      then putStr "" +      else renameFile "8_x.wav" file +    removeFile "x.wav" +    removeFile "_x.wav" +    dir <- listDirectory "." +    let paths4 = filter (isPrefixOf "nx.") dir+    mapM_ removeFile paths4 +    putStrLn "" +    return "") (do+      putStrLn "The process was not successful may be because of the not valid data. Please, specify the valid data as requested."+      putStrLn "_______________________________________________________________________"+      processD2 file)+{-# INLINE processD2 #-}++processD3 :: IO String+processD3 = onException (do+  putStr "Please, specify the octave number, to which you would like all the main components (not taking into account their respective lower pure quints) "+  putStrLn "should belong. The number should be better in the range [1..8]"+  octave0 <- getLine+  let octave = (read (take 1 octave0)::Int) `rem` 9+  return $ show octave ) (do+    putStrLn "The process was not successful may be because of the not valid data. Please, specify the valid data as requested."+    putStrLn "_______________________________________________________________________"+    processD3)+{-# INLINE processD3 #-}++processD4 :: IO String+processD4 = onException (do+  putStr "Please, specify the amplitude for the generated obertones as an Int number in the range [0..99]. "+  putStrLn "The default one is 99"+  putStrLn "To use the default value, you can simply press Enter."+  amplOb0 <- getLine+  if null amplOb0 then return "1.0"+  else let amplOb = (read (take 2 . filter isDigit $ amplOb0)::Int) `rem` 100 in+    case amplOb of+      99 -> return "1.0"+      _ -> if compare (amplOb `quot` 9) 1 == LT then return $ "0.0" ++ show (amplOb + 1)+           else return $ "0." ++ show (amplOb + 1)) (do+             putStrLn "The process was not successful may be because of the not valid data. Please, specify the valid data as requested."+             putStrLn "_______________________________________________________________________"+             processD4)+{-# INLINE processD4 #-}             ++processD5 :: IO String+processD5 = onException (do+  putStr "Please, specify the basic duration for the generated sounds as a Double number in the range [0.1..4.0]. "+  putStrLn "The default one is 0.5"+  putStrLn "To use the default value, you can simply press Enter."+  time0 <- getLine+  if null time0 then return "0.5"+  else let time1 = (read (filter (\z -> isDigit z || z == '.') $ time0)::Double) in+    if compare time1 0.1 /= LT && compare time1 4.0 /= GT then return (showFFloat (Just 4) time1 $ show 0)+    else let mantissa = time1 - (fromIntegral . truncate $ time1)+             ceilP    = (truncate time1::Int) `rem` 4 in+           if ceilP == 0 then return ("0." ++ (showFFloat (Just 4) mantissa $ show 0))+           else return $ show ceilP ++ "." ++ (showFFloat (Just 4) mantissa $ show 0)) (do+             putStrLn "The process was not successful may be because of the not valid data. Please, specify the valid data as requested."+             putStrLn "_______________________________________________________________________"+             processD5)+{-# INLINE processD5 #-}++processD7 :: IO String+processD7 = onException (do+  putStrLn "Please, input the Ukrainian text that will be used to define signs for the harmonics coefficients to produce a special timbre for the notes: "+  tts <- getLine+  if null tts then return "або"+  else return tts) (do+    putStrLn "The process was not successful may be because of the not valid data. Please, specify the valid data as requested."+    putStrLn "_______________________________________________________________________"+    processD7)+{-# INLINE processD7 #-}++processD8 :: IO String+processD8 = onException (do+  putStr "Please, specify in how many times the amplitude for the second lower note (if any) is greater than the amplitude for the main note. "+  putStrLn "The number is in the range [0.1..2.0]. The default one is 1.0"+  putStrLn "To use the default value, you can simply press Enter."+  dAmpl0 <- getLine+  if null dAmpl0 then return "1.0"+  else let dAmpl1 = (read (filter (\z -> isDigit z || z == '.') $ dAmpl0)::Double) in+    if compare dAmpl1 0.1 /= LT && compare dAmpl1 2.0 /= GT then return (showFFloat (Just 4) dAmpl1 $ show 0)+    else let mantissa = dAmpl1 - (fromIntegral . truncate $ dAmpl1)+             ceilP    = (truncate dAmpl1::Int) `rem` 2 in+           if ceilP == 0 then return ("0." ++ (showFFloat (Just 4) mantissa $ show 0))+           else return $ show ceilP ++ "." ++ (showFFloat (Just 4) mantissa $ show 0)) (do+             putStrLn "The process was not successful may be because of the not valid data. Please, specify the valid data as requested."+             putStrLn "_______________________________________________________________________"+             processD8)+{-# INLINE processD8 #-}++processD9 :: IO String+processD9 = onException (do+  putStrLn "Please, input the Ukrainian text that will be used to define intervals to be used to produce the lower note for the given main one. "+  putStrLn "The default one is \"й\". "+  putStrLn "To use the default value, you can simply press Enter."+  vs <- getLine+  if null vs then return "й"+  else return vs) (do+    putStrLn "The process was not successful may be because of the not valid data. Please, specify the valid data as requested."+    putStrLn "_______________________________________________________________________"+    processD9)+{-# INLINE processD9 #-}++processD :: IO String+processD = onException (do+  putStrLn "Please, input the Ukrainian text that will be used to create a special timbre for the notes: "+  wws <- getLine+  return wws) (do+    putStrLn "The process was not successful may be because of the not valid data. Please, specify the valid data as requested."+    putStrLn "_______________________________________________________________________"+    processD)+{-# INLINE processD #-}
+ O2Help.hs view
@@ -0,0 +1,25 @@+-- |+-- Module      :  O2Help+-- Copyright   :  (c) OleksandrZhabenko 2020+-- License     :  MIT+-- Stability   :  Experimental+-- Maintainer  :  olexandr543@yahoo.com+--+-- A program and a library to create experimental music+-- from a mono audio and a Ukrainian text.++{-# OPTIONS_GHC -threaded #-}++-- | The main function in the executable @O2help@. It converts its input (possibly multiline) to the output String and prints it to the stdout.+main :: IO ()+main = o2help++-- | Takes textual input from the stdin and prints it as one 'String' to the stdout.+o2help :: IO ()+o2help = do+  xs <- getContents+  let ys = unwords . lines $ xs in do+    putStrLn ""+    putStrLn "-------------------------------------------------------------------------------------------------------------"+    putStrLn ys+  
README.markdown view
@@ -13,7 +13,7 @@  For the executable you enter in the terminal: -dobutokO2 {1 | 2 | 3 | 4 | 5 | 6} {fileName} {Ukrainian text}+dobutokO2 { 1 | 2 | 3 | 4 | 5 | 6 } {fileName} {Ukrainian text}    where filename is:   the full name of the file to be recorded in the current directory or@@ -28,8 +28,8 @@    "2", or "4", or "6" -> then the program uses uniqOberTones functions. -  "3", or "4", or "5", or "6" -> the program uses additional String-    to define signs for the harmonics coefficients for obertones.+  "3", or "4", or "5", or "6" -> the program uses additional String to define+    signs for the harmonics coefficients for obertones.          In more detail: @@ -54,6 +54,10 @@    _  -> the program behaves like for the "5" option, but generates      obertones using additional String and allows maximum control over         the parameters.++If you specified just one of the previous with the zero at the end, then to stop+the Ukrainian textual input just press the keyboard keys combination that means+an end of input (e. g. for Unices it is Ctrl + D).  After the program executing (it takes some time) there is a file "end.wav" in the directory. This is the resulting melody generated.
dobutokO2.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/  name:                dobutokO2-version:             0.10.1.0+version:             0.11.0.0 synopsis:            A program and a library to create experimental music from a mono audio and a Ukrainian text description:         It can also create a timbre for the notes homepage:            https://hackage.haskell.org/package/dobutokO2@@ -17,7 +17,7 @@ cabal-version:       >=1.10  library-  exposed-modules:     Main, DobutokO.Sound, DobutokO.Sound.Functional, DobutokO.Sound.Executable+  exposed-modules:     Main, DobutokO.Sound, DobutokO.Sound.Functional, DobutokO.Sound.Executable, O2Help   -- other-modules:   -- other-extensions:   build-depends:       base >=4.7 && <4.14, vector >=0.11 && <0.14, process >=1.4 && <1.8, mmsyn3 >=0.1.4 && <1, mmsyn7s >=0.6.6 && <1, directory >=1.2.5 && <1.6, mmsyn7ukr >=0.15.3 && <1, mmsyn2 >=0.1.7 && <1, mmsyn6ukr >=0.6.3.1 && <1@@ -30,4 +30,14 @@   -- other-extensions:   build-depends:       base >=4.7 && <4.14, vector >=0.11 && <0.14, process >=1.4 && <1.8, mmsyn3 >=0.1.4 && <1, mmsyn7s >=0.6.6 && <1, directory >=1.2.5 && <1.6, mmsyn7ukr >=0.15.3 && <1, mmsyn2 >=0.1.7 && <1, mmsyn6ukr >=0.6.3.1 && <1   -- hs-source-dirs:+  ghc-options:         -main-is Main   default-language:    Haskell2010++executable O2help+  main-is:             O2Help.hs+  -- other-modules:+  -- other-extensions:+  build-depends:       base >=4.7 && <4.14+  -- hs-source-dirs:+  ghc-options:         -main-is O2Help+  default-language:    Haskell2010