packages feed

dobutokO2 0.19.1.0 → 0.20.0.0

raw patch · 4 files changed

+247/−22 lines, 4 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ DobutokO.Sound.Functional: oberSoXSynthGen2FDN :: FilePath -> Int -> Int -> (Double -> Vector (Double, Double)) -> Double -> String -> String -> IO ()
+ DobutokO.Sound.Functional: oberSoXSynthGen2FDN_B :: FilePath -> Int -> Int -> (Double -> Vector (Double, Double)) -> Double -> Double -> String -> String -> IO ()
+ DobutokO.Sound.Functional: oberSoXSynthGen2FDN_S :: FilePath -> Int -> Int -> (Double -> Vector (Double, Double)) -> Double -> String -> String -> IO ()
+ DobutokO.Sound.Functional: oberSoXSynthGen2FDN_Sf :: FilePath -> Int -> Int -> (Double -> Vector (Double, Double)) -> Double -> String -> String -> IO ()
+ DobutokO.Sound.Functional: oberSoXSynthGen2FDN_Sf3 :: FilePath -> Int -> Int -> (Double -> Vector (Double, Double)) -> Double -> Double -> String -> String -> IO ()
+ DobutokO.Sound.ParseList: parseVInf :: Vector String -> Maybe [Int]
- DobutokO.Sound.Functional: oberSoXSynth2FDN :: (Double -> Vector (Double, Double)) -> (Double, Double) -> String -> IO ()
+ DobutokO.Sound.Functional: oberSoXSynth2FDN :: (Double -> Vector (Double, Double)) -> (Double, Double) -> Int -> String -> IO ()
- DobutokO.Sound.Functional: oberSoXSynth2FDN_B :: (Double -> Vector (Double, Double)) -> (Double, Double, Double) -> String -> IO ()
+ DobutokO.Sound.Functional: oberSoXSynth2FDN_B :: (Double -> Vector (Double, Double)) -> (Double, Double, Double) -> Int -> String -> IO ()
- DobutokO.Sound.Functional: oberSoXSynth2FDN_S :: (Double -> Vector (Double, Double)) -> (Double, Double) -> String -> IO ()
+ DobutokO.Sound.Functional: oberSoXSynth2FDN_S :: (Double -> Vector (Double, Double)) -> (Double, Double) -> Int -> String -> IO ()
- DobutokO.Sound.Functional: oberSoXSynth2FDN_Sf :: (Double -> Vector (Double, Double)) -> (Double, Double) -> String -> IO ()
+ DobutokO.Sound.Functional: oberSoXSynth2FDN_Sf :: (Double -> Vector (Double, Double)) -> (Double, Double) -> Int -> String -> IO ()
- DobutokO.Sound.Functional: oberSoXSynth2FDN_Sf3 :: (Double -> Vector (Double, Double)) -> (Double, Double, Double) -> String -> IO ()
+ DobutokO.Sound.Functional: oberSoXSynth2FDN_Sf3 :: (Double -> Vector (Double, Double)) -> (Double, Double, Double) -> Int -> String -> IO ()

Files

