├── src
├── config.nims
├── paramidib.nim
└── paramidib
│ └── common.nim
├── .gitattributes
├── .gitignore
├── nim.cfg
├── output.wav
├── dueling_banjos.wav
├── README.md
├── paramidib.nimble
├── LICENSE
├── index.nim
└── index.html
/src/config.nims:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.html linguist-vendored
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | nimcache/
2 | nimblecache/
3 | htmldocs/
4 |
--------------------------------------------------------------------------------
/nim.cfg:
--------------------------------------------------------------------------------
1 | --path:"./src"
2 | -d:nimibPreviewCodeAsInSource
--------------------------------------------------------------------------------
/output.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pietroppeter/paramidib/main/output.wav
--------------------------------------------------------------------------------
/dueling_banjos.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pietroppeter/paramidib/main/dueling_banjos.wav
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🎶🐳 paramidib
2 | [paramidi] with [nimib], see [pietroppeter.github.io/paramidib/](https://pietroppeter.github.io/paramidib/). Install with `nimble install paramidib`.
3 |
4 | [paramidi]: https://github.com/paranim/paramidi
5 | [nimib]: https://github.com/pietroppeter/nimib
6 |
--------------------------------------------------------------------------------
/paramidib.nimble:
--------------------------------------------------------------------------------
1 | # Package
2 |
3 | version = "0.1.0"
4 | author = "Pietro Peterlongo"
5 | description = "paramidi with nimib"
6 | license = "MIT"
7 | srcDir = "src"
8 |
9 |
10 | # Dependencies
11 |
12 | requires "nim >= 1.6.0"
13 | requires "paramidi >= 0.6.0"
14 | requires "paramidi_soundfonts >= 0.2.0"
15 | requires "parasound >= 0.2.0"
--------------------------------------------------------------------------------
/src/paramidib.nim:
--------------------------------------------------------------------------------
1 | # adapted from https://github.com/paranim/paramidi_starter/blob/master/src/paramidi_starter.nim
2 | from paramidib / common import nil
3 | import paramidi
4 | import paramidi/tsf
5 | import paramidi_soundfonts
6 | import os
7 |
8 | export paramidi
9 |
10 | template saveMusic*(wavFile: string, score: untyped) =
11 | let scoreObject = score
12 | # get the sound font, read it from disc
13 | var sf = tsf_load_filename(cstring paramidi_soundfonts.getSoundFontPath("generaluser.sf2"))
14 | const sampleRate = 44100
15 | tsf_set_output(sf, TSF_MONO, sampleRate, 0)
16 | var res = render[cshort](compile(scoreObject), sf, sampleRate)
17 | tsf_close(sf)
18 | # create the wav file (without playing it)
19 | common.writeFile(wavFile, res.data, res.data.len.uint32, sampleRate)
20 |
21 | template nbAudio*(wavFile: string) =
22 | # todo: validate/escape wavFile
23 | nbText: """
24 |
25 | Your browser does not support the audio element.
26 |
27 | """
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Pietro Peterlongo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/paramidib/common.nim:
--------------------------------------------------------------------------------
1 | # taken as is from https://github.com/paranim/paramidi_starter/blob/master/src/common.nim
2 | import parasound/dr_wav
3 | import parasound/miniaudio
4 | import os
5 |
6 | proc play*(data: string | seq[uint8], sleepMsecs: int): bool =
7 | ## if `data` is a string, it is interpreted as a filename.
8 | ## if `data` is a byte sequence, it is interpreted as an in-memory buffer.
9 | var engine = newSeq[uint8](ma_engine_size())
10 | if MA_SUCCESS != ma_engine_init(nil, engine[0].addr):
11 | return false
12 | when data is string:
13 | if MA_SUCCESS != ma_engine_play_sound(engine[0].addr, data, nil):
14 | ma_engine_uninit(engine[0].addr)
15 | return false
16 | os.sleep(sleepMsecs)
17 | ma_engine_uninit(engine[0].addr)
18 | elif data is seq[uint8]:
19 | var decoder = newSeq[uint8](ma_decoder_size())
20 | if MA_SUCCESS != ma_decoder_init_memory(data[0].unsafeAddr, data.len.csize_t, nil, decoder[0].addr):
21 | ma_engine_uninit(engine[0].addr)
22 | return false
23 | var sound = newSeq[uint8](ma_sound_size())
24 | if MA_SUCCESS != ma_sound_init_from_data_source(engine[0].addr, decoder[0].addr, 0, nil, sound[0].addr):
25 | discard ma_decoder_uninit(decoder[0].addr)
26 | ma_engine_uninit(engine[0].addr)
27 | return false
28 | if MA_SUCCESS != ma_sound_start(sound[0].addr):
29 | ma_sound_uninit(sound[0].addr)
30 | discard ma_decoder_uninit(decoder[0].addr)
31 | ma_engine_uninit(engine[0].addr)
32 | return false
33 | os.sleep(sleepMsecs)
34 | ma_sound_uninit(sound[0].addr)
35 | discard ma_decoder_uninit(decoder[0].addr)
36 | ma_engine_uninit(engine[0].addr)
37 | true
38 |
39 | proc writeFile*(filename: string, data: var openArray[cshort], numSamples: uint32, sampleRate: uint32) =
40 | var
41 | wav = newSeq[uint8](drwav_size())
42 | format: drwav_data_format
43 | format.container = drwav_container_riff
44 | format.format = DR_WAVE_FORMAT_PCM
45 | format.channels = 1
46 | format.sampleRate = sampleRate
47 | format.bitsPerSample = 16
48 | doAssert drwav_init_file_write(wav[0].addr, filename, addr(format), nil)
49 | doAssert numSamples == drwav_write_pcm_frames(wav[0].addr, numSamples, data.addr)
50 | discard drwav_uninit(wav[0].addr)
51 |
52 | proc writeMemory*(data: var openArray[cshort], numSamples: uint32, sampleRate: uint32): seq[uint8] =
53 | var
54 | wav = newSeq[uint8](drwav_size())
55 | format: drwav_data_format
56 | format.container = drwav_container_riff
57 | format.format = DR_WAVE_FORMAT_PCM
58 | format.channels = 1
59 | format.sampleRate = sampleRate
60 | format.bitsPerSample = 16
61 | var
62 | outputRaw: pointer
63 | outputSize: csize_t
64 | doAssert drwav_init_memory_write_sequential(wav[0].addr, outputRaw.addr, outputSize.addr, format.addr, numSamples, nil)
65 | doAssert numSamples == drwav_write_pcm_frames(wav[0].addr, numSamples, data[0].addr)
66 | doAssert outputSize > 0
67 | result = newSeq[uint8](outputSize)
68 | copyMem(result[0].addr, outputRaw, outputSize)
69 | drwav_free(outputRaw, nil)
70 | discard drwav_uninit(wav[0].addr)
71 |
--------------------------------------------------------------------------------
/index.nim:
--------------------------------------------------------------------------------
1 | import nimib
2 |
3 | nbInit
4 | nbText: """# 🎶🐳 paramidib
5 |
6 | paramidi**b** is an easy way to make [paramidi] available with [nimib].
7 | Install with `nimble install paramidib`.
8 |
9 | It exports `paramidi` and provides two templates:
10 | 1. `saveMusic`: takes a valid score for paramidi and creates
11 | a `wav` file with the generated music.
12 | It is adapted from [paramidi_starter] and it can be used even
13 | without nimib (paramidib itself does not depend on nimib).
14 | 2. `nbAudio`: a new nimib block which create an audio control
15 | to play the `wav` file.
16 | In the following example is called with `nbAudio("output.wav")`
17 |
18 | [paramidi]: https://github.com/paranim/paramidi
19 | [nimib]: https://github.com/pietroppeter/nimib
20 | [paramidi_starter]: https://github.com/paranim/paramidi_starter
21 |
22 | """
23 | nbCode:
24 | import paramidib
25 |
26 | saveMusic("output.wav"):
27 | (piano,
28 | (tempo: 74),
29 | 1/8, {-d, -a, e, fx}, a,
30 | 1/2, {fx, +d},
31 | 1/8, {-e, e, +c}, a,
32 | 1/2, {c, e},
33 | 1/8, {-d, -a, e, fx}, a, +d, +cx, +e, +d, b, +cx,
34 | 1/2, {-e, c, a}, {c, e})
35 | nbAudio("output.wav")
36 | nbText: "Another example where the score is a json object generated at runtime:"
37 | nbCode:
38 | import json
39 |
40 | let
41 | measure1 = %*[1/16, "b", "c+", 1/8, "d+", "b", "c+", "a", "b", "g", "a"]
42 | measure2 = %*[1/16, "g", "g", 1/8, "g", "a", "b", "c+", "d+", "c+", 1/2, "b"]
43 | measure3 = %*[1/16, [{"mode": "concurrent"}, "d", "b-", "g-"], [{"mode": "concurrent"}, "d", "b-", "g-"],
44 | 1/8, [{"mode": "concurrent"}, "d", "b-", "g-"], [{"mode": "concurrent"}, "e", "c", "g-"],
45 | [{"mode": "concurrent"}, "d", "b-", "g-"]]
46 | measure4 = %*[1/16, "r", "r", 1/8, "g", "r", "d", "r", "g", "g", "d"]
47 | measure5 = %*[1/4, "g", 1/8, "a", "b", 1/4, "g", 1/8, "a", "d"]
48 | measure6 = %*[1/4, "g", 1/8, "a", "b", 1/4, "g", 1/8, [{"mode": "concurrent"}, "f", "a-"], "b", 1/4, "c"]
49 |
50 | score* =
51 | %*[{"tempo": 80, "octave": 3},
52 | ["guitar", measure1],
53 | ["banjo", measure1],
54 | ["guitar", measure1],
55 | ["guitar", 1/2, "d", 1/8, "g", "g", "a", "b", "g", "b", 1/2, "a"],
56 | ["banjo", 1/8, "g", "g", "a", "b", 1/2, "g"],
57 | ["guitar", {"octave": 2}, measure2],
58 | ["banjo", measure2],
59 | ["guitar", {"octave": 2}, measure2],
60 | ["banjo", measure2],
61 | ["guitar", measure2],
62 | ["banjo", measure2],
63 | {"octave": 4},
64 | ["guitar", measure3],
65 | ["banjo", measure3],
66 | ["guitar", measure3],
67 | ["banjo", measure3],
68 | ["guitar", {"octave": 2}, measure1],
69 | ["banjo", {"octave": 3}, measure1],
70 | {"tempo": 120, "octave": 3},
71 | [{"mode": "concurrent"},
72 | ["banjo", measure1],
73 | ["guitar", measure4]],
74 | [{"mode": "concurrent"},
75 | ["banjo", measure1],
76 | ["guitar", measure4]],
77 | [{"mode": "concurrent"},
78 | ["banjo", measure1],
79 | ["guitar", measure5]],
80 | [{"mode": "concurrent"},
81 | ["banjo", measure1],
82 | ["guitar", measure6]]]
83 |
84 | saveMusic("dueling_banjos.wav", score)
85 | nbAudio("dueling_banjos.wav")
86 | nbText: "Originally created for Advent Of Nim 🎄👑, 2021, Day 3, [Whale Music](https://pietroppeter.github.io/adventofnim/2021/day03.html#whale_music) 🐳🎶."
87 | nbSave
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | index.nim
5 |
6 |
7 |
8 |
9 |
10 |
11 |
30 |
31 |
32 |
33 |
34 |
35 |
🏡
36 |
index.nim
37 |
38 |
39 |
40 |
41 | 🎶🐳 paramidib
42 | paramidib is an easy way to make paramidi available with nimib .
43 | Install with nimble install paramidib.
44 | It exports paramidi and provides two templates:
45 |
46 | saveMusic: takes a valid score for paramidi and creates
47 | a wav file with the generated music.
48 | It is adapted from paramidi_starter and it can be used even
49 | without nimib (paramidib itself does not depend on nimib).
50 | nbAudio: a new nimib block which create an audio control
51 | to play the wav file.
52 | In the following example is called with nbAudio("output.wav")
53 |
54 | import paramidib
55 |
56 | saveMusic("output.wav" ):
57 | (piano,
58 | (tempo: 74 ),
59 | 1 /8 , {-d, -a, e, fx}, a,
60 | 1 /2 , {fx, +d},
61 | 1 /8 , {-e, e, +c}, a,
62 | 1 /2 , {c, e},
63 | 1 /8 , {-d, -a, e, fx}, a, +d, +cx, +e, +d, b, +cx,
64 | 1 /2 , {-e, c, a}, {c, e})
65 |
66 |
67 | Your browser does not support the audio element.
68 |
69 | Another example where the score is a json object generated at runtime:
70 | import json
71 |
72 | let
73 | measure1 = %*[1 /16 , "b" , "c+" , 1 /8 , "d+" , "b" , "c+" , "a" , "b" , "g" , "a" ]
74 | measure2 = %*[1 /16 , "g" , "g" , 1 /8 , "g" , "a" , "b" , "c+" , "d+" , "c+" , 1 /2 , "b" ]
75 | measure3 = %*[1 /16 , [{"mode" : "concurrent" }, "d" , "b-" , "g-" ], [{"mode" : "concurrent" }, "d" , "b-" , "g-" ],
76 | 1 /8 , [{"mode" : "concurrent" }, "d" , "b-" , "g-" ], [{"mode" : "concurrent" }, "e" , "c" , "g-" ],
77 | [{"mode" : "concurrent" }, "d" , "b-" , "g-" ]]
78 | measure4 = %*[1 /16 , "r" , "r" , 1 /8 , "g" , "r" , "d" , "r" , "g" , "g" , "d" ]
79 | measure5 = %*[1 /4 , "g" , 1 /8 , "a" , "b" , 1 /4 , "g" , 1 /8 , "a" , "d" ]
80 | measure6 = %*[1 /4 , "g" , 1 /8 , "a" , "b" , 1 /4 , "g" , 1 /8 , [{"mode" : "concurrent" }, "f" , "a-" ], "b" , 1 /4 , "c" ]
81 |
82 | score* =
83 | %*[{"tempo" : 80 , "octave" : 3 },
84 | ["guitar" , measure1],
85 | ["banjo" , measure1],
86 | ["guitar" , measure1],
87 | ["guitar" , 1 /2 , "d" , 1 /8 , "g" , "g" , "a" , "b" , "g" , "b" , 1 /2 , "a" ],
88 | ["banjo" , 1 /8 , "g" , "g" , "a" , "b" , 1 /2 , "g" ],
89 | ["guitar" , {"octave" : 2 }, measure2],
90 | ["banjo" , measure2],
91 | ["guitar" , {"octave" : 2 }, measure2],
92 | ["banjo" , measure2],
93 | ["guitar" , measure2],
94 | ["banjo" , measure2],
95 | {"octave" : 4 },
96 | ["guitar" , measure3],
97 | ["banjo" , measure3],
98 | ["guitar" , measure3],
99 | ["banjo" , measure3],
100 | ["guitar" , {"octave" : 2 }, measure1],
101 | ["banjo" , {"octave" : 3 }, measure1],
102 | {"tempo" : 120 , "octave" : 3 },
103 | [{"mode" : "concurrent" },
104 | ["banjo" , measure1],
105 | ["guitar" , measure4]],
106 | [{"mode" : "concurrent" },
107 | ["banjo" , measure1],
108 | ["guitar" , measure4]],
109 | [{"mode" : "concurrent" },
110 | ["banjo" , measure1],
111 | ["guitar" , measure5]],
112 | [{"mode" : "concurrent" },
113 | ["banjo" , measure1],
114 | ["guitar" , measure6]]]
115 |
116 | saveMusic("dueling_banjos.wav" , score)
117 |
118 |
119 | Your browser does not support the audio element.
120 |
121 | Originally created for Advent Of Nim 🎄👑, 2021, Day 3, Whale Music 🐳🎶.
122 |
123 |
124 |
125 |
126 |
127 |
made with nimib 🐳
128 |
129 |
Show Source
130 |
131 |
132 |
133 | import nimib
134 |
135 | nbInit
136 | nbText: """# 🎶🐳 paramidib
137 |
138 | paramidi**b** is an easy way to make [paramidi] available with [nimib].
139 | Install with `nimble install paramidib`.
140 |
141 | It exports `paramidi` and provides two templates:
142 | 1. `saveMusic`: takes a valid score for paramidi and creates
143 | a `wav` file with the generated music.
144 | It is adapted from [paramidi_starter] and it can be used even
145 | without nimib (paramidib itself does not depend on nimib).
146 | 2. `nbAudio`: a new nimib block which create an audio control
147 | to play the `wav` file.
148 | In the following example is called with `nbAudio("output.wav")`
149 |
150 | [paramidi]: https://github.com/paranim/paramidi
151 | [nimib]: https://github.com/pietroppeter/nimib
152 | [paramidi_starter]: https://github.com/paranim/paramidi_starter
153 |
154 | """
155 | nbCode:
156 | import paramidib
157 |
158 | saveMusic("output.wav" ):
159 | (piano,
160 | (tempo: 74 ),
161 | 1 /8 , {-d, -a, e, fx}, a,
162 | 1 /2 , {fx, +d},
163 | 1 /8 , {-e, e, +c}, a,
164 | 1 /2 , {c, e},
165 | 1 /8 , {-d, -a, e, fx}, a, +d, +cx, +e, +d, b, +cx,
166 | 1 /2 , {-e, c, a}, {c, e})
167 | nbAudio("output.wav" )
168 | nbText: "Another example where the score is a json object generated at runtime:"
169 | nbCode:
170 | import json
171 |
172 | let
173 | measure1 = %*[1 /16 , "b" , "c+" , 1 /8 , "d+" , "b" , "c+" , "a" , "b" , "g" , "a" ]
174 | measure2 = %*[1 /16 , "g" , "g" , 1 /8 , "g" , "a" , "b" , "c+" , "d+" , "c+" , 1 /2 , "b" ]
175 | measure3 = %*[1 /16 , [{"mode" : "concurrent" }, "d" , "b-" , "g-" ], [{"mode" : "concurrent" }, "d" , "b-" , "g-" ],
176 | 1 /8 , [{"mode" : "concurrent" }, "d" , "b-" , "g-" ], [{"mode" : "concurrent" }, "e" , "c" , "g-" ],
177 | [{"mode" : "concurrent" }, "d" , "b-" , "g-" ]]
178 | measure4 = %*[1 /16 , "r" , "r" , 1 /8 , "g" , "r" , "d" , "r" , "g" , "g" , "d" ]
179 | measure5 = %*[1 /4 , "g" , 1 /8 , "a" , "b" , 1 /4 , "g" , 1 /8 , "a" , "d" ]
180 | measure6 = %*[1 /4 , "g" , 1 /8 , "a" , "b" , 1 /4 , "g" , 1 /8 , [{"mode" : "concurrent" }, "f" , "a-" ], "b" , 1 /4 , "c" ]
181 |
182 | score* =
183 | %*[{"tempo" : 80 , "octave" : 3 },
184 | ["guitar" , measure1],
185 | ["banjo" , measure1],
186 | ["guitar" , measure1],
187 | ["guitar" , 1 /2 , "d" , 1 /8 , "g" , "g" , "a" , "b" , "g" , "b" , 1 /2 , "a" ],
188 | ["banjo" , 1 /8 , "g" , "g" , "a" , "b" , 1 /2 , "g" ],
189 | ["guitar" , {"octave" : 2 }, measure2],
190 | ["banjo" , measure2],
191 | ["guitar" , {"octave" : 2 }, measure2],
192 | ["banjo" , measure2],
193 | ["guitar" , measure2],
194 | ["banjo" , measure2],
195 | {"octave" : 4 },
196 | ["guitar" , measure3],
197 | ["banjo" , measure3],
198 | ["guitar" , measure3],
199 | ["banjo" , measure3],
200 | ["guitar" , {"octave" : 2 }, measure1],
201 | ["banjo" , {"octave" : 3 }, measure1],
202 | {"tempo" : 120 , "octave" : 3 },
203 | [{"mode" : "concurrent" },
204 | ["banjo" , measure1],
205 | ["guitar" , measure4]],
206 | [{"mode" : "concurrent" },
207 | ["banjo" , measure1],
208 | ["guitar" , measure4]],
209 | [{"mode" : "concurrent" },
210 | ["banjo" , measure1],
211 | ["guitar" , measure5]],
212 | [{"mode" : "concurrent" },
213 | ["banjo" , measure1],
214 | ["guitar" , measure6]]]
215 |
216 | saveMusic("dueling_banjos.wav" , score)
217 | nbAudio("dueling_banjos.wav" )
218 | nbText: "Originally created for Advent Of Nim 🎄👑, 2021, Day 3, [Whale Music](https://pietroppeter.github.io/adventofnim/2021/day03.html#whale_music) 🐳🎶."
219 | nbSave
220 |
233 |
--------------------------------------------------------------------------------