New major features
Support for other synth types Added a universal silence function (necessary for "pluck" type) Did away with the unnecessary soxpipes variable Support two-note harmonies (see pokemon-gsc-mainmenu for example) Support flat notes Auto-reset the notes array after calling createSoxPipes To distinguish between nonlooped and looped melodies, you now have to call an empty echo. Better solution than putting a newline at the start of the output. See sleeping-terror.sh for example.
This commit is contained in:
parent
077e12670e
commit
67ff915bf1
36
README
36
README
|
@ -4,6 +4,30 @@ libsox.sh
|
|||
A library for GNU bash making it easier to create music with the power of SoX
|
||||
synths.
|
||||
|
||||
If you're one of these people:
|
||||
|
||||
- a Bash programmer
|
||||
- suck at reading sheet music
|
||||
- finds MML too difficult
|
||||
- too lazy to learn FamiTracker
|
||||
- think that scientific note duration is the best thing since sliced bread
|
||||
|
||||
Then try this crappy library of mine!
|
||||
|
||||
Some features of this library:
|
||||
|
||||
- Easy to write syntax for inputting notes ("$duration:${key[pitch]}")
|
||||
- Inspired from korobeiniki.sh of the dsuni/bashtris repository
|
||||
- Supports two-note harmonies ("$duration:${key1[pitch1]},${key2[pitch2]}")
|
||||
- Supports every synth type included in SoX
|
||||
- Adheres to the Unix philosophy of "do one thing and do it well"
|
||||
|
||||
What this library doesn't support:
|
||||
|
||||
- Using your own samples (just use FamiTracker or a DAW for that)
|
||||
- Harmonies with more than two notes
|
||||
- POSIX compatibility
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
|
@ -63,7 +87,8 @@ notes=(
|
|||
|
||||
"$si:${c[5]}" # A sixteenth C note in the 5th octave
|
||||
"$ei:${gs[4]}" # An eighth G sharp in 4th octave
|
||||
"$qu:${fs[4]}"
|
||||
"$qu:${gf[4]}" # A quarter G flat in 4th octave
|
||||
"$qu:${gb[4]}" # Also a G flat
|
||||
)
|
||||
|
||||
function repeatingNotes { # Use bash functions to repeat parts of your music
|
||||
|
@ -87,16 +112,17 @@ notes+=(
|
|||
"$dei:${b[2]}" # Dotted notes are supported
|
||||
"$tqu:${a[3]}" # Triplets are supported
|
||||
"0.02:${gs[4]}" # You can do custom durations
|
||||
"0.05:489 # Custom frequencies too, though I'm not sure why you'd do that
|
||||
"0.05:489 # Custom frequencies too
|
||||
)
|
||||
|
||||
createSoxPipes # Useful for dividing the part that loops and the part that doesn't
|
||||
createSoxPipes # Will reset the notes array too
|
||||
echo # Useful for distinguishing the part that loops and the part that doesn't
|
||||
|
||||
# Loop start
|
||||
setTempo 160 # Change the BPM if needed
|
||||
|
||||
notes=( # Don't forget to reset the notes array. Don't append.
|
||||
"$dei:${fs[5]}"
|
||||
notes+=(
|
||||
"$dei:${fs[5]},${gs[5]}" # You can do two-note harmonies
|
||||
"$dei:${c[6]}"
|
||||
"$ei:${as[5]}"
|
||||
"$ha:${as[5]}"
|
||||
|
|
|
@ -41,6 +41,8 @@ Arranged by Job Bautista
|
|||
|
||||
setTempo 150
|
||||
|
||||
setDefaultSynthType sin
|
||||
|
||||
# intro
|
||||
function intro-ccg {
|
||||
notes+=(
|
||||
|
@ -79,9 +81,8 @@ notes+=(
|
|||
"$qu:${g[4]}"
|
||||
)
|
||||
|
||||
createSoxPipes # loop no $1
|
||||
|
||||
notes=()
|
||||
createSoxPipes
|
||||
echo
|
||||
|
||||
# verse 1
|
||||
function verse1-common {
|
||||
|
@ -250,4 +251,4 @@ notes+=(
|
|||
"$qu:${g[4]}"
|
||||
)
|
||||
|
||||
createSoxPipes # loop yes $1
|
||||
createSoxPipes
|
||||
|
|
45
libsox.sh
45
libsox.sh
|
@ -37,7 +37,15 @@ a=(27 55 110 220 440 880 1760 3520 7040)
|
|||
as=(29 58 116 233 466 932 1864 3729 7458)
|
||||
b=(30 61 123 246 493 987 1975 3951 7902)
|
||||
|
||||
declare -rg c cs d ds e f g gs a as b
|
||||
# flats as references to their respective sharps
|
||||
declare -n df db ef eb gf gb af ab bf bb
|
||||
df="cs" db="cs"
|
||||
ef="ds" eb="ds"
|
||||
gf="fs" gb="fs"
|
||||
af="gs" ab="gs"
|
||||
bf="as" bb="as"
|
||||
|
||||
declare -rg c cs d ds e f g gs a as b df db ef eb gf gb af ab bf bb
|
||||
|
||||
function setTempo {
|
||||
declare -g BPM=$1
|
||||
|
@ -57,17 +65,34 @@ function setTempo {
|
|||
declare -g tsi=$(echo "scale=3; 10 / $BPM" | bc -l) # Triplet-sixteenth note
|
||||
}
|
||||
|
||||
declare -a notes # In the following format - "$duration:${key}[pitch]"
|
||||
declare -ag notes # In the following format - "$duration:${key[pitch]}"
|
||||
# For a harmony - "$duration:${key1[pitch1]},${key2[pitch2]}"
|
||||
|
||||
declare -g defaultsynth="sin" # for backwards compatibility with previous
|
||||
synthtype="$defaultsynth" # child scripts that only used sine
|
||||
|
||||
function setDefaultSynthType {
|
||||
defaultsynth=$1
|
||||
synthtype="$defaultsynth"
|
||||
}
|
||||
|
||||
function silence { # needed because pluck synth doesn't support zero frequency
|
||||
declare -n duration=$1 # we want $1 to be recognized as a variable name
|
||||
createSoxPipes # necessary because we will be changing synth type
|
||||
synthtype="sin" # sin, square, sawtooth, trapezium, and exp support freq=0
|
||||
notes+=( "$duration:0" )
|
||||
createSoxPipes # get the silence printed before we return to default synth
|
||||
synthtype="$defaultsynth"
|
||||
}
|
||||
|
||||
function createSoxPipes {
|
||||
declare soxpipes
|
||||
soxpipes=$(printf '\n"|sox -n -p synth '$(echo "${notes[0]}" |
|
||||
sed 's/:.*//')' sin '$(echo "${notes[0]}" | sed 's/.*://')'"\n')
|
||||
for note in "${notes[@]:1}"
|
||||
for note in "${notes[@]}"
|
||||
do
|
||||
soxpipes+=$(printf '%b' '\n"|sox -n -p synth '$(echo "$note" |
|
||||
sed 's/:.*//')' sin '$(echo "$note" | sed 's/.*://')'"')
|
||||
printf '"|sox -n -p synth '$(echo "$note" |
|
||||
sed 's/:.*//')' '$synthtype' '$(echo "$note" | sed 's/.*://' |
|
||||
sed 's/,.*//')' '$synthtype' '$(echo "$note" | sed 's/.*://' |
|
||||
sed 's/.*,//')'"\n'
|
||||
# The sed for commas is there to support two-note harmonies.
|
||||
done
|
||||
|
||||
echo "$soxpipes"
|
||||
notes=() # You usually want to reset the notes array after calling this
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
#!/bin/bash
|
||||
|
||||
: '
|
||||
Copyright (C) 2022 Job Bautista
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
'
|
||||
|
||||
source ../libsox.sh
|
||||
|
||||
setTempo 120
|
||||
|
||||
function part1 {
|
||||
notes+=(
|
||||
"$dei:${cs[4]},${fs[4]}"
|
||||
"$ei:0"
|
||||
"$si:0"
|
||||
"$si:${cs[4]},${fs[4]}"
|
||||
"$si:${cs[4]},${fs[4]}"
|
||||
"$ei:${cs[4]},${fs[4]}"
|
||||
"$ei:${cs[4]},${fs[4]}"
|
||||
"$ei:${cs[4]},${fs[4]}"
|
||||
"$ei:0"
|
||||
)
|
||||
}
|
||||
part1; part1;
|
||||
notes+=(
|
||||
"$ei:${ds[4]},${gs[4]}"
|
||||
"$qu:0"
|
||||
"$si:${ds[4]},${gs[4]}"
|
||||
"$si:${ds[4]},${gs[4]}"
|
||||
"$ei:${ds[4]},${gs[4]}"
|
||||
"$ei:${ds[4]},${gs[4]}"
|
||||
"$dei:${ds[4]},${gs[4]}"
|
||||
"$si:0"
|
||||
|
||||
"$dei:${e[4]},${e[5]}"
|
||||
"$ei:0"
|
||||
"$si:0"
|
||||
"$si:${e[4]},${e[5]}"
|
||||
"$si:${e[4]},${e[5]}"
|
||||
"$ei:${e[4]},${e[5]}"
|
||||
"$ei:${e[4]},${e[5]}"
|
||||
"$qu:${c[4]},${f[5]}"
|
||||
)
|
||||
|
||||
createSoxPipes 2
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
cat art.txt
|
||||
sleep 1
|
||||
play -M -V1 "|sox -n -p synth .75 sin 293" "|sox -n -p synth .75 sin 391"
|
||||
play -V1 "|sox -n -p synth .75 sin 293 sin 391"
|
||||
# d5 = 293Hz, g5 = 391Hz
|
||||
play -M -V1 left.wav right.wav repeat 6
|
||||
./combined.sh | xargs ../myplay-repeat.sh 6
|
||||
|
|
|
@ -35,6 +35,8 @@ Arranged by Job Bautista
|
|||
|
||||
'
|
||||
|
||||
setDefaultSynthType sin
|
||||
|
||||
# intro
|
||||
setTempo 102
|
||||
notes=(
|
||||
|
@ -99,15 +101,18 @@ notes=(
|
|||
"$si:${ds[4]}"
|
||||
"$si:${gs[4]}"
|
||||
"$si:${d[4]}"
|
||||
"$qu:${f[4]}" # 62nd item
|
||||
"$qu:${f[4]}"
|
||||
|
||||
"3.096:0" # 2 whole notes in 155 BPM
|
||||
)
|
||||
createSoxPipes # loop no $1
|
||||
createSoxPipes
|
||||
echo
|
||||
|
||||
# main loop
|
||||
setTempo 155
|
||||
|
||||
# fast bridge
|
||||
notes=(
|
||||
notes+=(
|
||||
"$si:${c[5]}"
|
||||
"$si:${gs[4]}"
|
||||
"$si:${fs[4]}"
|
||||
|
@ -689,5 +694,6 @@ function verse7 {
|
|||
)
|
||||
}
|
||||
verse7; verse7;
|
||||
notes+=( "$fu:0" )
|
||||
|
||||
createSoxPipes # loop yes $1
|
||||
createSoxPipes
|
||||
|
|
Reference in New Issue