CHANGELOG.md view
@@ -183,3 +183,8 @@  * Nineteenth version revised A. Fixed issue with the infinite lists and thus the divergent functions. Changed some functions and fulfilled them with a limitation parameter. Some minor documentation improvements.++## 0.20.0.0 -- 2020-03-28++* Twentieth version. Improved behaviour of the functions in the DobutokO.Sound.Functional module. Added new functions to produce melodies. Some minor+documentation improvements.
DobutokO/Sound/Functional.hs view
@@ -20,8 +20,15 @@   -- *** With additional filtering   , oberSoXSynth2FDN_Sf   , oberSoXSynth2FDN_Sf3+  -- * Use additional function and Ukrainian texts and generates melody+  , oberSoXSynthGen2FDN+  , oberSoXSynthGen2FDN_B+  , oberSoXSynthGen2FDN_S+  , oberSoXSynthGen2FDN_Sf+  , oberSoXSynthGen2FDN_Sf3 ) where +import Data.Char (isDigit) import System.Exit (ExitCode( ExitSuccess )) import Numeric import Data.List (isPrefixOf,sort,sortBy,nubBy)@@ -31,23 +38,26 @@ import EndOfExe import System.Directory import Melodics.Ukrainian+import SoXBasics (durationA) import DobutokO.Sound hiding (oberSoXSynth2FDN)  -- | Similar to 'oberSoXSynth2DN' but instead of 'oberTones' function, it uses volatile function @f::Double -> Vector (Double, Double)@ with -- somewhat sophisticated mechanism to normalize the resulting 'V.Vector' elements @(Double, Double)@. The last one is an experimental feature, so -- it is your responsibility to provide a function so that it does not lead to clipping. In such a case, the result of application of the--- 'convertToProperUkrainian' to the 'String' parameter must not be 'V.empty'.+-- 'convertToProperUkrainian' to the 'String' parameter must not be 'V.empty'. 'Int' argument is an index of the element to be taken from +-- the 'intervalsFromString' applied to the 'String' argument. To obtain compatible with versions prior to 0.20.0.0 behaviour, use for the 'Int' 0. -- -- Be aware that the result can be rather unpredictable (the program can even obtain segmentation fault) for not very suitable function. -- But for a lot of functions this works well. --  -- It is recommended to fully simplify the computation for \"f\" function before using it in the 'oberSoXSynth2FDN'.-oberSoXSynth2FDN :: (Double -> V.Vector (Double, Double)) -> (Double, Double) -> String -> IO ()-oberSoXSynth2FDN f (x, y) zs+oberSoXSynth2FDN :: (Double -> V.Vector (Double, Double)) -> (Double, Double) -> Int -> String -> IO ()+oberSoXSynth2FDN f (x, y) j zs  | V.null . convertToProperUkrainian $ zs = oberSoXSynth x  | otherwise = do     let note0 = closestNote (if x /= 0.0 then abs x else V.unsafeIndex notes 0)-        note1 = dNote (V.unsafeIndex (intervalsFromString zs) 0) note0+        l0     = length zs+        note1 = dNote (V.unsafeIndex (intervalsFromString zs) (abs (j `rem` l0))) note0         g0    = V.fromList . nubBy (\(!x1,_) (!x2,_) -> x1 == x2) . V.toList . V.map (\(noteX, !amplX) ->            if noteX <= 0.0 then (fromIntegral 2 * note0, abs (amplX - (fromIntegral . truncate $ amplX))) else (closestNote noteX,              abs (amplX - (fromIntegral . truncate $ amplX)))) . f@@ -79,25 +89,60 @@     _ <- readProcessWithExitCode (fromJust (showE "sox")) (["--combine", "mix"] ++ paths ++ ["result.wav","vol","0.3"]) ""     mapM_ removeFile paths +-- | Uses additional 'Int' parameters. The first one is a number of enka (see 'nkyT'). The second one defines, to which n-th elements set+-- (see 'nkyT') belongs the obtained higher notes in the intervals. To obtain reasonable results, please, use for the first one 2, 3, 4, 6, 9, or 12.+-- The first 'String' parameter is used to produce durations of the notes. The second one is used to define intervals. A 'Double' parameter is a+-- basic sound duration, it defines tempo of the melody in general.+oberSoXSynthGen2FDN :: FilePath -> Int -> Int -> (Double -> V.Vector (Double, Double)) -> Double -> String -> String -> IO ()+oberSoXSynthGen2FDN file m ku f y zs wws = do+  duration0 <- durationA file+  let n = truncate (duration0 / 0.001)+  vecA <- V.generateM n (\k -> do {+    (_, _, herr) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "-n", "trim", showFFloat (Just 4) (fromIntegral k * 0.001) $ show 0,+      "0.001", "stat"] ""+    ; let line0s = lines herr+          noteN0 = takeWhile isDigit . dropWhile (not . isDigit) . concat . drop 13 . take 14 $ line0s+    ; if null noteN0 then return (11440::Int)+      else let noteN1  = read (takeWhile isDigit . dropWhile (not . isDigit) . concat . drop 13 . take 14 $ line0s)::Int in return noteN1 })+  let vecB = liftInEnkuV m ku . V.map fromIntegral . V.filter (/= (11440::Int)) $ vecA+      (t, ws) = splitAt 1 . syllableStr n $ zs+      m0    = length ws+      zeroN = numVZeroesPre vecB+      v2    = V.map (\yy -> y * fromIntegral (yy * m0) / fromIntegral (head t)) . V.fromList $ ws in V.imapM_ (\j x -> do+        oberSoXSynth2FDN f (x, (V.unsafeIndex v2 (j `rem` (V.length v2)))) j wws+        renameFile "result.wav" $ "result0" ++ prependZeroes zeroN (show (j + 1)) ++ ".wav") vecB+  path2s <- listDirectory "."+  let paths3 = sort . filter (isPrefixOf "result") $ path2s+  (code,_,_) <- readProcessWithExitCode (fromJust (showE "sox")) (paths3 ++ ["end.wav"]) ""+  case code of+    ExitSuccess -> putStrLn "The final file \"end.wav\" was successfully created. You can now manually change or delete \"result*\" files in the directory. "+    _           -> do+      exi <- doesFileExist "end.wav"+      if exi then removeFile "end.wav"+      else putStr "Your final file \"end.wav\" was not created by some reason, but the intermediate files in the respective order are present. " >>+        putStrLn "Use them manually as needed."+ -- | Similar to 'oberSoXSynth2DN' but instead of 'oberTones' function, it uses volatile function @f::Double -> Vector (Double, Double)@ with -- somewhat sophisticated mechanism to normalize the resulting 'V.Vector' elements @(Double, Double)@. The last one is experimental feature, so -- it is your responsibility to provide a function so that it does not lead to clipping. In such a case, the result of application of the -- 'convertToProperUkrainian' to the 'String' parameter must not be 'V.empty'. The function also tries to perform filtering to avoid possible beating. -- The third 'Double' parameter in the tuple is used as a limit for frequencies difference in Hz to be filtered out from the resulting sound. It is--- considered to be from the range @[0.1..10.0]@.+-- considered to be from the range @[0.1..10.0]@. An 'Int' parameter is used to define the needed interval. To obtain compatible with versions prior+-- to 0.20.0.0 behaviour, use for the 'Int' 0. -- -- Be aware that the result can be rather unpredictable (the program can even obtain segmentation fault) for not very suitable function. -- But for a lot of functions this works well. --  -- It is recommended to fully simplify the computation for \"f\" function before using it in the 'oberSoXSynth2FDN_B'.-oberSoXSynth2FDN_B :: (Double -> V.Vector (Double, Double)) -> (Double, Double, Double) -> String -> IO ()-oberSoXSynth2FDN_B f (x, y, limB) zs+oberSoXSynth2FDN_B :: (Double -> V.Vector (Double, Double)) -> (Double, Double, Double) -> Int -> String -> IO ()+oberSoXSynth2FDN_B f (x, y, limB) j zs  | V.null . convertToProperUkrainian $ zs = oberSoXSynth x  | otherwise = do     let limA0 = abs ((limB / fromIntegral 10) - (fromIntegral . truncate $ (limB / fromIntegral 10))) * fromIntegral 10         limA  = if compare limA0 0.1 == LT then 0.1 else limA0+        l0    = length zs         note0 = closestNote (if x /= 0.0 then abs x else V.unsafeIndex notes 0)-        note1 = dNote (V.unsafeIndex (intervalsFromString zs) 0) note0+        note1 = dNote (V.unsafeIndex (intervalsFromString zs) (abs (j `rem` l0))) note0         g0    = V.fromList . nubBy (\(!x1,_) (!x2,_) -> compare (abs (x1 - x2)) limA == LT) . V.toList . V.map (\(noteX, !amplX) ->            if noteX <= 0.0 then (fromIntegral 2 * note0, abs (amplX - (fromIntegral . truncate $ amplX))) else (closestNote noteX,              abs (amplX - (fromIntegral . truncate $ amplX)))) . f@@ -127,22 +172,58 @@     paths0 <- listDirectory "."     let paths = sort . filter (isPrefixOf "test") $ paths0     _ <- readProcessWithExitCode (fromJust (showE "sox")) (["--combine", "mix"] ++ paths ++ ["result.wav","vol","0.3"]) ""-    mapM_ removeFile paths    +    mapM_ removeFile paths +-- | Uses additional 'Int' parameters. The first one is a number of enka (see 'nkyT'). The second one defines, to which n-th elements set+-- (see 'nkyT') belongs the obtained higher notes in the intervals. To obtain reasonable results, please, use for the first one 2, 3, 4, 6, 9, or 12.+-- The first 'String' parameter is used to produce durations of the notes. The second one is used to define intervals. The first 'Double' parameter is a+-- basic sound duration, it defines tempo of the melody in general. The second one is a limit for frequencies difference in Hz to be filtered out from the+-- resulting sound. It is considered to be from the range @[0.1..10.0]@.+oberSoXSynthGen2FDN_B :: FilePath -> Int -> Int -> (Double -> V.Vector (Double, Double)) -> Double -> Double -> String -> String -> IO ()+oberSoXSynthGen2FDN_B file m ku f y limB zs wws = do+  duration0 <- durationA file+  let n = truncate (duration0 / 0.001)+  vecA <- V.generateM n (\k -> do {+    (_, _, herr) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "-n", "trim", showFFloat (Just 4) (fromIntegral k * 0.001) $ show 0,+      "0.001", "stat"] ""+    ; let line0s = lines herr+          noteN0 = takeWhile isDigit . dropWhile (not . isDigit) . concat . drop 13 . take 14 $ line0s+    ; if null noteN0 then return (11440::Int)+      else let noteN1  = read (takeWhile isDigit . dropWhile (not . isDigit) . concat . drop 13 . take 14 $ line0s)::Int in return noteN1 })+  let vecB = liftInEnkuV m ku . V.map fromIntegral . V.filter (/= (11440::Int)) $ vecA+      (t, ws) = splitAt 1 . syllableStr n $ zs+      m0    = length ws+      zeroN = numVZeroesPre vecB+      v2    = V.map (\yy -> y * fromIntegral (yy * m0) / fromIntegral (head t)) . V.fromList $ ws in V.imapM_ (\j x -> do+        oberSoXSynth2FDN_B f (x, (V.unsafeIndex v2 (j `rem` (V.length v2))), limB) j wws+        renameFile "result.wav" $ "result0" ++ prependZeroes zeroN (show (j + 1)) ++ ".wav") vecB+  path2s <- listDirectory "."+  let paths3 = sort . filter (isPrefixOf "result") $ path2s+  (code,_,_) <- readProcessWithExitCode (fromJust (showE "sox")) (paths3 ++ ["end.wav"]) ""+  case code of+    ExitSuccess -> putStrLn "The final file \"end.wav\" was successfully created. You can now manually change or delete \"result*\" files in the directory. "+    _           -> do+      exi <- doesFileExist "end.wav"+      if exi then removeFile "end.wav"+      else putStr "Your final file \"end.wav\" was not created by some reason, but the intermediate files in the respective order are present. " >>+        putStrLn "Use them manually as needed."+ -- | Similar to 'oberSoXSynth2FDN' but it does not make any normalizing transformations with the 'V.Vector' argument. To be used properly, it is needed -- that every second element in the tuple in the 'V.Vector' argument must be in the range [-1.0..1.0] and every first element must be in between--- 16.351597831287414 and 7902.132820097988 (Hz).+-- 16.351597831287414 and 7902.132820097988 (Hz). An 'Int' parameter is used to define an interval. To obtain compatible with versions prior to+-- 0.20.0.0 behaviour, use for the 'Int' 0. -- -- Be aware that the result can be rather unpredictable (the program can even obtain segmentation fault) for not very suitable function. -- But for a lot of functions this works well. --  -- It is recommended to fully simplify the computation for \"f\" function before using it in the 'oberSoXSynth2FDN_S'.-oberSoXSynth2FDN_S :: (Double -> V.Vector (Double, Double)) -> (Double, Double) -> String -> IO ()-oberSoXSynth2FDN_S f (x, y) zs+oberSoXSynth2FDN_S :: (Double -> V.Vector (Double, Double)) -> (Double, Double) -> Int -> String -> IO ()+oberSoXSynth2FDN_S f (x, y) j zs  | V.null . convertToProperUkrainian $ zs = oberSoXSynth x  | otherwise = do     let note0 = closestNote (if x /= 0.0 then abs x else V.unsafeIndex notes 0)-        note1 = dNote (V.unsafeIndex (intervalsFromString zs) 0) note0+        l0    = length zs+        note1 = dNote (V.unsafeIndex (intervalsFromString zs) (abs (j `rem` l0))) note0         v0    = f note0         v1    = if isNothing note1 then V.empty                 else f . fromJust $ note1@@ -195,19 +276,51 @@     _ <- readProcessWithExitCode (fromJust (showE "sox")) (["--combine", "mix"] ++ paths ++ ["result.wav","vol","0.3"]) ""     mapM_ removeFile paths +-- | Similar to 'oberSoXSynthGen2FDN', but instead of 'oberSoXSynth2FDN' uses 'oberSoXSynth2FDN_S' function. +oberSoXSynthGen2FDN_S :: FilePath -> Int -> Int -> (Double -> V.Vector (Double, Double)) -> Double -> String -> String -> IO ()+oberSoXSynthGen2FDN_S file m ku f y zs wws = do+  duration0 <- durationA file+  let n = truncate (duration0 / 0.001)+  vecA <- V.generateM n (\k -> do {+    (_, _, herr) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "-n", "trim", showFFloat (Just 4) (fromIntegral k * 0.001) $ show 0,+      "0.001", "stat"] ""+    ; let line0s = lines herr+          noteN0 = takeWhile isDigit . dropWhile (not . isDigit) . concat . drop 13 . take 14 $ line0s+    ; if null noteN0 then return (11440::Int)+      else let noteN1  = read (takeWhile isDigit . dropWhile (not . isDigit) . concat . drop 13 . take 14 $ line0s)::Int in return noteN1 })+  let vecB = liftInEnkuV m ku . V.map fromIntegral . V.filter (/= (11440::Int)) $ vecA+      (t, ws) = splitAt 1 . syllableStr n $ zs+      m0    = length ws+      zeroN = numVZeroesPre vecB+      v2    = V.map (\yy -> y * fromIntegral (yy * m0) / fromIntegral (head t)) . V.fromList $ ws in V.imapM_ (\j x -> do+        oberSoXSynth2FDN_S f (x, (V.unsafeIndex v2 (j `rem` (V.length v2)))) j wws+        renameFile "result.wav" $ "result0" ++ prependZeroes zeroN (show (j + 1)) ++ ".wav") vecB+  path2s <- listDirectory "."+  let paths3 = sort . filter (isPrefixOf "result") $ path2s+  (code,_,_) <- readProcessWithExitCode (fromJust (showE "sox")) (paths3 ++ ["end.wav"]) ""+  case code of+    ExitSuccess -> putStrLn "The final file \"end.wav\" was successfully created. You can now manually change or delete \"result*\" files in the directory. "+    _           -> do+      exi <- doesFileExist "end.wav"+      if exi then removeFile "end.wav"+      else putStr "Your final file \"end.wav\" was not created by some reason, but the intermediate files in the respective order are present. " >>+        putStrLn "Use them manually as needed."+ -- | Similar to 'oberSoXSynth2FDN_S' but additionally the program filters out from the resulting 'V.Vector' after \"f\" application values that are smaller--- by absolute value than 0.001.+-- by absolute value than 0.001. An 'Int' parameter is used to define an interval. To obtain compatible with versions prior to+-- 0.20.0.0 behaviour, use for the 'Int' 0. -- -- Be aware that the result can be rather unpredictable (the program can even obtain segmentation fault) for not very suitable function. -- But for a lot of functions this works well. --  -- It is recommended to fully simplify the computation for \"f\" function before using it in the 'oberSoXSynth2FDN_Sf'.-oberSoXSynth2FDN_Sf :: (Double -> V.Vector (Double, Double)) -> (Double, Double) -> String -> IO ()-oberSoXSynth2FDN_Sf f (x, y) zs+oberSoXSynth2FDN_Sf :: (Double -> V.Vector (Double, Double)) -> (Double, Double) -> Int -> String -> IO ()+oberSoXSynth2FDN_Sf f (x, y) j zs  | V.null . convertToProperUkrainian $ zs = oberSoXSynth x  | otherwise = do     let note0 = closestNote (if x /= 0.0 then abs x else V.unsafeIndex notes 0)-        note1 = dNote (V.unsafeIndex (intervalsFromString zs) 0) note0+        l0    = length zs+        note1 = dNote (V.unsafeIndex (intervalsFromString zs) (abs (j `rem` l0))) note0         v0    = V.filter (\(_,!z) -> compare (abs z) 0.001 == GT) . f $ note0         v1    = if isNothing note1 then V.empty                 else V.filter (\(_,!z) -> compare z 0.001 == GT) . f . fromJust $ note1@@ -256,19 +369,51 @@     _ <- readProcessWithExitCode (fromJust (showE "sox")) (["--combine", "mix"] ++ paths ++ ["result.wav","vol","0.3"]) ""     mapM_ removeFile paths +-- | Similar to 'oberSoXSynthGen2FDN_S', but instead of 'oberSoXSynth2FDN_S' uses 'oberSoXSynth2FDN_Sf' function. +oberSoXSynthGen2FDN_Sf :: FilePath -> Int -> Int -> (Double -> V.Vector (Double, Double)) -> Double -> String -> String -> IO ()+oberSoXSynthGen2FDN_Sf file m ku f y zs wws = do+  duration0 <- durationA file+  let n = truncate (duration0 / 0.001)+  vecA <- V.generateM n (\k -> do {+    (_, _, herr) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "-n", "trim", showFFloat (Just 4) (fromIntegral k * 0.001) $ show 0,+      "0.001", "stat"] ""+    ; let line0s = lines herr+          noteN0 = takeWhile isDigit . dropWhile (not . isDigit) . concat . drop 13 . take 14 $ line0s+    ; if null noteN0 then return (11440::Int)+      else let noteN1  = read (takeWhile isDigit . dropWhile (not . isDigit) . concat . drop 13 . take 14 $ line0s)::Int in return noteN1 })+  let vecB = liftInEnkuV m ku . V.map fromIntegral . V.filter (/= (11440::Int)) $ vecA+      (t, ws) = splitAt 1 . syllableStr n $ zs+      m0    = length ws+      zeroN = numVZeroesPre vecB+      v2    = V.map (\yy -> y * fromIntegral (yy * m0) / fromIntegral (head t)) . V.fromList $ ws in V.imapM_ (\j x -> do+        oberSoXSynth2FDN_Sf f (x, (V.unsafeIndex v2 (j `rem` (V.length v2)))) j wws+        renameFile "result.wav" $ "result0" ++ prependZeroes zeroN (show (j + 1)) ++ ".wav") vecB+  path2s <- listDirectory "."+  let paths3 = sort . filter (isPrefixOf "result") $ path2s+  (code,_,_) <- readProcessWithExitCode (fromJust (showE "sox")) (paths3 ++ ["end.wav"]) ""+  case code of+    ExitSuccess -> putStrLn "The final file \"end.wav\" was successfully created. You can now manually change or delete \"result*\" files in the directory. "+    _           -> do+      exi <- doesFileExist "end.wav"+      if exi then removeFile "end.wav"+      else putStr "Your final file \"end.wav\" was not created by some reason, but the intermediate files in the respective order are present. " >>+        putStrLn "Use them manually as needed."    + -- | Similar to 'oberSoXSynth2FDN_S' but additionally the program filters out from the resulting 'V.Vector' after \"f\" application values that are smaller--- than the third 'Double' parameter by an absolute value in the triple of @Double@'s. +-- than the third 'Double' parameter by an absolute value in the triple of @Double@'s. An 'Int' parameter is used to define an interval. To obtain compatible+-- with versions prior to 0.20.0.0 behaviour, use for the 'Int' 0. -- -- Be aware that the result can be rather unpredictable (the program can even obtain segmentation fault) for not very suitable function. -- But for a lot of functions this works well. --  -- It is recommended to fully simplify the computation for \"f\" function before using it in the 'oberSoXSynth2FDN_Sf3'.-oberSoXSynth2FDN_Sf3 :: (Double -> V.Vector (Double, Double)) -> (Double, Double, Double) -> String -> IO ()-oberSoXSynth2FDN_Sf3 f (x, y, t0) zs+oberSoXSynth2FDN_Sf3 :: (Double -> V.Vector (Double, Double)) -> (Double, Double, Double) -> Int -> String -> IO ()+oberSoXSynth2FDN_Sf3 f (x, y, t0) j zs  | V.null . convertToProperUkrainian $ zs = oberSoXSynth x  | otherwise = do     let note0 = closestNote (if x /= 0.0 then abs x else V.unsafeIndex notes 0)-        note1 = dNote (V.unsafeIndex (intervalsFromString zs) 0) note0+        l0    = length zs+        note1 = dNote (V.unsafeIndex (intervalsFromString zs) (abs (j `rem` l0))) note0         v0    = V.filter (\(_,!z) -> compare (abs z) t0 == GT) . f $ note0         v1    = if isNothing note1 then V.empty                 else V.filter (\(_,!z) -> compare (abs z) t0 == GT) . f . fromJust $ note1@@ -316,3 +461,33 @@     let paths = sort . filter (isPrefixOf "test") $ paths0     _ <- readProcessWithExitCode (fromJust (showE "sox")) (["--combine", "mix"] ++ paths ++ ["result.wav","vol","0.3"]) ""     mapM_ removeFile paths++-- | Similar to 'oberSoXSynthGen2FDN_S', but instead of 'oberSoXSynth2FDN_S' uses 'oberSoXSynth2FDN_Sf3' function. +oberSoXSynthGen2FDN_Sf3 :: FilePath -> Int -> Int -> (Double -> V.Vector (Double, Double)) -> Double -> Double -> String -> String -> IO ()+oberSoXSynthGen2FDN_Sf3 file m ku f y t0 zs wws = do+  duration0 <- durationA file+  let n = truncate (duration0 / 0.001)+  vecA <- V.generateM n (\k -> do {+    (_, _, herr) <- readProcessWithExitCode (fromJust (showE "sox")) [file, "-n", "trim", showFFloat (Just 4) (fromIntegral k * 0.001) $ show 0,+      "0.001", "stat"] ""+    ; let line0s = lines herr+          noteN0 = takeWhile isDigit . dropWhile (not . isDigit) . concat . drop 13 . take 14 $ line0s+    ; if null noteN0 then return (11440::Int)+      else let noteN1  = read (takeWhile isDigit . dropWhile (not . isDigit) . concat . drop 13 . take 14 $ line0s)::Int in return noteN1 })+  let vecB = liftInEnkuV m ku . V.map fromIntegral . V.filter (/= (11440::Int)) $ vecA+      (t, ws) = splitAt 1 . syllableStr n $ zs+      m0    = length ws+      zeroN = numVZeroesPre vecB+      v2    = V.map (\yy -> y * fromIntegral (yy * m0) / fromIntegral (head t)) . V.fromList $ ws in V.imapM_ (\j x -> do+        oberSoXSynth2FDN_Sf3 f (x, (V.unsafeIndex v2 (j `rem` (V.length v2))), t0) j wws+        renameFile "result.wav" $ "result0" ++ prependZeroes zeroN (show (j + 1)) ++ ".wav") vecB+  path2s <- listDirectory "."+  let paths3 = sort . filter (isPrefixOf "result") $ path2s+  (code,_,_) <- readProcessWithExitCode (fromJust (showE "sox")) (paths3 ++ ["end.wav"]) ""+  case code of+    ExitSuccess -> putStrLn "The final file \"end.wav\" was successfully created. You can now manually change or delete \"result*\" files in the directory. "+    _           -> do+      exi <- doesFileExist "end.wav"+      if exi then removeFile "end.wav"+      else putStr "Your final file \"end.wav\" was not created by some reason, but the intermediate files in the respective order are present. " >>+        putStrLn "Use them manually as needed."    
DobutokO/Sound/ParseList.hs view
@@ -29,6 +29,8 @@ containsExtV :: V.Vector String -> Bool containsExtV = V.elem ".." +-- | Predicate to check whether a 'V.Vector' does not contain round parentheses or dash (a minus sign) as its elements. Is used internally in the+-- 'parseStoLInts' function to avoid lists with negative elements. canBePreParseV :: V.Vector String -> Bool canBePreParseV v = not (V.elem "(" v || V.elem "-" v || V.elem ")" v) @@ -78,6 +80,49 @@          then Nothing          else Just (V.toList . V.mapMaybe id $ insV1)  | otherwise = Nothing++-- | From the 0.19.0.0 version. Can be used to parse also into infinite lists. +parseVInf :: V.Vector String -> Maybe [Int]+parseVInf v+ | V.findIndices (== "..") v == V.singleton 2 && V.length v == 4 =+    if V.unsafeIndex v 0 == "[" && V.unsafeIndex v 3 == "]"+      then let ins1 = readMaybe (V.unsafeIndex v 1)::Maybe Int in+        case ins1 of+          Just ins -> Just [ins..]+          Nothing  -> Nothing+      else Nothing+ | V.findIndices (== "..") v == V.singleton 2 && V.length v == 5 =+    if V.unsafeIndex v 0 == "[" && V.unsafeIndex v 4 == "]"+      then let ins1 = readMaybe (V.unsafeIndex v 1)::Maybe Int+               ins2 = readMaybe (V.unsafeIndex v 3)::Maybe Int in+        case (ins1,ins2) of+          (Just ins01,Just ins02) -> if ins02 >= ins01 then Just [ins01..ins02] else Nothing+          _                       -> Nothing+      else Nothing+ | V.findIndices (== "..") v == V.singleton 4 && V.length v == 6 =+    if V.unsafeIndex v 0 == "[" && V.unsafeIndex v 2 == "," && V.unsafeIndex v 5 == "]"+      then let ins1 = readMaybe (V.unsafeIndex v 1)::Maybe Int+               ins2 = readMaybe (V.unsafeIndex v 3)::Maybe Int in+        case (ins1,ins2) of+          (Just ins01,Just ins02) -> Just [ins01,ins02..]+          _                       -> Nothing+      else Nothing+ | V.findIndices (== "..") v == V.singleton 4 && V.length v == 7 =+    if V.unsafeIndex v 0 == "[" && V.unsafeIndex v 2 == "," && V.unsafeIndex v 6 == "]"+      then let ins1 = readMaybe (V.unsafeIndex v 1)::Maybe Int+               ins2 = readMaybe (V.unsafeIndex v 3)::Maybe Int+               ins3 = readMaybe (V.unsafeIndex v 5)::Maybe Int in+        case (ins1,ins2,ins3) of+          (Just ins01,Just ins02,Just ins03) -> if null [ins01,ins02..ins03] then Nothing else Just [ins01,ins02..ins03]+          _                       -> Nothing+      else Nothing+ | V.unsafeIndex v 0 == "[" && V.unsafeIndex v (V.length v - 1) == "]" && V.length v `rem` 2 == 1 &&+    (V.toList . V.findIndices (== ",") $ v) == [2,4..(V.length v - 2)] =+      let insV1 = V.imap (\i _ -> readMaybe (V.unsafeIndex v (2 * i + 1))::Maybe Int) (V.unsafeSlice 0 (V.length v `quot` 2) v) in+       if V.any isNothing insV1+         then Nothing+         else Just (V.toList . V.mapMaybe id $ insV1)+ | otherwise = Nothing   -- | Parses a 'String' being a list of Ints written with Haskell rules, e. g. \"[1..]\", \"[2,4..45]\", \"[3,5,6,7,8,3]\" etc. into a list of 'Int'. -- If it is not possible or list is empty, returns []. Preceding whitespaces are ignored. An 'Int' argument is used as a delimiter to avoid infinite lists.
dobutokO2.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/  name:                dobutokO2-version:             0.19.1.0+version:             0.20.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. Uses SoX inside. homepage:            https://hackage.haskell.org/package/dobutokO2