├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── Setup.hs
├── Sound
└── Tidal
│ └── MIDI
│ ├── Ambika.hs
│ ├── Blofeld.hs
│ ├── CC.hs
│ ├── Context.hs
│ ├── Control.hs
│ ├── Device.hs
│ ├── GMPerc.hs
│ ├── KorgKP3.hs
│ ├── MBase01.hs
│ ├── MiniAtmegatron.hs
│ ├── Minilogue.hs
│ ├── Output.hs
│ ├── Prophet08.hs
│ ├── Rytm.hs
│ ├── Stream.hs
│ ├── Synth.hs
│ ├── Synthino.hs
│ ├── System1M.hs
│ ├── Tanzbar.hs
│ ├── Tetra.hs
│ ├── VolcaBass.hs
│ ├── VolcaBeats.hs
│ ├── VolcaFM.hs
│ ├── VolcaKeys.hs
│ └── VolcaKick.hs
├── doc
├── blofeld-params.md
├── synth-mapping.md
└── synths.md
└── tidal-midi.cabal
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | cabal-dev
3 | *.*~
4 | *.o
5 | *.hi
6 | *.chi
7 | *.chs.h
8 | .virtualenv
9 | .hsenv
10 | .cabal-sandbox/
11 | cabal.sandbox.config
12 | cabal.config
13 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # This file has been generated by `make_travis_yml_2.hs`
2 | # see https://github.com/hvr/multi-ghc-travis for more information
3 | language: c
4 | sudo: false
5 |
6 | cache:
7 | directories:
8 | - $HOME/.ghc
9 | - $HOME/.cabal
10 | - .cabal-sandbox
11 |
12 | before_cache:
13 | - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log
14 | - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.tar
15 |
16 | matrix:
17 | include:
18 | - env: CABALVER=1.18 GHCVER=7.6.3
19 | compiler: ": #GHC 7.6.3"
20 | addons: {apt: {packages: [cabal-install-1.18,ghc-7.6.3,libasound2-dev,libportmidi-dev], sources: [hvr-ghc]}}
21 | - env: CABALVER=1.18 GHCVER=7.8.4
22 | compiler: ": #GHC 7.8.4"
23 | addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.4,libasound2-dev,libportmidi-dev], sources: [hvr-ghc]}}
24 | - env: CABALVER=1.22 GHCVER=7.10.3
25 | compiler: ": #GHC 7.10.3"
26 | addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3,libasound2-dev,libportmidi-dev], sources: [hvr-ghc]}}
27 | - env: CABALVER=1.24 GHCVER=8.0.1
28 | compiler: ": #GHC 8.0.1"
29 | addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.1,libasound2-dev,libportmidi-dev], sources: [hvr-ghc]}}
30 |
31 | before_install:
32 | - unset CC
33 | - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH
34 |
35 | install:
36 | - cabal --version
37 | - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"
38 | - if [ -f $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz ];
39 | then
40 | zcat $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz >
41 | $HOME/.cabal/packages/hackage.haskell.org/00-index.tar;
42 | fi
43 | - travis_retry cabal update -v
44 | - sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config
45 | - cabal install --only-dependencies --enable-tests --enable-benchmarks --dry -v > installplan.txt
46 | - sed -i -e '1,/^Resolving /d' installplan.txt
47 | - cat installplan.txt
48 |
49 | # check whether current requested install-plan matches cached package-db snapshot
50 | - if diff -u installplan.txt $HOME/.cabsnap/installplan.txt;
51 | then
52 | echo "cabal build-cache HIT";
53 | rm -rfv .ghc;
54 | cp -a $HOME/.cabsnap/ghc $HOME/.ghc;
55 | cp -a $HOME/.cabsnap/lib $HOME/.cabsnap/share $HOME/.cabsnap/bin $HOME/.cabal/;
56 | else
57 | echo "cabal build-cache MISS";
58 | rm -rf $HOME/.cabsnap;
59 | mkdir -p $HOME/.ghc $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin;
60 | cabal install --only-dependencies --enable-tests --enable-benchmarks;
61 | fi
62 |
63 | # snapshot package-db on cache miss
64 | - if [ ! -d $HOME/.cabsnap ];
65 | then
66 | echo "snapshotting package-db to build-cache";
67 | mkdir $HOME/.cabsnap;
68 | cp -a $HOME/.ghc $HOME/.cabsnap/ghc;
69 | cp -a $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin installplan.txt $HOME/.cabsnap/;
70 | fi
71 |
72 | # Here starts the actual work to be performed for the package under test;
73 | # any command which exits with a non-zero exit code causes the build to fail.
74 | script:
75 | - if [ -f configure.ac ]; then autoreconf -i; fi
76 | - cabal configure --enable-tests --enable-benchmarks -v2 # -v2 provides useful information for debugging
77 | - cabal build # this builds all libraries and executables (including tests/benchmarks)
78 | - cabal test
79 | - cabal check
80 | - cabal sdist # tests that a source-distribution can be generated
81 |
82 | # Check that the resulting source distribution can be built & installed.
83 | # If there are no other `.tar.gz` files in `dist`, this can be even simpler:
84 | # `cabal install --force-reinstalls dist/*-*.tar.gz`
85 | - SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz &&
86 | (cd dist && cabal install --force-reinstalls "$SRC_TGZ")
87 |
88 | # EOF
89 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## 1.0
4 | - add support for `legato` parameter to automatically scale note durations
5 |
6 | ## 0.9
7 |
8 | - normalize Shape names as lowercased Controller Module name, e.g.
9 | if you `import Sound.Tidal.MIDI.VolcaKeys` use `midiStream "Device Name" 1 volcakeys`
10 | - default latency of `0.1` to work around late messages _most of the time_
11 | - drop default values in `ControlChange`, can be specified via Tidal `Param` helpers
12 | `pF`, `pS` and `pI`
13 | - default `n` to `128` to allow CC-only patterns, e.g. `m1 $ resonance "0.3 0.1 0.9"`
14 | - params that _leave_ patterns will be reset to their defaults
15 | - `unit "cycle"` calculates inter-onsets and tries to behave like SuperDirt
16 | - `Stream` is now just the Tidal communication layer and internal MIDI
17 | messaging/scheduling lives in `Output`
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 | {one line to give the program's name and a brief idea of what it does.}
635 | Copyright (C) {year} {name of author}
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | {project} Copyright (C) {year} {fullname}
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
676 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Not Maintained
3 |
4 | This package is not actively maintained. Please visit [https://tidalcycles.org/index.php/Community](https://tidalcycles.org/index.php/Community) if you are interested in becoming a maintainer.
5 |
6 | In the meantime, we recommend using SuperDirt MIDI. Please refer to [this SuperDirt MIDI guide](https://tidalcycles.org/index.php/MIDI) to start using it.
7 |
8 |
9 | # tidal-midi
10 |
11 | [](https://travis-ci.org/tidalcycles/tidal-midi)
12 |
13 | A [TidalCycles](http://tidalcycles.org) module for sending patterns over MIDI.
14 |
15 | __PortMIDI__ variant. Should work on OS X, Linux and Windows.
16 |
17 | This _still_ is __experimental__ software.
18 |
19 |
45 |
46 |
47 | # Installation
48 |
49 |
50 | ## Prerequisites
51 |
52 | Depending on your operating system, you will need to install some prerequisites
53 | first.
54 |
55 | ### All Systems
56 |
57 | `tidal-midi` requires the latest version of `tidal`. Run these two commands
58 | in your terminal to install the latest version:
59 |
60 | ```shell
61 | cabal update
62 | cabal install tidal
63 | ```
64 |
65 | ### Linux
66 |
67 | Run the following to install `libasound2-dev` and `libportmidi-dev`:
68 |
69 | ```shell
70 | apt-get install libasound2-dev and libportmidi-dev
71 | ```
72 |
73 | ### Mac OS X
74 |
75 | Install PortMIDI:
76 |
77 | ```shell
78 | brew install portmidi
79 | ```
80 |
81 |
82 | ## Install tidal-midi
83 |
84 | Simply do:
85 |
86 | ```shell
87 | cabal update
88 | cabal install tidal-midi
89 | ```
90 |
91 | __Note:__ On OS X with GHC 7.10 it is necessary to reinstall PortMidi again with
92 | frameworks correctly linked:
93 |
94 | ```shell
95 | cabal install portmidi --ghc-options="-optl-Wl,-framework,CoreMIDI,-framework,CoreAudio" --reinstall --jobs=1 --force-reinstalls
96 | ```
97 |
98 |
99 | # Usage
100 |
101 | _This guide assumes you are already familiar with Tidal and creating patterns
102 | with samples._
103 |
104 |
105 | ## Get the names of MIDI devices on your system
106 |
107 | In order to use `tidal-midi` you will need the _exact_ name of a MIDI
108 | device on your system. You can get a list of MIDI devices on your system
109 | by running some code in a regular `.tidal` file.
110 |
111 | Assuming you're using the Atom editor, create a new file and save it with
112 | a `.tidal` extension (e.g. `midi-test.tidal`). Then, type the following in
113 | the editor:
114 |
115 | ```haskell
116 | import Sound.Tidal.MIDI.Context
117 |
118 | displayOutputDevices >>= putStrLn
119 | ```
120 |
121 | Evalulate both of those above lines separately using `Shift+Enter` in Atom.
122 | After evaluating the last line, it will output a list of MIDI devices
123 | in your editor (in Atom, at the bottom output panel).
124 |
125 | After listing MIDI devices on your system, take note of the device name you
126 | will use. Devices names are case-sensitive.
127 |
128 | For the purposes of this guide, we'll assume your device name is "USB MIDI Device".
129 |
130 | > You only need to do this step whenever you want to get a list of devices.
131 | > Once you take note of your system's device names, you don't need to perform
132 | > this step ever again (unless you acquire a new MIDI device).
133 |
134 |
135 | ## Boot tidal-midi
136 |
137 | Make sure you're currently working in a file with a `.tidal` extension in
138 | your editor (it could be the same file from the device list step above).
139 | Then type these three lines of bootup code:
140 |
141 | ```haskell
142 | import Sound.Tidal.MIDI.Context
143 |
144 | devices <- midiDevices
145 |
146 | m1 <- midiStream devices "USB MIDI Device" 1 synthController
147 | ```
148 |
149 | Evaluate each of those lines (use `Shift+Enter` in the Atom
150 | editor). Now Atom is ready to run MIDI patterns using `m1`.
151 |
152 | > In the last line of the boot code above, the last three parameters
153 | > are the most important:
154 | >
155 | > - "USB MIDI Device" is the name of your device
156 | > - 1 is the MIDI channel number
157 | > - synthController is the type of synthesizer code to use (you can use custom ones)
158 |
159 |
160 | ## Playing patterns on your device
161 |
162 | The following code will play a very simple pattern on middle-C:
163 |
164 | ```haskell
165 | m1 $ note "0"
166 | ```
167 |
168 | Above, the `note` param indicates a MIDI note, where `0` equals middle-C. The
169 | following pattern plays a major scale:
170 |
171 | ```haskell
172 | m1 $ note "0 2 4 5 7 9 11 12"
173 | ```
174 |
175 | Alternatively, you can use `midinote` to explicitly use a MIDI note from 0 to 127:
176 |
177 | ```haskell
178 | m1 $ midinote "60 62 64 65 67 69 71 72"
179 | ```
180 |
181 | You can use normal TidalCycles pattern transform functions to change `tidal-midi`
182 | patterns:
183 |
184 | ```haskell
185 | m1 $ every 3 (rev) $ every 2 (density 2) $ note "0 2 4 5 7 9 11 12"
186 | ```
187 |
188 |
189 | ### Note length, velocity, and other MIDI CC parameters
190 |
191 | Note length and velocity are controlled using the `dur` and `velocity`
192 | parameters, respectively.
193 |
194 | The value of `dur` is given in seconds:
195 |
196 | ```haskell
197 | m1 $ note "0 2" # dur "0.05 0.2"
198 |
199 | m1 $ note "0 2" # dur (scale 0.05 0.3 $ slow 1.5 tri1)
200 | ```
201 |
202 | Alternatively, the `legato` parameter tells Tidal to scale the note
203 | duration to fill it's "slot" in the pattern. For example, the following
204 | will give four notes each a quarter cycle in duration (values of legato
205 | greater or less than one will multiply the duration):
206 |
207 | ```haskell
208 | m1 $ note "0 1 0 2" # legato "1"
209 | ```
210 |
211 | `velocity` has a range from *0 to 1*, and equates to MIDI values *0 to 127*:
212 |
213 | ```haskell
214 | m1 $ note "0 2 4 5 7 9 11 12" # velocity "0.5 0.75 1"
215 |
216 | m1 $ note "0 2 4 5 7 9 11 12" # velocity (scale 0.5 1 $ slow 1.5 saw1)
217 | ```
218 |
219 | The `synthController` has some params that support MIDI Change Control messages,
220 | such as the mod wheel:
221 |
222 | ```haskell
223 | m1 $ note "0 2 4 5 7 9 11 12" # modwheel "0.1 0.4 0.9"
224 | ```
225 |
226 | Details about the default MIDI CC messages can be found in the
227 | [default synth controller](#defaultsynthcontroller) section below.
228 |
229 | MIDI CC params can have decimal values in the range *0 to 1*, which map to MIDI
230 | CC values *0 to 127*.
231 |
232 | _Custom synthesizer implementations may implement additional MIDI CC parameters.
233 | Please refer to the [supported synths](doc/synths.md) for more information._
234 |
235 |
236 | ## Custom MIDI Channels
237 |
238 | Let's review this line from the boilerplate code above:
239 |
240 | ```haskell
241 | m1 <- midiStream devices "USB MIDI Device" 1 synthController
242 | ```
243 |
244 | The 2nd to last parameter on that line indicates the channel number. Let's say
245 | your device is running on channel 7. You can specify channel 7 by changing the
246 | 2nd to last parameter:
247 |
248 | ```haskell
249 | m1 <- midiStream devices "USB MIDI Device" 7 synthController
250 | ```
251 |
252 |
253 | ## Multiple MIDI Channels
254 |
255 | `tidal-midi` supports devices with multiple channels so that you can create
256 | patterns on each channel separately:
257 |
258 | ```haskell
259 | m1 <- midiStream devices "USB MIDI Device" 1 synthController
260 | m2 <- midiStream devices "USB MIDI Device" 2 synthController
261 | m5 <- midiStream devices "USB MIDI Device" 5 synthController
262 |
263 | m1 $ note (run 4) # velocity "0.5"
264 | m2 $ note "0*2 5 7" # dur "0.1"
265 | m5 $ midinote "36 60"
266 | ```
267 |
268 | > Note: at the time of this writing, multiple channels can cause scheduling
269 | > problems if the synth controller's latency is too low. This is mainly an
270 | > issue for `tidal-midi` developers to improve, but users may be impacted.
271 | > Latency values can be increased by modifying the synth controller's source
272 | > code (e.g. in `SimpleSynth.hs`), then re-compiling `tidal-midi`
273 | > with `cabal install`.
274 |
275 |
276 | ## The default synthController (a.k.a "simple synth")
277 |
278 | The simple synth comes with _simple_ MIDI parameters, that any device should understand:
279 |
280 | * modwheel (MIDI CC #1)
281 | * balance (MIDI CC #8)
282 | * expression (MIDI CC #11)
283 | * sustainpedal (MIDI CC #64)
284 |
285 | All of these parameters map the given values from __0..1__ to MIDI values ranging from __0..127__.
286 |
287 | You can use all of these parameters like the familiar synth parameters in
288 | TidalCycles:
289 |
290 | ```haskell
291 | m1 $ note "0*8" # modwheel "0.25 0.75" # balance "0.1 0.9" # expression (sine1)
292 | ```
293 |
294 | __All tidal-midi synthesizers__ "inherit" from the "simple synth" and
295 | automatically expose these same parameters.
296 |
297 | See the section below on [Supported Synthesizers](#supportedsynths) for details
298 | on custom controllers for popular hardware synthesizers.
299 |
300 |
301 | # Supported Synthesizers
302 |
303 | A variety of custom mappings have been created in `tidal-midi` for popular hardware synthesizers.
304 | Click on a device below to get details on its usage:
305 |
306 | * [DSI Tetra](doc/synths.md#dsi-tetra)
307 | * Elektron Analog RYTM
308 | * [Korg Volca Bass](doc/synths.md#korg-volca-bass)
309 | * [Korg Volca Beats](doc/synths.md#korg-volca-beats)
310 | * [Korg Volca Keys](doc/synths.md#korg-volca-keys)
311 | * Roland System-1M
312 | * Synthino
313 | * [Waldorf Blofeld](doc/synths.md#waldorf-blofeld)
314 |
315 |
316 |
317 | # How to write your own synth mapping
318 |
319 | Interested in using `tidal-midi` with your own synthesizer? Please read the guide on [Writing a new synth mapping](doc/synth-mapping.md).
320 |
321 |
322 |
323 | # Automatic startup in Emacs
324 |
325 | Within your `tidal.el` script, locate the function `tidal-start-haskell` and add:
326 |
327 | ```emacs
328 | (tidal-send-string "import Sound.Tidal.MIDI.Context")
329 | ```
330 |
331 | after
332 |
333 | ```emacs
334 | (tidal-send-string "import Sound.Tidal.Context")
335 | ```
336 |
337 | Additionally you will have to add lines to import the synth you want to control via MIDI, e.g. `(tidal-send-string "import Sound.Tidal.VolcaKeys")` as well as the initialization commands for streams:
338 |
339 | ```emacs
340 | (tidal-send-string "devices <- midiDevices")
341 | (tidal-send-string "t1 <- midiStream devices \"USB MIDI Device\" 1 synthController")
342 | ```
343 |
344 | The above code adds the MIDI device "USB MIDI Device" and controls it via MIDI channel 1.
345 | With this set up you will be able to use it via e.g. `t1 $ note "50"`
346 |
347 |
348 |
349 | # Known issues and limitations
350 |
351 | - SysEx support is there but really limited to work with the Waldorf Blofeld
352 |
--------------------------------------------------------------------------------
/Setup.hs:
--------------------------------------------------------------------------------
1 | import Distribution.Simple
2 | main = defaultMain
3 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/Ambika.hs:
--------------------------------------------------------------------------------
1 | module Sound.Tidal.MIDI.Ambika where
2 |
3 | import Sound.Tidal.MIDI.Control
4 | import Sound.Tidal.Params
5 |
6 | ambikaController :: ControllerShape
7 | ambikaController =
8 | ControllerShape
9 | { controls =
10 | [ mCC gain_p 7
11 | , mCC growl_p 9
12 | , mCC fuzz_p 12
13 | , mCC crush_p 13
14 | , mCC osc1range_p 14
15 | , mCC osc1detune_p 15
16 | , mCC osc1shape_p 16
17 | , mCC osc1param_p 17
18 | , mCC osc2shape_p 18
19 | , mCC osc2param_p 19
20 | , mCC osc2range_p 20
21 | , mCC osc2detune_p 21
22 | , mCC pan_p 22
23 | , mCC xmodtype_p 23
24 | , mCC xmodamount_p 24
25 | , mCC subshape_p 25
26 | , mCC sublevel_p 26
27 | , mCC noiselevel_p 27
28 | , mCC filtermode_p 28
29 | , mCC f2cutoff_p 29
30 | , mCC f2res_p 30
31 | , mCC f2mode_p 31
32 | , mCC lfo1sync_p 44
33 | , mCC lfo1rate_p 45
34 | , mCC lfo1shape_p 46
35 | , mCC lfo4rate_p 47
36 | , mCC lfo4shape_p 48
37 | , mCC lfo2sync_p 52
38 | , mCC lfo2rate_p 53
39 | , mCC lfo2shape_p 54
40 | , mCC lfo3sync_p 60
41 | , mCC lfo3rate_p 61
42 | , mCC lfo3shape_p 62
43 | , mCC hold_p 64
44 | , mCC mlegato_p 68
45 | , mCC env1s_p 70
46 | , mCC f1res_p 71
47 | , mCC env1r_p 72
48 | , mCC env1a_p 73
49 | , mCC f1cutoff_p 74
50 | , mCC env1d_p 75
51 | , mCC env2s_p 78
52 | , mCC env2r_p 80
53 | , mCC env2a_p 81
54 | , mCC env2d_p 83
55 | , mCC env3s_p 86
56 | , mCC env3r_p 88
57 | , mCC env3a_p 89
58 | , mCC env3d_p 91
59 | , mCC parttuning_p 94
60 | , mCC tuningspread_p 95
61 | , mCC arpmode_p 102
62 | , mCC arpdir_p 103
63 | , mCC arpoct_p 104
64 | , mCC arppat_p 105
65 | , mCC arpres_p 106
66 | , mCC polymode_p 107
67 | , mCC allsoundsoff_p 120
68 | , mCC resetallcontrollers_p 121
69 | , mCC allnotesoff_p 123
70 | ]
71 | , latency = 0.1
72 | }
73 |
74 | ambikaSynth = toShape ambikaController
75 |
76 | (growl, growl_p) = pF "growl" (Just 0)
77 |
78 | (fuzz, fuzz_p) = pF "fuzz" (Just 0)
79 |
80 | (acrush, acrush_p) = pF "crush" (Just 0)
81 |
82 | (osc1range, osc1range_p) = pF "osc1range" (Just 0)
83 |
84 | (osc1detune, osc1detune_p) = pF "osc1detune" (Just 0)
85 |
86 | (osc1shape, osc1shape_p) = pF "osc1shape" (Just 0)
87 |
88 | (osc1param, osc1param_p) = pF "osc1param" (Just 0)
89 |
90 | (osc2range, osc2range_p) = pF "osc2range" (Just 0)
91 |
92 | (osc2detune, osc2detune_p) = pF "osc2detune" (Just 0)
93 |
94 | (osc2shape, osc2shape_p) = pF "osc2shape" (Just 0)
95 |
96 | (osc2param, osc2param_p) = pF "osc2param" (Just 0)
97 |
98 | (xmodtype, xmodtype_p) = pF "xmodtype" (Just 0)
99 |
100 | (xmodamount, xmodamount_p) = pF "xmodamount" (Just 0)
101 |
102 | (subshape, subshape_p) = pF "subshape" (Just 0)
103 |
104 | (sublevel, sublevel_p) = pF "sublevel" (Just 0)
105 |
106 | (noiselevel, noiselevel_p) = pF "noiselevel" (Just 0)
107 |
108 | (filtermode, filtermode_p) = pF "filtermode" (Just 0)
109 |
110 | (f1cutoff, f1cutoff_p) = pF "f1cutoff" (Just 0)
111 |
112 | (f1res, f1res_p) = pF "f1res" (Just 0)
113 |
114 | (f2cutoff, f2cutoff_p) = pF "f2cutoff" (Just 0)
115 |
116 | (f2res, f2res_p) = pF "f2res" (Just 0)
117 |
118 | (f2mode, f2mode_p) = pF "f2mode" (Just 0)
119 |
120 | (lfo1sync, lfo1sync_p) = pF "lfo1sync" (Just 0)
121 |
122 | (lfo1rate, lfo1rate_p) = pF "lfo1rate" (Just 0)
123 |
124 | (lfo1shape, lfo1shape_p) = pF "lfo1shape" (Just 0)
125 |
126 | (lfo2sync, lfo2sync_p) = pF "lfo2sync" (Just 0)
127 |
128 | (lfo2rate, lfo2rate_p) = pF "lfo2rate" (Just 0)
129 |
130 | (lfo2shape, lfo2shape_p) = pF "lfo2shape" (Just 0)
131 |
132 | (lfo3sync, lfo3sync_p) = pF "lfo3sync" (Just 0)
133 |
134 | (lfo3rate, lfo3rate_p) = pF "lfo3rate" (Just 0)
135 |
136 | (lfo3shape, lfo3shape_p) = pF "lfo3shape" (Just 0)
137 |
138 | (lfo4sync, lfo4sync_p) = pF "lfo4sync" (Just 0)
139 |
140 | (lfo4rate, lfo4rate_p) = pF "lfo4rate" (Just 0)
141 |
142 | (lfo4shape, lfo4shape_p) = pF "lfo4shape" (Just 0)
143 |
144 | (mlegato, mlegato_p) = pF "mlegato" (Just 0)
145 |
146 | (env1a, env1a_p) = pF "env1a" (Just 0)
147 |
148 | (env1d, env1d_p) = pF "env1d" (Just 0)
149 |
150 | (env1s, env1s_p) = pF "env1s" (Just 0)
151 |
152 | (env1r, env1r_p) = pF "env1r" (Just 0)
153 |
154 | (env2a, env2a_p) = pF "env2a" (Just 0)
155 |
156 | (env2d, env2d_p) = pF "env2d" (Just 0)
157 |
158 | (env2s, env2s_p) = pF "env2s" (Just 0)
159 |
160 | (env2r, env2r_p) = pF "env2r" (Just 0)
161 |
162 | (env3a, env3a_p) = pF "env3a" (Just 0)
163 |
164 | (env3d, env3d_p) = pF "env3d" (Just 0)
165 |
166 | (env3s, env3s_p) = pF "env3s" (Just 0)
167 |
168 | (env3r, env3r_p) = pF "env3r" (Just 0)
169 |
170 | (arpmode, arpmode_p) = pF "arpmode" (Just 0)
171 |
172 | (arpdir, arpdir_p) = pF "arpdir" (Just 0)
173 |
174 | (arpoct, arpoct_p) = pF "arpoct" (Just 0)
175 |
176 | (arppat, arppat_p) = pF "arppat" (Just 0)
177 |
178 | (arpres, arpres_p) = pF "arpres" (Just 0)
179 |
180 | (parttuning, parttuning_p) = pF "parttuning" (Just 0)
181 |
182 | (tuningspread, tuningspread_p) = pF "tuningspread" (Just 0)
183 |
184 | (polymode, polymode_p) = pF "polymode" (Just 0)
185 |
186 | (allsoundsoff, allsoundsoff_p) = pF "allsoundsoff" (Just 0)
187 |
188 | (allnotesoff, allnotesoff_p) = pF "allnotesoff" (Just 0)
189 |
190 | (resetallcontrollers, resetallcontrollers_p) = pF "resetallcontrollers" (Just 0)
191 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/Blofeld.hs:
--------------------------------------------------------------------------------
1 | module Sound.Tidal.MIDI.Blofeld where
2 |
3 | import Sound.Tidal.MIDI.Control
4 | import Sound.Tidal.Params
5 |
6 | -- Blofeld midi mapping --
7 |
8 | -- mod wheel: MIDI CC 1, 0...127
9 | -- breath control: MIDI CC 2, 0...127
10 | -- foot control: MIDI CC 4, 0...127
11 | -- glide rate: MIDI CC 5, 0...127
12 | -- channel volume: MIDI CC 7, 0...127
13 | -- pan: MIDI CC 10, 0...127
14 | --
15 | -- arp range: MIDI CC 12, 0...9
16 | -- arp length: MIDI CC 13, 0...15
17 | -- arp active: MIDI CC 14, 0...3
18 | --
19 | -- lfo 1 shape: MIDI CC 15, 0...5
20 | -- lfo 1 speed: MIDI CC 16, 0...127
21 | -- lfo 1 sync: MIDI CC 17, 0...1
22 | -- lfo 1 delay: MIDI CC 18, 0...127
23 | --
24 | -- lfo 2 shape: MIDI CC 19, 0...5
25 | -- lfo 2 speed: MIDI CC 20, 0...127
26 | -- lfo 2 sync: MIDI CC 21, 0...1
27 | -- lfo 2 delay: MIDI CC 22, 0...127
28 | --
29 | -- lfo 3 shape: MIDI CC 23, 0...5
30 | -- lfo 3 speed: MIDI CC 24, 0...127
31 | -- lfo 3 sync: MIDI CC 25, 0...1
32 | -- lfo 3 delay: MIDI CC 26, 0...127
33 | --
34 | -- osc 1 octave: MIDI CC 27, 16,28,40...112
35 | -- osc 1 semitone: MIDI CC 28, 52...76
36 | -- osc 1 detune: MIDI CC 29, 0...127
37 | -- osc 1 fm: MIDI CC 30, 0...127
38 | -- osc 1 shape: MIDI CC 31, 0...5
39 | --
40 | -- bank select LSB: MIDI CC 32, 0...n
41 | --
42 | -- osc 1 pw: MIDI CC 33, 0...127
43 | -- osc 1 pwm: MIDI CC 34, 0...127
44 | --
45 | -- osc 2 octave: MIDI CC 35, 16,28,40...112
46 | -- osc 2 semitone: MIDI CC 36, 52...76
47 | -- osc 2 detune: MIDI CC 37, 0...127
48 | -- osc 2 fm: MIDI CC 38, 0...127
49 | -- osc 2 shape: MIDI CC 39, 0...5
50 | -- osc 2 pw: MIDI CC 40, 0...127
51 | -- osc 2 pwm: MIDI CC 41, 0...127
52 | --
53 | -- osc 3 octave: MIDI CC 42, 16,28,40...112
54 | -- osc 3 semitone: MIDI CC 43, 52...76
55 | -- osc 3 detune: MIDI CC 44, 0...127
56 | -- osc 3 fm: MIDI CC 45, 0...127
57 | -- osc 3 shape: MIDI CC 46, 0...5
58 | -- osc 3 pw: MIDI CC 47, 0...127
59 | -- osc 3 pwm: MIDI CC 48, 0...127
60 | --
61 | -- sync: MIDI CC 49, 0...1
62 | -- pitchmod: MIDI CC 50, 0...127
63 | -- glide mode: MIDI CC 51, 0...9
64 | --
65 | -- osc 1 level: MIDI CC 52, 0...127
66 | -- osc 1 balance: MIDI CC 53, 0...127
67 | --
68 | -- ringmod level: MIDI CC 54, 0...127
69 | -- ringmod bal: MIDI CC 55, 0...127
70 | --
71 | -- osc 2 level: MIDI CC 56, 0...127
72 | -- osc 2 balance: MIDI CC 57, 0...127
73 | --
74 | -- osc 3 level: MIDI CC 58, 0...127
75 | -- osc 3 balance: MIDI CC 59, 0...127
76 | --
77 | -- noise level: MIDI CC 60, 0...127
78 | -- noise balance: MIDI CC 61, 0...127
79 | -- noise colour: MIDI CC 62, 0...127
80 | --
81 | -- sustain pedal: MIDI CC 64, 0...127
82 | -- glide active: MIDI CC 65, 0...127
83 | -- sostenuto: MIDI CC 66, 0...127
84 | --
85 | -- routing: MIDI CC 67, 0...127
86 | -- filter 1 type: MIDI CC 68, 0...10
87 | -- filter 1 cutoff: MIDI CC 69, 0...127
88 | -- filter 1 resonance: MIDI CC 70, 0...127
89 | -- filter 1 drive: MIDI CC 71, 0...127
90 | -- filter 1 keytrack: MIDI CC 72, 0...127
91 | -- filter 1 env amnt: MIDI CC 73, 0...127
92 | -- filter 1 env vel: MIDI CC 74, 0...127
93 | -- filter 1 cutoff mod: MIDI CC 75, 0...127
94 | -- filter 1 fm: MIDI CC 76, 0...127
95 | -- filter 1 pan: MIDI CC 77, 0...127
96 | -- filter 1 panmod: MIDI CC 78, 0...127
97 | --
98 | -- filter 2 type: MIDI CC 79, 0...10
99 | -- filter 2 cutoff: MIDI CC 80, 0...127
100 | -- filter 2 resonance: MIDI CC 81, 0...127
101 | -- filter 2 drive: MIDI CC 82, 0...127
102 | -- filter 2 keytrack: MIDI CC 83, 0...127
103 | -- filter 2 env amnt: MIDI CC 84, 0...127
104 | -- filter 2 env vel: MIDI CC 85, 0...127
105 | -- filter 2 cutoff mod: MIDI CC 86, 0...127
106 | -- filter 2 fm: MIDI CC 87, 0...127
107 | -- filter 2 pan: MIDI CC 88, 0...127
108 | -- filter 2 panmod: MIDI CC 89, 0...127
109 | --
110 | -- amp volume: MIDI CC 90, 0...127
111 | -- amp velocity: MIDI CC 91, 0...127
112 | -- amp mod: MIDI CC 92, 0...127
113 | --
114 | -- fx 1 mix: MIDI CC 93, 0...127
115 | -- fx 2 mix: MIDI CC 94, 0...127
116 | --
117 | -- fe attack: MIDI CC 95, 0...127
118 | -- fe decay: MIDI CC 96, 0...127
119 | -- fe sustain: MIDI CC 97, 0...127
120 | -- fe decay 2: MIDI CC 98, 0...127
121 | -- fe sustain 2: MIDI CC 99, 0...127
122 | -- fe release: MIDI CC 100, 0...127
123 | --
124 | -- ae attack: MIDI CC 101, 0...127
125 | -- ae decay: MIDI CC 102, 0...127
126 | -- ae sustain: MIDI CC 103, 0...127
127 | -- ae decay 2: MIDI CC 104, 0...127
128 | -- ae sustain 2: MIDI CC 105, 0...127
129 | -- ae release: MIDI CC 106, 0...127
130 | --
131 | -- e3 attack: MIDI CC 107, 0...127
132 | -- e3 decay: MIDI CC 108, 0...127
133 | -- e3 sustain: MIDI CC 109, 0...127
134 | -- e3 decay 2: MIDI CC 110, 0...127
135 | -- e3 sustain 2: MIDI CC 111, 0...127
136 | -- e3 release: MIDI CC 112, 0...127
137 | --
138 | -- e4 attack: MIDI CC 113, 0...127
139 | -- e4 decay: MIDI CC 114, 0...127
140 | -- e4 sustain: MIDI CC 115, 0...127
141 | -- e4 decay 2: MIDI CC 116, 0...127
142 | -- e4 sustain 2: MIDI CC 117, 0...127
143 | -- e4 release: MIDI CC 118, 0...127
144 | --
145 | -- all sounds off: MIDI CC 120, 0
146 | -- reset all controls: MIDI CC 121, 0
147 | -- local control: MIDI CC 122, 0...127
148 | -- all notes off: MIDI CC 123, 0
149 |
150 | (mod_w, mod_w_p) = pF "mod_w" (Just 0)
151 | (br_ctrl, br_ctrl_p) = pF "br_ctrl" (Just 0)
152 | (ft_ctrl, ft_ctrl_p) = pF "ft_ctrl" (Just 0)
153 | (gl_rate, gl_rate_p) = pF "gl_rate" (Just 0)
154 | (ch_vol, ch_vol_p) = pF "ch_vol" (Just 0)
155 | (pan_, pan__p) = pF "pan" (Just 0)
156 | (arp_rng, arp_rng_p) = pF "arp_rng" (Just 0)
157 | (arp_len, arp_len_p) = pF "arp_len" (Just 0)
158 | (arp_act, arp_act_p) = pF "arp_act" (Just 0)
159 | (lfo1shape, lfo1shape_p) = pF "lfo1shape" (Just 0)
160 | (lfo1speed, lfo1speed_p) = pF "lfo1speed" (Just 0)
161 | (lfo1sync, lfo1sync_p) = pF "lfo1sync" (Just 0)
162 | (lfo1delay, lfo1delay_p) = pF "lfo1delay" (Just 0)
163 | (lfo2shape, lfo2shape_p) = pF "lfo2shape" (Just 0)
164 | (lfo2speed, lfo2speed_p) = pF "lfo2speed" (Just 0)
165 | (lfo2sync, lfo2sync_p) = pF "lfo2sync" (Just 0)
166 | (lfo2delay, lfo2delay_p) = pF "lfo2delay" (Just 0)
167 | (lfo3shape, lfo3shape_p) = pF "lfo3shape" (Just 0)
168 | (lfo3speed, lfo3speed_p) = pF "lfo3speed" (Just 0)
169 | (lfo3sync, lfo3sync_p) = pF "lfo3sync" (Just 0)
170 | (lfo3delay, lfo3delay_p) = pF "lfo3delay" (Just 0)
171 | (osc1oct, osc1oct_p) = pF "osc1oct" (Just 0)
172 | (osc1semi, osc1semi_p) = pF "osc1semi" (Just 0)
173 | (osc1detune, osc1detune_p) = pF "osc1detune" (Just 0)
174 | (osc1fm, osc1fm_p) = pF "osc1fm" (Just 0)
175 | (osc1shape, osc1shape_p) = pF "osc1shape" (Just 0)
176 | (bank_sel, bank_sel_p) = pF "bank_sel" (Just 0)
177 | (osc1pw, osc1pw_p) = pF "osc1pw" (Just 0)
178 | (osc1pwm, osc1pwm_p) = pF "osc1pwm" (Just 0)
179 | (osc2oct, osc2oct_p) = pF "osc2oct" (Just 0)
180 | (osc2semi, osc2semi_p) = pF "osc2semi" (Just 0)
181 | (osc2detune, osc2detune_p) = pF "osc2detune" (Just 0)
182 | (osc2fm, osc2fm_p) = pF "osc2fm" (Just 0)
183 | (osc2shape, osc2shape_p) = pF "osc2shape" (Just 0)
184 | (osc2pw, osc2pw_p) = pF "osc2pw" (Just 0)
185 | (osc2pwm, osc2pwm_p) = pF "osc2pwm" (Just 0)
186 | (osc3oct, osc3oct_p) = pF "osc3oct" (Just 0)
187 | (osc3semi, osc3semi_p) = pF "osc3semi" (Just 0)
188 | (osc3detune, osc3detune_p) = pF "osc3detune" (Just 0)
189 | (osc3fm, osc3fm_p) = pF "osc3fm" (Just 0)
190 | (osc3shape, osc3shape_p) = pF "osc3shape" (Just 0)
191 | (osc3pw, osc3pw_p) = pF "osc3pw" (Just 0)
192 | (osc3pwm, osc3pwm_p) = pF "osc3pwm" (Just 0)
193 | (sync, sync_p) = pF "sync" (Just 0)
194 | (pitchmod, pitchmod_p) = pF "pitchmod" (Just 0)
195 | (glide_mode, glide_mode_p) = pF "glide_mode" (Just 0)
196 | (osc1lvl, osc1lvl_p) = pF "osc1lvl" (Just 0)
197 | (osc1bal, osc1bal_p) = pF "osc1bal" (Just 0)
198 | (ringmod_lvl, ringmod_lvl_p) = pF "ringmod_lvl" (Just 0)
199 | (ringmod_bal, ringmod_bal_p) = pF "ringmod_bal" (Just 0)
200 | (osc2lvl, osc2lvl_p) = pF "osc2lvl" (Just 0)
201 | (osc2bal, osc2bal_p) = pF "osc2bal" (Just 0)
202 | (osc3lvl, osc3lvl_p) = pF "osc3lvl" (Just 0)
203 | (osc3bal, osc3bal_p) = pF "osc3bal" (Just 0)
204 | (noise_lvl, noise_lvl_p) = pF "noise_lvl" (Just 0)
205 | (noise_bal, noise_bal_p) = pF "noise_bal" (Just 0)
206 | (noise_col, noise_col_p) = pF "noise_col" (Just 0)
207 | (sus_ped, sus_ped_p) = pF "sus_ped" (Just 0)
208 | (glide_act, glide_act_p) = pF "glide_act" (Just 0)
209 | (sostenuto, sostenuto_p) = pF "sostenuto" (Just 0)
210 | (routing, routing_p) = pF "routing" (Just 0)
211 | (fil1tp, fil1tp_p) = pF "fil1tp" (Just 0)
212 | (fil1cut, fil1cut_p) = pF "fil1cut" (Just 0)
213 | (fil1res, fil1res_p) = pF "fil1res" (Just 0)
214 | (fil1drv, fil1drv_p) = pF "fil1drv" (Just 0)
215 | (fil1key, fil1key_p) = pF "fil1key" (Just 0)
216 | (fil1enva, fil1enva_p) = pF "fil1enva" (Just 0)
217 | (fil1envv, fil1envv_p) = pF "fil1envv" (Just 0)
218 | (fil1cutmo, fil1cutmo_p) = pF "fil1cutmo" (Just 0)
219 | (fil1fm, fil1fm_p) = pF "fil1fm" (Just 0)
220 | (fil1pan, fil1pan_p) = pF "fil1pan" (Just 0)
221 | (fil1panmod, fil1panmod_p) = pF "fil1panmod" (Just 0)
222 | (fil2tp, fil2tp_p) = pF "fil2tp" (Just 0)
223 | (fil2cut, fil2cut_p) = pF "fil2cut" (Just 0)
224 | (fil2res, fil2res_p) = pF "fil2res" (Just 0)
225 | (fil2drv, fil2drv_p) = pF "fil2drv" (Just 0)
226 | (fil2key, fil2key_p) = pF "fil2key" (Just 0)
227 | (fil2enva, fil2enva_p) = pF "fil2enva" (Just 0)
228 | (fil2envv, fil2envv_p) = pF "fil2envv" (Just 0)
229 | (fil2cutmo, fil2cutmo_p) = pF "fil2cutmo" (Just 0)
230 | (fil2fm, fil2fm_p) = pF "fil2fm" (Just 0)
231 | (fil2pan, fil2pan_p) = pF "fil2pan" (Just 0)
232 | (fil2panmod, fil2panmod_p) = pF "fil2panmod" (Just 0)
233 | (amp_vol, amp_vol_p) = pF "amp_vol" (Just 0)
234 | (amp_vel, amp_vel_p) = pF "amp_vel" (Just 0)
235 | (amp_mod, amp_mod_p) = pF "amp_mod" (Just 0)
236 | (fx1mix, fx1mix_p) = pF "fx1mix" (Just 0)
237 | (fx2mix, fx2mix_p) = pF "fx2mix" (Just 0)
238 | (fe_att, fe_att_p) = pF "fe_att" (Just 0)
239 | (fe_dec, fe_dec_p) = pF "fe_dec" (Just 0)
240 | (fe_sus, fe_sus_p) = pF "fe_sus" (Just 0)
241 | (fe_dec2, fe_dec2_p) = pF "fe_dec2" (Just 0)
242 | (fe_sus2, fe_sus2_p) = pF "fe_sus2" (Just 0)
243 | (fe_rel, fe_rel_p) = pF "fe_rel" (Just 0)
244 | (ae_att, ae_att_p) = pF "ae_att" (Just 0)
245 | (ae_dec, ae_dec_p) = pF "ae_dec" (Just 0)
246 | (ae_sus, ae_sus_p) = pF "ae_sus" (Just 0)
247 | (ae_dec2, ae_dec2_p) = pF "ae_dec2" (Just 0)
248 | (ae_sus2, ae_sus2_p) = pF "ae_sus2" (Just 0)
249 | (ae_rel, ae_rel_p) = pF "ae_rel" (Just 0)
250 | (e3_att, e3_att_p) = pF "e3_att" (Just 0)
251 | (e3_dec, e3_dec_p) = pF "e3_dec" (Just 0)
252 | (e3_sus, e3_sus_p) = pF "e3_sus" (Just 0)
253 | (e3_dec2, e3_dec2_p) = pF "e3_dec2" (Just 0)
254 | (e3_sus2, e3_sus2_p) = pF "e3_sus2" (Just 0)
255 | (e3_rel, e3_rel_p) = pF "e3_rel" (Just 0)
256 | (e4_att, e4_att_p) = pF "e4_att" (Just 0)
257 | (e4_dec, e4_dec_p) = pF "e4_dec" (Just 0)
258 | (e4_sus, e4_sus_p) = pF "e4_sus" (Just 0)
259 | (e4_dec2, e4_dec2_p) = pF "e4_dec2" (Just 0)
260 | (e4_sus2, e4_sus2_p) = pF "e4_sus2" (Just 0)
261 | (e4_rel, e4_rel_p) = pF "e4_rel" (Just 0)
262 | (soff, soff_p) = pF "soff" (Just 0)
263 | (res_ctrl, res_ctrl_p) = pF "res_ctrl" (Just 0)
264 | (loc_cont, loc_cont_p) = pF "loc_cont" (Just 0)
265 | (noff, noff_p) = pF "noff" (Just 0)
266 |
267 |
268 | blofeldController :: ControllerShape
269 | blofeldController = ControllerShape {
270 | controls = [
271 | mCC mod_w_p 1,
272 | mCC br_ctrl_p 2,
273 | mCC ft_ctrl_p 4,
274 | mCC gl_rate_p 5,
275 | mCC ch_vol_p 7,
276 | mCC pan__p 10,
277 | mCC arp_rng_p 12,
278 | mCC arp_len_p 13,
279 | mCC arp_act_p 14,
280 | CC lfo1shape_p 15 (0, 5) passThru -- 0..5 - sine,triangle,square,saw,random,sample&hold
281 | ,mCC lfo1speed_p 16,
282 | CC lfo1sync_p 17 (0, 1) passThru -- 0 off, 1 on
283 | ,mCC lfo1delay_p 18,
284 | mCC lfo2shape_p 19,
285 | mCC lfo2speed_p 20,
286 | mCC lfo2sync_p 21,
287 | mCC lfo2delay_p 22,
288 | mCC lfo3shape_p 23,
289 | mCC lfo3speed_p 24,
290 | mCC lfo3sync_p 25,
291 | mCC lfo3delay_p 26,
292 | CC osc1oct_p 27 (16, 112) passThru -- 16, 28, 40 .. 112 - 128' .. 1/2'
293 | ,CC osc1semi_p 28 (52, 76) passThru -- 52 .. 76 - -12 - +12 semitones
294 | ,mCC osc1detune_p 29,
295 | mCC osc1fm_p 30,
296 | CC osc1shape_p 31 (0, 5) passThru -- 0..5 - pulse, saw, tri, sine, alt 1, alt 2
297 | ,mCC bank_sel_p 32,
298 | mCC osc1pw_p 33,
299 | mCC osc1pwm_p 34,
300 | mCC osc2oct_p 35,
301 | mCC osc2semi_p 36,
302 | mCC osc2detune_p 37,
303 | mCC osc2fm_p 38,
304 | mCC osc2shape_p 39,
305 | mCC osc2pw_p 40,
306 | mCC osc2pwm_p 41,
307 | mCC osc3oct_p 42,
308 | mCC osc3semi_p 43,
309 | mCC osc3detune_p 44,
310 | mCC osc3fm_p 45,
311 | mCC osc3shape_p 46,
312 | mCC osc3pw_p 47,
313 | mCC osc3pwm_p 48,
314 | mCC sync_p 49,
315 | mCC pitchmod_p 50,
316 | mCC glide_mode_p 51,
317 | mCC osc1lvl_p 52,
318 | mCC osc1bal_p 53,
319 | mCC ringmod_lvl_p 54,
320 | mCC ringmod_bal_p 55,
321 | mCC osc2lvl_p 56,
322 | mCC osc2bal_p 57,
323 | mCC osc3lvl_p 58,
324 | mCC osc3bal_p 59,
325 | mCC noise_lvl_p 60,
326 | mCC noise_bal_p 61,
327 | mCC noise_col_p 62,
328 | mCC sus_ped_p 64,
329 | mCC glide_act_p 65,
330 | mCC sostenuto_p 66,
331 | mCC routing_p 67,
332 | mCC fil1tp_p 68,
333 | mCC fil1cut_p 69,
334 | mCC fil1res_p 70,
335 | mCC fil1drv_p 71,
336 | mCC fil1key_p 72,
337 | mCC fil1enva_p 73,
338 | mCC fil1envv_p 74,
339 | mCC fil1cutmo_p 75,
340 | mCC fil1fm_p 76,
341 | mCC fil1pan_p 77,
342 | mCC fil1panmod_p 78,
343 | mCC fil2tp_p 79,
344 | mCC fil2cut_p 80,
345 | mCC fil2res_p 81,
346 | mCC fil2drv_p 82,
347 | mCC fil2key_p 83,
348 | mCC fil2enva_p 84,
349 | mCC fil2envv_p 85,
350 | mCC fil2cutmo_p 86,
351 | mCC fil2fm_p 87,
352 | mCC fil2pan_p 88,
353 | mCC fil2panmod_p 89,
354 | mCC amp_vol_p 90,
355 | mCC amp_vel_p 91,
356 | mCC amp_mod_p 92,
357 | mCC fx1mix_p 93,
358 | mCC fx2mix_p 94,
359 | mCC fe_att_p 95,
360 | mCC fe_dec_p 96,
361 | mCC fe_sus_p 97,
362 | mCC fe_dec2_p 98,
363 | mCC fe_sus2_p 99,
364 | mCC fe_rel_p 100,
365 | mCC ae_att_p 101,
366 | mCC ae_dec_p 102,
367 | mCC ae_sus_p 103,
368 | mCC ae_dec2_p 104,
369 | mCC ae_sus2_p 105,
370 | mCC ae_rel_p 106,
371 | mCC e3_att_p 107,
372 | mCC e3_dec_p 108,
373 | mCC e3_sus_p 109,
374 | mCC e3_dec2_p 110,
375 | mCC e3_sus2_p 111,
376 | mCC e3_rel_p 112,
377 | mCC e4_att_p 113,
378 | mCC e4_dec_p 114,
379 | mCC e4_sus_p 115,
380 | mCC e4_dec2_p 116,
381 | mCC e4_sus2_p 117,
382 | mCC e4_rel_p 118,
383 | mCC soff_p 120,
384 | mCC res_ctrl_p 121,
385 | mCC loc_cont_p 122,
386 | mCC noff_p 123
387 | ],
388 | latency = 0.1 }
389 |
390 | blofeld = toShape blofeldController
391 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/CC.hs:
--------------------------------------------------------------------------------
1 | module Sound.Tidal.MIDI.CC where
2 |
3 | import Sound.Tidal.MIDI.Control
4 | import Sound.Tidal.Params
5 |
6 | ccallController :: ControllerShape
7 | ccallController =
8 | ControllerShape
9 | { controls =
10 | [ mCC cc0_p 0
11 | , mCC cc1_p 1
12 | , mCC cc2_p 2
13 | , mCC cc3_p 3
14 | , mCC cc4_p 4
15 | , mCC cc5_p 5
16 | , mCC cc6_p 6
17 | , mCC cc7_p 7
18 | , mCC cc8_p 8
19 | , mCC cc9_p 9
20 | , mCC cc10_p 10
21 | , mCC cc11_p 11
22 | , mCC cc12_p 12
23 | , mCC cc13_p 13
24 | , mCC cc14_p 14
25 | , mCC cc15_p 15
26 | , mCC cc16_p 16
27 | , mCC cc17_p 17
28 | , mCC cc18_p 18
29 | , mCC cc19_p 19
30 | , mCC cc20_p 20
31 | , mCC cc21_p 21
32 | , mCC cc22_p 22
33 | , mCC cc23_p 23
34 | , mCC cc24_p 24
35 | , mCC cc25_p 25
36 | , mCC cc26_p 26
37 | , mCC cc27_p 27
38 | , mCC cc28_p 28
39 | , mCC cc29_p 29
40 | , mCC cc30_p 30
41 | , mCC cc31_p 31
42 | , mCC cc32_p 32
43 | , mCC cc33_p 33
44 | , mCC cc34_p 34
45 | , mCC cc35_p 35
46 | , mCC cc36_p 36
47 | , mCC cc37_p 37
48 | , mCC cc38_p 38
49 | , mCC cc39_p 39
50 | , mCC cc40_p 40
51 | , mCC cc41_p 41
52 | , mCC cc42_p 42
53 | , mCC cc43_p 43
54 | , mCC cc44_p 44
55 | , mCC cc45_p 45
56 | , mCC cc46_p 46
57 | , mCC cc47_p 47
58 | , mCC cc48_p 48
59 | , mCC cc49_p 49
60 | , mCC cc50_p 50
61 | , mCC cc51_p 51
62 | , mCC cc52_p 52
63 | , mCC cc53_p 53
64 | , mCC cc54_p 54
65 | , mCC cc55_p 55
66 | , mCC cc56_p 56
67 | , mCC cc57_p 57
68 | , mCC cc58_p 58
69 | , mCC cc59_p 59
70 | , mCC cc60_p 60
71 | , mCC cc61_p 61
72 | , mCC cc62_p 62
73 | , mCC cc63_p 63
74 | , mCC cc64_p 64
75 | , mCC cc65_p 65
76 | , mCC cc66_p 66
77 | , mCC cc67_p 67
78 | , mCC cc68_p 68
79 | , mCC cc69_p 69
80 | , mCC cc70_p 70
81 | , mCC cc71_p 71
82 | , mCC cc72_p 72
83 | , mCC cc73_p 73
84 | , mCC cc74_p 74
85 | , mCC cc75_p 75
86 | , mCC cc76_p 76
87 | , mCC cc77_p 77
88 | , mCC cc78_p 78
89 | , mCC cc79_p 79
90 | , mCC cc80_p 80
91 | , mCC cc81_p 81
92 | , mCC cc82_p 82
93 | , mCC cc83_p 83
94 | , mCC cc84_p 84
95 | , mCC cc85_p 85
96 | , mCC cc86_p 86
97 | , mCC cc87_p 87
98 | , mCC cc89_p 89
99 | , mCC cc90_p 90
100 | , mCC cc91_p 91
101 | , mCC cc92_p 92
102 | , mCC cc93_p 93
103 | , mCC cc94_p 94
104 | , mCC cc95_p 95
105 | , mCC cc96_p 96
106 | , mCC cc97_p 97
107 | , mCC cc98_p 98
108 | , mCC cc99_p 99
109 | , mCC cc100_p 100
110 | , mCC cc101_p 101
111 | , mCC cc102_p 102
112 | , mCC cc103_p 103
113 | , mCC cc104_p 104
114 | , mCC cc105_p 105
115 | , mCC cc106_p 106
116 | , mCC cc107_p 107
117 | , mCC cc108_p 108
118 | , mCC cc109_p 109
119 | , mCC cc110_p 110
120 | , mCC cc111_p 111
121 | , mCC cc112_p 112
122 | , mCC cc113_p 113
123 | , mCC cc114_p 114
124 | , mCC cc115_p 115
125 | , mCC cc116_p 116
126 | , mCC cc117_p 117
127 | , mCC cc118_p 118
128 | , mCC cc119_p 119
129 | , mCC cc120_p 120
130 | , mCC cc121_p 121
131 | , mCC cc122_p 122
132 | , mCC cc123_p 123
133 | , mCC cc124_p 124
134 | , mCC cc125_p 125
135 | , mCC cc126_p 126
136 | , mCC cc127_p 127
137 | ]
138 | , latency = 0.1
139 | }
140 |
141 | ccall = toShape ccallController
142 |
143 | (cc0, cc0_p) = pF "cc0" (Just 0)
144 |
145 | (cc1, cc1_p) = pF "cc1" (Just 0)
146 |
147 | (cc2, cc2_p) = pF "cc2" (Just 0)
148 |
149 | (cc3, cc3_p) = pF "cc3" (Just 0)
150 |
151 | (cc4, cc4_p) = pF "cc4" (Just 0)
152 |
153 | (cc5, cc5_p) = pF "cc5" (Just 0)
154 |
155 | (cc6, cc6_p) = pF "cc6" (Just 0)
156 |
157 | (cc7, cc7_p) = pF "cc7" (Just 0)
158 |
159 | (cc8, cc8_p) = pF "cc8" (Just 0)
160 |
161 | (cc9, cc9_p) = pF "cc9" (Just 0)
162 |
163 | (cc10, cc10_p) = pF "cc10" (Just 0)
164 |
165 | (cc11, cc11_p) = pF "cc11" (Just 0)
166 |
167 | (cc12, cc12_p) = pF "cc12" (Just 0)
168 |
169 | (cc13, cc13_p) = pF "cc13" (Just 0)
170 |
171 | (cc14, cc14_p) = pF "cc14" (Just 0)
172 |
173 | (cc15, cc15_p) = pF "cc15" (Just 0)
174 |
175 | (cc16, cc16_p) = pF "cc16" (Just 0)
176 |
177 | (cc17, cc17_p) = pF "cc17" (Just 0)
178 |
179 | (cc18, cc18_p) = pF "cc18" (Just 0)
180 |
181 | (cc19, cc19_p) = pF "cc19" (Just 0)
182 |
183 | (cc20, cc20_p) = pF "cc20" (Just 0)
184 |
185 | (cc21, cc21_p) = pF "cc21" (Just 0)
186 |
187 | (cc22, cc22_p) = pF "cc22" (Just 0)
188 |
189 | (cc23, cc23_p) = pF "cc23" (Just 0)
190 |
191 | (cc24, cc24_p) = pF "cc24" (Just 0)
192 |
193 | (cc25, cc25_p) = pF "cc25" (Just 0)
194 |
195 | (cc26, cc26_p) = pF "cc26" (Just 0)
196 |
197 | (cc27, cc27_p) = pF "cc27" (Just 0)
198 |
199 | (cc28, cc28_p) = pF "cc28" (Just 0)
200 |
201 | (cc29, cc29_p) = pF "cc29" (Just 0)
202 |
203 | (cc30, cc30_p) = pF "cc30" (Just 0)
204 |
205 | (cc31, cc31_p) = pF "cc31" (Just 0)
206 |
207 | (cc32, cc32_p) = pF "cc32" (Just 0)
208 |
209 | (cc33, cc33_p) = pF "cc33" (Just 0)
210 |
211 | (cc34, cc34_p) = pF "cc34" (Just 0)
212 |
213 | (cc35, cc35_p) = pF "cc35" (Just 0)
214 |
215 | (cc36, cc36_p) = pF "cc36" (Just 0)
216 |
217 | (cc37, cc37_p) = pF "cc37" (Just 0)
218 |
219 | (cc38, cc38_p) = pF "cc38" (Just 0)
220 |
221 | (cc39, cc39_p) = pF "cc39" (Just 0)
222 |
223 | (cc40, cc40_p) = pF "cc40" (Just 0)
224 |
225 | (cc41, cc41_p) = pF "cc41" (Just 0)
226 |
227 | (cc42, cc42_p) = pF "cc42" (Just 0)
228 |
229 | (cc43, cc43_p) = pF "cc43" (Just 0)
230 |
231 | (cc44, cc44_p) = pF "cc44" (Just 0)
232 |
233 | (cc45, cc45_p) = pF "cc45" (Just 0)
234 |
235 | (cc46, cc46_p) = pF "cc46" (Just 0)
236 |
237 | (cc47, cc47_p) = pF "cc47" (Just 0)
238 |
239 | (cc48, cc48_p) = pF "cc48" (Just 0)
240 |
241 | (cc49, cc49_p) = pF "cc49" (Just 0)
242 |
243 | (cc50, cc50_p) = pF "cc50" (Just 0)
244 |
245 | (cc51, cc51_p) = pF "cc51" (Just 0)
246 |
247 | (cc52, cc52_p) = pF "cc52" (Just 0)
248 |
249 | (cc53, cc53_p) = pF "cc53" (Just 0)
250 |
251 | (cc54, cc54_p) = pF "cc54" (Just 0)
252 |
253 | (cc55, cc55_p) = pF "cc55" (Just 0)
254 |
255 | (cc56, cc56_p) = pF "cc56" (Just 0)
256 |
257 | (cc57, cc57_p) = pF "cc57" (Just 0)
258 |
259 | (cc58, cc58_p) = pF "cc58" (Just 0)
260 |
261 | (cc59, cc59_p) = pF "cc59" (Just 0)
262 |
263 | (cc60, cc60_p) = pF "cc60" (Just 0)
264 |
265 | (cc61, cc61_p) = pF "cc61" (Just 0)
266 |
267 | (cc62, cc62_p) = pF "cc62" (Just 0)
268 |
269 | (cc63, cc63_p) = pF "cc63" (Just 0)
270 |
271 | (cc64, cc64_p) = pF "cc64" (Just 0)
272 |
273 | (cc65, cc65_p) = pF "cc65" (Just 0)
274 |
275 | (cc66, cc66_p) = pF "cc66" (Just 0)
276 |
277 | (cc67, cc67_p) = pF "cc67" (Just 0)
278 |
279 | (cc68, cc68_p) = pF "cc68" (Just 0)
280 |
281 | (cc69, cc69_p) = pF "cc69" (Just 0)
282 |
283 | (cc70, cc70_p) = pF "cc70" (Just 0)
284 |
285 | (cc71, cc71_p) = pF "cc71" (Just 0)
286 |
287 | (cc72, cc72_p) = pF "cc72" (Just 0)
288 |
289 | (cc73, cc73_p) = pF "cc73" (Just 0)
290 |
291 | (cc74, cc74_p) = pF "cc74" (Just 0)
292 |
293 | (cc75, cc75_p) = pF "cc75" (Just 0)
294 |
295 | (cc76, cc76_p) = pF "cc76" (Just 0)
296 |
297 | (cc77, cc77_p) = pF "cc77" (Just 0)
298 |
299 | (cc78, cc78_p) = pF "cc78" (Just 0)
300 |
301 | (cc79, cc79_p) = pF "cc79" (Just 0)
302 |
303 | (cc80, cc80_p) = pF "cc80" (Just 0)
304 |
305 | (cc81, cc81_p) = pF "cc81" (Just 0)
306 |
307 | (cc82, cc82_p) = pF "cc82" (Just 0)
308 |
309 | (cc83, cc83_p) = pF "cc83" (Just 0)
310 |
311 | (cc84, cc84_p) = pF "cc84" (Just 0)
312 |
313 | (cc85, cc85_p) = pF "cc85" (Just 0)
314 |
315 | (cc86, cc86_p) = pF "cc86" (Just 0)
316 |
317 | (cc87, cc87_p) = pF "cc87" (Just 0)
318 |
319 | (cc88, cc88_p) = pF "cc88" (Just 0)
320 |
321 | (cc89, cc89_p) = pF "cc89" (Just 0)
322 |
323 | (cc90, cc90_p) = pF "cc90" (Just 0)
324 |
325 | (cc91, cc91_p) = pF "cc91" (Just 0)
326 |
327 | (cc92, cc92_p) = pF "cc92" (Just 0)
328 |
329 | (cc93, cc93_p) = pF "cc93" (Just 0)
330 |
331 | (cc94, cc94_p) = pF "cc94" (Just 0)
332 |
333 | (cc95, cc95_p) = pF "cc95" (Just 0)
334 |
335 | (cc96, cc96_p) = pF "cc96" (Just 0)
336 |
337 | (cc97, cc97_p) = pF "cc97" (Just 0)
338 |
339 | (cc98, cc98_p) = pF "cc98" (Just 0)
340 |
341 | (cc99, cc99_p) = pF "cc99" (Just 0)
342 |
343 | (cc100, cc100_p) = pF "cc100" (Just 0)
344 |
345 | (cc101, cc101_p) = pF "cc101" (Just 0)
346 |
347 | (cc102, cc102_p) = pF "cc102" (Just 0)
348 |
349 | (cc103, cc103_p) = pF "cc103" (Just 0)
350 |
351 | (cc104, cc104_p) = pF "cc104" (Just 0)
352 |
353 | (cc105, cc105_p) = pF "cc105" (Just 0)
354 |
355 | (cc106, cc106_p) = pF "cc106" (Just 0)
356 |
357 | (cc107, cc107_p) = pF "cc107" (Just 0)
358 |
359 | (cc108, cc108_p) = pF "cc108" (Just 0)
360 |
361 | (cc109, cc109_p) = pF "cc109" (Just 0)
362 |
363 | (cc110, cc110_p) = pF "cc110" (Just 0)
364 |
365 | (cc111, cc111_p) = pF "cc111" (Just 0)
366 |
367 | (cc112, cc112_p) = pF "cc112" (Just 0)
368 |
369 | (cc113, cc113_p) = pF "cc113" (Just 0)
370 |
371 | (cc114, cc114_p) = pF "cc114" (Just 0)
372 |
373 | (cc115, cc115_p) = pF "cc115" (Just 0)
374 |
375 | (cc116, cc116_p) = pF "cc116" (Just 0)
376 |
377 | (cc117, cc117_p) = pF "cc117" (Just 0)
378 |
379 | (cc118, cc118_p) = pF "cc118" (Just 0)
380 |
381 | (cc119, cc119_p) = pF "cc119" (Just 0)
382 |
383 | (cc120, cc120_p) = pF "cc120" (Just 0)
384 |
385 | (cc121, cc121_p) = pF "cc121" (Just 0)
386 |
387 | (cc122, cc122_p) = pF "cc122" (Just 0)
388 |
389 | (cc123, cc123_p) = pF "cc123" (Just 0)
390 |
391 | (cc124, cc124_p) = pF "cc124" (Just 0)
392 |
393 | (cc125, cc125_p) = pF "cc125" (Just 0)
394 |
395 | (cc126, cc126_p) = pF "cc126" (Just 0)
396 |
397 | (cc127, cc127_p) = pF "cc127" (Just 0)
398 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/Context.hs:
--------------------------------------------------------------------------------
1 | module Sound.Tidal.MIDI.Context (module C) where
2 |
3 | import Sound.Tidal.MIDI.Device as C
4 | import Sound.Tidal.MIDI.Control as C
5 | import Sound.Tidal.MIDI.Stream as C
6 | import Sound.Tidal.MIDI.Synth as C
7 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/Control.hs:
--------------------------------------------------------------------------------
1 | {- |
2 | Mappings between Tidal's 'Sound.Tidal.Stream.Param's and MIDI control changes
3 | -}
4 | module Sound.Tidal.MIDI.Control where
5 |
6 | import Control.Applicative ((<$>))
7 | import qualified Sound.Tidal.Stream as S
8 | import Sound.Tidal.Tempo (Tempo(cps))
9 | import qualified Data.Map.Strict as Map
10 | import Data.Ratio
11 | import Sound.Tidal.Params hiding (n_p, legato_p)
12 |
13 | n_p :: S.Param
14 | n_p = snd $ pI "n" (Just 128)
15 |
16 | legato_p :: S.Param
17 | legato_p = snd $ pF "legato" (Just $ negate 1.0)
18 |
19 | {-|
20 | Map a 'Double' to 'Int' using given min/max values
21 | -}
22 | type RangeMapFunc = (Int, Int) -> Double -> Int
23 |
24 | {- | Make sure you apply @cutShape midiShape@ to an 'Sound.Tidal.Stream.ParamMap'
25 | before passing it into a function wanting this type -}
26 | type MIDINoteShape = S.ParamMap
27 |
28 | {-|
29 | Describe mapping a Tidal 'Sound.Tidal.Stream.Param' in terms of MIDI
30 | -}
31 | data ControlChange =
32 | CC { param :: S.Param, -- ^ the 'Sound.Tidal.Stream.Param' this control will apply to
33 | midi :: Int, -- ^ the MIDI parameter number to map to
34 | range :: (Int, Int), -- ^ the range this MIDI parameter accepts, by default this is (0,127)
35 | scalef :: RangeMapFunc -- ^ the function to apply mapping floating point values from pattern to MIDI integer values
36 | }
37 | | NRPN { param :: S.Param,
38 | midi :: Int,
39 | range :: (Int, Int),
40 | scalef :: RangeMapFunc
41 | }
42 | | SysEx { param :: S.Param,
43 | midi :: Int,
44 | range :: (Int, Int),
45 | scalef :: RangeMapFunc
46 | }
47 |
48 | {- |
49 | A definition for using a Tidal with specific MIDI device type.
50 |
51 | By default, every 'ControllerShape' accepts the following 'Sound.Tidal.Stream.Param's:
52 |
53 | * 'Sound.Tidal.Params.dur'
54 | * 'Sound.Tidal.Params.n'
55 | * 'Sound.Tidal.Params.velocity'
56 | * 'Sound.Tidal.Params.nudge'
57 | * 'Sound.Tidal.Params.unit'
58 |
59 | which will define the MIDI note to be played.
60 | -}
61 | data ControllerShape = ControllerShape {
62 | controls :: [ControlChange], -- ^ a list of controls that can be understood by a certain device type
63 | latency :: Double -- ^ the latency to be used when sending out MIDI messages, this is passed to 'Sound.Tidal.Stream.Shape'
64 | }
65 |
66 | {- |
67 | A simple shape defining the 'Sound.Tidal.Stream.Param's that are used for generating MIDI notes.
68 |
69 | This simplifies splitting a 'Sound.Tidal.Stream.ParamMap' into params for notes and control values.
70 | -}
71 | midiShape :: S.Shape
72 | midiShape = S.Shape {
73 | S.params = [
74 | dur_p,
75 | n_p,
76 | nudge_p,
77 | velocity_p,
78 | unit_p,
79 | legato_p
80 | ],
81 | S.latency = 0,
82 | S.cpsStamp = False
83 | }
84 |
85 | {- |
86 | Turns a 'MIDINoteShape' into concrete values for scheduling.
87 |
88 | -}
89 | computeTiming :: Tempo -- ^ the current playback speed
90 | -> Ratio Integer {- ^ if 'Sound.Tidal.Params.unit' is specified as @cycle@,
91 | this will be utilized to calculate the note's absolute duration with regard to current cycle length __Note__: this will ignore the specified duration of the Tidal param 'Sound.Tidal.Params.dur' -}
92 | -> MIDINoteShape -- ^ A map of 'Sound.Tidal.Stream.Param's that describes the note to be played
93 | -> ((Int,Int,Ratio Integer), Double) -- ^ A tuple of a 'Sound.Tidal.MIDI.Output.TimedNote' triplet and the value for 'nudge' to offset this note by
94 | computeTiming tempo duration note' = ((n', v', d'), nudge')
95 | where
96 | legato' = realToFrac $ S.fvalue $ note' Map.! legato_p
97 | unit' = if (legato' <= 0) then (head $ S.svalue $ note' Map.! unit_p) else 'c'
98 | v' = mapRange (0, 127) $ S.fvalue $ note' Map.! velocity_p
99 | n' = S.ivalue $ note' Map.! n_p
100 | d' = case unit' of
101 | 'r'-> byRate
102 | 'c' -> (+) (-0.001) $ (*) (abs legato') $ (/) duration $ realToFrac $ cps tempo
103 | _ -> byRate
104 | byRate = realToFrac $ S.fvalue $ note' Map.! dur_p
105 |
106 | nudge' = S.fvalue $ note' Map.! nudge_p
107 |
108 | {- | Converts a 'ControllerShape's controls into 'Sound.Tidal.Stream.Param's and makes a 'Sound.Tidal.Stream.Shape'
109 | This acts as an interface between Tidal's scheduling loop and MIDI scheduling. -}
110 | toShape :: ControllerShape -> S.Shape
111 | toShape cs = S.Shape {
112 | S.params = toParams cs,
113 | S.cpsStamp = False,
114 | S.latency = latency cs
115 | }
116 |
117 | {- | A 'RangeMapFunc' that simply passes 'floor's 'Double's.
118 |
119 | This can be used if a MIDI parameter of a device has different meanings for each value,
120 | e.g. the type of oscillator has to be specified by either "0", "1", "2" or "3" each representing a different waveform (sine, tri, square, rand)
121 | -}
122 | passThru :: (Int, Int) -> Double -> Int
123 | passThru (_, _) = floor -- no sanitizing of range…
124 |
125 | {- | Default mapping function from Double to Int.
126 |
127 | >>> mapRange (0, 127) 0.5
128 | 63
129 | -}
130 | mapRange :: (Int, Int) -> Double -> Int
131 | mapRange (low, high) = floor . (+ fromIntegral low) . (* ratio)
132 | where ratio = fromIntegral $ high - low
133 |
134 | -- | Helper function for creating a standard ControlChange for MIDI parameter
135 | mCC :: S.Param -> Int -> ControlChange
136 | mCC p m = CC {param=p, midi=m, range=(0, 127), scalef=mapRange }
137 |
138 | -- | Helper function for creating a standard ControlChange for a non-registered MIDI parameter
139 | mNRPN :: S.Param -> Int -> ControlChange
140 | mNRPN p m = NRPN {param=p, midi=m, range=(0, 127), scalef=mapRange }
141 |
142 | -- | Helper function for creating a ControlChange for a non-registered MIDI parameter with a custom range
143 | mrNRPN :: S.Param -> Int -> (Int, Int) -> ControlChange
144 | mrNRPN p m r = NRPN {param=p, midi=m, range=r, scalef=mapRange }
145 |
146 | -- | Translate a 'ControllerShape's controls into a list of 'Sound.Tidal.Stream.Param'
147 | toParams :: ControllerShape -> [S.Param]
148 | toParams shape' = map param (controls shape')
149 |
150 | {- | Translate a Tidal 'Sound.Tidal.Stream.Param' into the corresponding MIDI parameter number
151 | according to a specific 'ControllerShape' -}
152 | ctrlN :: Num b => ControllerShape -> S.Param -> Maybe b
153 | ctrlN shape' x = (fromIntegral . midi) <$> (paramN shape' x)
154 |
155 | -- | Find the first 'ControlChange' that uses 'Sound.Tidal.Stream.Param'
156 | paramN :: ControllerShape -> S.Param -> Maybe ControlChange
157 | paramN shape' x
158 | | x `elem` names = paramX $ matching p
159 | | otherwise = Nothing
160 | where names = toParams shape'
161 | paramX [] = Nothing
162 | paramX (h:_) = Just h
163 | matching = filter ((== x) . param)
164 | p = controls shape'
165 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/Device.hs:
--------------------------------------------------------------------------------
1 | {-# OPTIONS_HADDOCK not-home #-}
2 | {-|
3 | Convenience functions to access "Sound.PortMidi" devices.
4 | -}
5 | module Sound.Tidal.MIDI.Device where
6 | import qualified Sound.PortMidi as PM
7 |
8 | {-| Example usage:
9 |
10 | >>> putStrLn =<< displayOutputDevices
11 | ID: Name
12 | 0: Midi Through Port-0
13 | 2: DSI Tetra MIDI 1
14 |
15 | -}
16 | displayOutputDevices :: IO String
17 | displayOutputDevices = do
18 | devices <- getIndexedDevices
19 | return $ displayDevices $ getOutputDevices devices
20 |
21 | -- | Readable version of a list of indexed MIDI devices
22 | displayDevices :: Show a => [(a, PM.DeviceInfo)] -> String
23 | displayDevices devices =
24 | let indices = map (show . fst) devices
25 | names = map ((":\t"++) . PM.name . snd) devices
26 | pairs = zipWith (++) indices names
27 | in unlines ("ID:\tName" : pairs)
28 |
29 | getOutputDevices :: [(a, PM.DeviceInfo)] -> [(a, PM.DeviceInfo)]
30 | getOutputDevices = filter (PM.output . snd)
31 |
32 | getIndexedDevices :: IO [(Integer, PM.DeviceInfo)]
33 | getIndexedDevices = do
34 | rawDevices <- getDevices
35 | return $ zip [0..] rawDevices
36 |
37 | getDevices :: IO [PM.DeviceInfo]
38 | getDevices = do
39 | _ <- PM.initialize
40 | count <- PM.countDevices
41 | mapM PM.getDeviceInfo [0..(count - 1)]
42 |
43 | getIDForDeviceName :: Num a => String -> IO (Maybe a)
44 | getIDForDeviceName name = do
45 | odevs <- fmap getOutputDevices getIndexedDevices
46 | let res = filter (\n -> (PM.name . snd) n == name) odevs
47 | case res of
48 | [] -> return Nothing
49 | [dev] -> return $ Just $ fromIntegral $ fst dev
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/GMPerc.hs:
--------------------------------------------------------------------------------
1 | module Sound.Tidal.MIDI.GMPerc where
2 |
3 | import Control.Applicative
4 | import Sound.Tidal.MIDI.Control
5 | import Sound.Tidal.Params
6 |
7 | gmpercController :: ControllerShape
8 | gmpercController =
9 | ControllerShape
10 | { controls = [mCC balance_p 10, mCC reverb_p 91, mCC chorus_p 93]
11 | , latency = 0.1
12 | }
13 |
14 | perc = midinote . (percN <$>)
15 |
16 | percN :: Num a => String -> a
17 | percN "hq" = 27
18 | percN "sl" = 28
19 | percN "sps" = 29
20 | percN "spl" = 30
21 | percN "st" = 31
22 | percN "sqc" = 32
23 | percN "mcl" = 33
24 | percN "mb" = 34
25 | percN "abd" = 35
26 | percN "bd" = 36
27 | percN "sti" = 37
28 | percN "sn" = 38
29 | percN "cp" = 39
30 | percN "esn" = 40
31 | percN "lft" = 41
32 | percN "ch" = 42
33 | percN "hft" = 43
34 | percN "hh" = 44
35 | percN "lt" = 45
36 | percN "oh" = 46
37 | percN "lmt" = 47
38 | percN "hmt" = 48
39 | percN "cr" = 49
40 | percN "ht" = 50
41 | percN "ri" = 51
42 | percN "cy" = 52
43 | percN "be" = 53
44 | percN "ta" = 54
45 | percN "scy" = 55
46 | percN "cow" = 56
47 | percN "cr2" = 57
48 | percN "vib" = 58
49 | percN "ri2" = 59
50 | percN "hb" = 60
51 | percN "lb" = 61
52 | percN "mhc" = 62
53 | percN "ohc" = 63
54 | percN "lc" = 64
55 | percN "hti" = 65
56 | percN "lti" = 66
57 | percN "hag" = 67
58 | percN "lag" = 68
59 | percN "ca" = 69
60 | percN "ma" = 70
61 | percN "shi" = 71
62 | percN "lhi" = 72
63 | percN "sgui" = 73
64 | percN "lgui" = 74
65 | percN "cl" = 75
66 | percN "hwb" = 76
67 | percN "lwb" = 77
68 | percN "mc" = 78
69 | percN "oc" = 79
70 | percN "mt" = 80
71 | percN "ot" = 81
72 | percN "sha" = 82
73 | percN "jb" = 83
74 | percN "bt" = 84
75 | percN "cas" = 85
76 | percN "ms" = 86
77 | percN "os" = 87
78 | percN _ = 0
79 |
80 | -- general shape for stream
81 | gmperc = toShape gmpercController
82 |
83 | (balance, balance_p) = pF "balance" (Just 0)
84 |
85 | (reverb, reverb_p) = pF "reverb" (Just 0)
86 |
87 | (chorus, chorus_p) = pF "chorus" (Just 0)
88 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/KorgKP3.hs:
--------------------------------------------------------------------------------
1 | module Sound.Tidal.MIDI.KorgKP3 where
2 |
3 | import Sound.Tidal.Params
4 |
5 | import Sound.Tidal.MIDI.Control
6 |
7 | kp3 :: ControllerShape
8 | kp3 =
9 | ControllerShape
10 | { controls =
11 | [ mCC xaxis_p 12
12 | , mCC yaxis_p 13
13 | , mCC padon_p 92
14 | , mCC level_p 93
15 | , mCC fxdepth_p 94
16 | , mCC holdbut_p 95
17 | ]
18 | , latency = 0.1
19 | }
20 |
21 | oscKp3 = toShape kp3
22 |
23 | (xaxis, xaxis_p) = pF "xaxis" (Just 0)
24 |
25 | (yaxis, yaxis_p) = pF "yaxis" (Just 0)
26 |
27 | (padon, padon_p) = pF "padon" (Just 0)
28 |
29 | (level, level_p) = pF "level" (Just 0)
30 |
31 | (fxdepth, fxdepth_p) = pF "fxdepth" (Just 0)
32 |
33 | (holdbut, holdbut_p) = pF "holdbut" (Just 0)
34 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/MBase01.hs:
--------------------------------------------------------------------------------
1 | module Sound.Tidal.MIDI.MBase01 where
2 |
3 | import Sound.Tidal.MIDI.Control
4 | import Sound.Tidal.Params
5 |
6 | mbase01Controller :: ControllerShape
7 | mbase01Controller =
8 | ControllerShape
9 | { controls =
10 | [ mCC tune_p 100
11 | , mCC pitch_p 101
12 | , mCC decay_p 102
13 | , mCC harmonics_p 103
14 | , mCC pulse_p 104
15 | , mCC noise_p 105
16 | , mCC attack_p 106
17 | , mCC eqlzr_p 107
18 | ]
19 | , latency = 0.1
20 | }
21 |
22 | mbase01 = toShape mbase01Controller
23 |
24 | (tune, tune_p) = pF "tune" (Just 0)
25 |
26 | (pitch, pitch_p) = pF "pitch" (Just 0)
27 |
28 | (harmonics, harmonics_p) = pF "harmonics" (Just 0)
29 |
30 | (pulse, pulse_p) = pF "pulse" (Just 0)
31 |
32 | (noise, noise_p) = pF "noise" (Just 0)
33 |
34 | (eqlzr, eqlzr_p) = pF "eqlzr" (Just 0)
35 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/MiniAtmegatron.hs:
--------------------------------------------------------------------------------
1 | {-|
2 | miniAtmegatron - Soulsby Synthesizers
3 |
4 | http://soulsbysynths.com/wp-content/uploads/2016/08/Mini-Manual.pdf, page 15
5 |
6 | -}
7 | module Sound.Tidal.MIDI.MiniAtmegatron where
8 |
9 | import Sound.Tidal.MIDI.Control
10 | import Sound.Tidal.Params
11 |
12 | matmController :: ControllerShape
13 | matmController =
14 | ControllerShape
15 | { controls =
16 | [ mCC modwheel_p 1
17 | , mCC pan_p 10
18 | , mCC expression_p 11
19 | , mCC sustainpedal_p 64
20 | , mCC cutoff_p 74
21 | , mCC filtenv_p 16
22 | , mCC flfo_p 93
23 | , mCC alfo_p 92
24 | , mCC shape_p 17
25 | , mCC resonance_p 71
26 | , mCC penv_p 94
27 | , mCC plfo_p 1
28 | , mCC pwm_p 91
29 | , mCC flange_p 95
30 | , mCC fwave_p 30
31 | , mCC ffilt_p 31
32 | , mCC ffenv_p 32
33 | , mCC faenv_p 33
34 | , mCC mlfoshape_p 34
35 | , mCC lfospeed_p 79
36 | , mCC porta_p 5
37 | ]
38 | , latency = 0.1
39 | }
40 |
41 | matm = toShape matmController
42 |
43 | (fen, filtenv_p) = pF "fen" (Just 0)
44 |
45 | (flo, flfo_p) = pF "flo" (Just 0)
46 |
47 | (alo, alfo_p) = pF "alo" (Just 0)
48 |
49 | (pen, penv_p) = pF "pen" (Just 0)
50 |
51 | (plo, plfo_p) = pF "plo" (Just 0)
52 |
53 | (pwm, pwm_p) = pF "pwm" (Just 0)
54 |
55 | (fln, flange_p) = pF "fln" (Just 0)
56 |
57 | (fwv, fwave_p) = pF "fwv" (Just 0)
58 |
59 | (ffl, ffilt_p) = pF "ffl" (Just 0)
60 |
61 | (ffe, ffenv_p) = pF "ffe" (Just 0)
62 |
63 | (fae, faenv_p) = pF "fae" (Just 0)
64 |
65 | (lfs, mlfoshape_p) = pF "lfs" (Just 0)
66 |
67 | (lss, lfospeed_p) = pF "lss" (Just 0)
68 |
69 | (por, porta_p) = pF "por" (Just 0)
70 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/Minilogue.hs:
--------------------------------------------------------------------------------
1 | module Sound.Tidal.MIDI.Minilogue where
2 |
3 | import Sound.Tidal.Params
4 | import Sound.Tidal.MIDI.Control
5 |
6 | minilogueController :: ControllerShape
7 | minilogueController = ControllerShape { controls = [
8 | mCC vco1_pitch_p 2,
9 | mCC vco2_pitch_p 3,
10 | mCC vco1_shape_p 4,
11 | mCC vco2_shape_p 5,
12 | mCC vco1_level_p 7,
13 | mCC vco2_level_p 8,
14 | mCC noise_p 1,
15 | mCC cross_mod_depth_p 9,
16 | mCC pitch_eg_int_p 10,
17 | mCC cutoff_p 11,
18 | mCC resonance_p 12,
19 | mCC filter_eg_int_p 13,
20 | mCC amp_attack_p 16,
21 | mCC amp_decay_p 17,
22 | mCC amp_sustant_p 18,
23 | mCC amp_release_p 19,
24 | mCC eg_attack_p 20,
25 | mCC eg_decay_p 21,
26 | mCC eg_sustant_p 22,
27 | mCC eg_release_p 23,
28 | mCC lfo_rate_p 24,
29 | mCC lfo_depth_p 25,
30 | mCC voice_depth_p 27,
31 | mCC delay_cutoff_p 29,
32 | mCC delay_time_p 30,
33 | mCC delay_feedback_p 31,
34 | mCC vco1_octave_p 64,
35 | mCC vco2_octave_p 65,
36 | mCC vco1_wave_p 66,
37 | mCC vco2_wave_p 67,
38 | mCC sync_p 80,
39 | mCC ring_p 81,
40 | mCC velocity_p 82,
41 | mCC key_track_p 83,
42 | mCC filter_type_p 84,
43 | mCC delay_output_routing_p 88,
44 | mCC lfo_target_p 90,
45 | mCC lfo_amount_p 91,
46 | mCC lfo_wave_p 92
47 | ],
48 | --duration = ("dur", 0.05),
49 | --velocity = ("vel", 0.5),
50 | latency = 0.1
51 | }
52 |
53 | minilogue = toShape minilogueController
54 |
55 | (vco1_pitch, vco1_pitch_p) = pF "vco1_pitch" (Just 0)
56 | (vco2_pitch, vco2_pitch_p) = pF "vco2_pitch" (Just 0)
57 | (vco1_shape, vco1_shape_p) = pF "vco1_shape" (Just 0)
58 | (vco2_shape, vco2_shape_p) = pF "vco2_shape" (Just 0)
59 | (vco1_level, vco1_level_p) = pF "vco1_level" (Just 0)
60 | (vco2_level, vco2_level_p) = pF "vco2_level" (Just 0)
61 | (noise, noise_p) = pF "noise" (Just 0)
62 | (cross_mod_depth, cross_mod_depth_p) = pF "cross_mod_depth" (Just 0)
63 | (pitch_eg_int, pitch_eg_int_p) = pF "pitch_eg_int" (Just 0)
64 | --(cutoff, cutoff_p) = pF "cutoff" (Just 0)
65 | --(resonance, resonance_p) = pF "resonance" (Just 0)
66 | (filter_eg_int, filter_eg_int_p) = pF "filter_eg_int" (Just 0)
67 | (amp_attack, amp_attack_p) = pF "amp_attack" (Just 0)
68 | (amp_decay, amp_decay_p) = pF "amp_decay" (Just 0)
69 | (amp_sustant, amp_sustant_p) = pF "amp_sustant" (Just 0)
70 | (amp_release, amp_release_p) = pF "amp_release" (Just 0)
71 | (eg_attack, eg_attack_p) = pF "eg_attack" (Just 0)
72 | (eg_decay, eg_decay_p) = pF "eg_decay" (Just 0)
73 | (eg_sustant, eg_sustant_p) = pF "eg_sustant" (Just 0)
74 | (eg_release, eg_release_p) = pF "eg_release" (Just 0)
75 | (lfo_rate, lfo_rate_p) = pF "lfo_rate" (Just 0)
76 | (lfo_depth, lfo_depth_p) = pF "lfo_depth" (Just 0)
77 | (voice_depth, voice_depth_p) = pF "voice_depth" (Just 0)
78 | (delay_cutoff, delay_cutoff_p) = pF "delay_cutoff" (Just 0)
79 | (delay_time, delay_time_p) = pF "delay_time" (Just 0)
80 | (delay_feedback, delay_feedback_p) = pF "delay_feedback" (Just 0)
81 | (vco1_octave, vco1_octave_p) = pF "vco1_octave" (Just 0)
82 | (vco2_octave, vco2_octave_p) = pF "vco2_octave" (Just 0)
83 | (vco1_wave, vco1_wave_p) = pF "vco1_wave" (Just 0)
84 | (vco2_wave, vco2_wave_p) = pF "vco2_wave" (Just 0)
85 | (sync, sync_p) = pF "sync" (Just 0)
86 | (ring, ring_p) = pF "ring" (Just 0)
87 | --(velocity, velocity_p) = pF "velocity" (Just 0)
88 | (key_track, key_track_p) = pF "key_track" (Just 0)
89 | (filter_type, filter_type_p) = pF "filter_type" (Just 0)
90 | (delay_output_routing, delay_output_routing_p) = pF "delay_output_routing" (Just 0)
91 | (lfo_target, lfo_target_p) = pF "lfo_target" (Just 0)
92 | (lfo_amount, lfo_amount_p) = pF "lfo_amount" (Just 0)
93 | (lfo_wave, lfo_wave_p) = pF "lfo_wave" (Just 0)
94 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/Output.hs:
--------------------------------------------------------------------------------
1 | {-# OPTIONS_HADDOCK not-home #-}
2 | {-|
3 | A bridge between evaluated Tidal patterns and MIDI events.
4 |
5 | This module contains functions necessary to mediate between
6 | 'Sound.Tidal.Time.Event's generated from a Tidal 'Sound.Tidal.Pattern.Pattern'
7 | and plain MIDI events sent through 'Sound.PortMidi.PMStream'.
8 | -}
9 | module Sound.Tidal.MIDI.Output (
10 | -- * Types
11 | Output(..),
12 | OutputState,
13 | MidiDeviceMap,
14 | TimedNote,
15 | -- * Initialization
16 | makeConnection,
17 | flushBackend,
18 | -- * Scheduling
19 | sendevents,
20 | store,
21 | mkStore,
22 | storeParams,
23 | scheduleTime,
24 | -- * Converters
25 | toMidiValue,
26 | cutShape,
27 | stripDefaults,
28 | -- * State handling
29 | changeState,
30 | readState,
31 | -- * Low-level functions
32 | useOutput,
33 | displayOutputDevices,
34 | outputDevice,
35 | makeRawEvent,
36 | noteOn,
37 | noteOff,
38 | makeCtrl
39 | ) where
40 |
41 | -- generics
42 | import Control.Applicative ((<$>), (<*>), pure)
43 | import Control.Monad
44 | import Control.Concurrent
45 | import Control.Concurrent.MVar ()
46 | import Data.Bits
47 | import Data.List (sortBy, find, partition)
48 | import qualified Data.Map as Map
49 | import Data.Maybe
50 | import Data.Ord (comparing)
51 | import Data.Ratio (Ratio)
52 | import Data.Time (getCurrentTime, UTCTime)
53 | import Data.Time.Clock.POSIX
54 | import Foreign.C
55 | import Numeric
56 |
57 | -- Tidal specific
58 | import Sound.Tidal.Tempo (Tempo(Tempo))
59 | import Sound.Tidal.Stream as S
60 |
61 | -- MIDI specific
62 | import Sound.Tidal.MIDI.Device
63 | import Sound.Tidal.MIDI.Control
64 | import qualified Sound.PortMidi as PM
65 |
66 | type ConnectionCount = Int
67 | type TickedConnectionCount = Int
68 | type OutputOnline = Bool
69 | {- |
70 | Keep track of virtual streams
71 |
72 | * Reflects the number of virtual streams that have already stored their events for this tick. Every time 'TickedConnectionCount' cycles, MIDI events will be sent out.
73 | * 'ConnectionCount' is increased on every new stream created via `midiSetters`
74 | * For each channel, currently used params and their values are kept.
75 | * Output will only be scheduling, once __online__, i.e. when the first stream is initialized
76 | -}
77 | type OutputState = (
78 | TickedConnectionCount,
79 | ConnectionCount,
80 | [ParamMap],
81 | OutputOnline
82 | )
83 |
84 | type Tick = Int
85 | type Onset = Double
86 | type Offset = Double
87 | type RelativeOffset = Double
88 | type MIDITime = (Tempo, Tick, Onset, RelativeOffset)
89 | type MIDIEvent = (MIDITime, MIDIMessage)
90 | type MIDIChannel = CLong
91 | type MIDIStatus = CLong
92 | type MIDINote = MIDIDatum
93 | type MIDIVelocity = MIDIDatum
94 | type MIDIDatum = CLong
95 | type MIDIDuration = Ratio Integer
96 | type MIDIMessage = (MIDIChannel, MIDIStatus, MIDINote, MIDIVelocity)
97 | -- | A Triplet of the deviation from the note @a5@, velocity and duration
98 | type TimedNote = (CLong, MIDIVelocity, MIDIDuration)
99 | type SentEvent = (CULong, Double, PM.PMEvent, CULong, UTCTime)
100 | {-|
101 | An abstract definition of a physical MIDI Output.
102 |
103 | Manages virtual streams to multiple channels of a single connection to a MIDI device.
104 | -}
105 | data Output = Output {
106 | cshape :: ControllerShape, -- ^ The ControllerShape defining which 'Param's will be available for use
107 | conn :: PM.PMStream, -- ^ The physical connection to the device, uses 'PortMidi'
108 | buffer :: MVar ([ParamMap], [MIDIEvent]), -- ^ A buffer of currently used 'Param's and their 'Value's as well as a list of 'MIDIEvent's to be sent on the next tick.
109 | bufferstate :: MVar OutputState, -- ^ Keeps track of connected virtual streams during one tick
110 | midistart :: CULong, -- ^ the MIDI time when this output was created
111 | rstart :: UTCTime -- ^ the real time when this output was created
112 | }
113 |
114 | type MidiMap = Map.Map S.Param (Maybe Int)
115 | type MidiDeviceMap = Map.Map String Output
116 |
117 |
118 | -- | Initialize a connection to the given MIDI device by Name
119 | makeConnection :: MVar MidiDeviceMap -- ^ The current list of already connected devices
120 | -> String -- ^ The MIDI device name
121 | -> Int -- ^ The MIDI channel
122 | -> ControllerShape -- ^ The definition of useable 'Control's
123 | -> IO (S.ToMessageFunc, Output) -- ^ A function to schedule MIDI events and the output that keeps track of connections
124 | makeConnection devicesM displayname channel controllershape = do
125 | moutput <- useOutput devicesM displayname controllershape
126 | case moutput of
127 | Just o -> do
128 | s <- connected channel displayname o
129 | return (s, o)
130 | Nothing ->
131 | error "Failed initializing MIDI connection"
132 |
133 |
134 | {- |
135 | Sends out MIDI events once all virtual streams have buffered their events.
136 |
137 | This will be called after every tick
138 | -}
139 | flushBackend :: Output -> S.Shape -> Tempo -> Int -> IO ()
140 | flushBackend o shape change ticks = do
141 | changeState tickConnections o
142 | cycling <- readState isCycling o
143 |
144 | Control.Monad.when cycling (do
145 | -- gather last sent params, update state with new
146 | let buf = buffer o
147 | (states, events) <- takeMVar buf
148 |
149 | ((_,_,newstates,_), (_,_,oldstates,_)) <- changeState' (resetParamStates states) o
150 |
151 | -- find params that were removed
152 | let mapDefaults = Map.mapWithKey (\k _ -> defaultValue k)
153 | diffs = map mapDefaults $ zipWith Map.difference oldstates newstates
154 | -- store additional "reset" events in buffer
155 | -- schedule time must be exactly before/ontime with the next regular event to be sent. otherwise we risk
156 | -- mixing order of ctrl messages, and resets get overridden
157 | -- FIXME: when scheduling, note late CC messages and DROP THEM, otherwise everything is screwed
158 | let offset = S.latency shape
159 | mididiffs = map ((toMidiMap (cshape o)).(stripShape (toShape $ cshape o))) $ diffs
160 | resetevents = concat $ zipWith (\x y -> makectrls o x (change,ticks,1,offset) y) [1..] mididiffs
161 |
162 | -- send out MIDI events
163 | (late, later) <- sendevents o shape change ticks events resetevents
164 | -- finally clear buffered ParamMap for next tick
165 | putMVar buf (replicate 16 Map.empty, later)
166 | let len = length late
167 | case len of
168 | 0 ->
169 | return ()
170 | _ -> do
171 | putStrLn $ showLate $ head late
172 | putStrLn $ "and " ++ show (len - 1) ++ " more")
173 |
174 |
175 | -- Scheduling
176 |
177 | {- |
178 | Sends out MIDI events due for this tick.
179 | -}
180 | sendevents :: Output -- ^ The connection to be used
181 | -> S.Shape -- ^ The shape to be queried for latency
182 | -> Tempo -- ^ The current speed
183 | -> Tick -- ^ The number of ticks elapsed since start, may be reset when using @cps (-1)@
184 | -> [MIDIEvent] -- ^ A list of events potentially needed to be sent
185 | -> [MIDIEvent] -- ^ A list of reset events potentially needed to be sent
186 | -> IO ([SentEvent], [MIDIEvent]) -- ^ A list of events sent late and a list of events to send later
187 | sendevents _ _ _ _ [] [] = return ([],[])
188 | sendevents s shape change ticks evts resets = do
189 | -- assumptions:
190 | -- all reset events have the same timestamp
191 | -- questions:
192 | -- could there be any events in `evts` at all that need reset? or are these just in late from the last tick?
193 | let output = conn s
194 | toDescriptor midiTime now (o,_,t,e) = (o,t,e, midiTime, now)
195 | calcOnsets (a@(tempo, tick, onset, offset), e) = (a, logicalOnset' tempo tick onset offset, e)
196 |
197 | midiTime <- PM.time
198 | now <- getCurrentTime
199 | let offset = S.latency shape
200 | nextTick = logicalOnset' change (ticks+1) 0 offset
201 | mkEvent (t, o, e) = (midionset, t, o, makeRawEvent e midionset)
202 | where midionset = scheduleTime (midistart s, rstart s) o
203 | onsets = map calcOnsets evts
204 | -- calculate temporary scheduling for resetevts
205 | resetevts = map calcOnsets resets
206 | -- split into events sent now and later (e.g. a noteOff that would otherwise cut off noteOn's in the next tick)
207 | (evts', later) = span ((< nextTick).(\(_,o,_) -> o)) $ sortBy (comparing (\(_,o,_) -> o)) onsets
208 | -- calculate MIDI time to schedule events, putting time into fn to create PM.PMEvents
209 | evts'' = map mkEvent evts'
210 | -- a list CC `names` that need to be reset
211 | resetccs = map (\(_, _, (_, _, d1, _)) -> d1) resetevts
212 | later' = map (\(t,_,e) -> (t,e)) later
213 | findCC match list = find (\(_, _, (_, st, d1, _)) -> st == 0xB0 && (d1 `elem` match)) $ reverse list
214 |
215 |
216 | -- 1. find the ccs that needs reset (search in `later` then in `evts`)
217 | (evtstosend, laterevts) = case findCC resetccs later of
218 | Nothing -> case findCC resetccs evts' of
219 | -- 1c. no events at all need to be reset
220 | -- 1cI. use the default passed in midionset for resets
221 | -- 1cII. append `resets` to `evts` FIXME: make sure we really do by timing
222 | -- 1cIII. send `evts`
223 | Nothing -> (evts'' ++ map mkEvent resetevts, later')
224 | -- 1b. only `evts` contain a CC to be reset
225 | -- 1bI. set scheduletime for reset __after__ the latest CC that needs to be reset in `evts`
226 | -- 1bII. add `resets` to `evts`
227 | -- 1bIII. send `evts`
228 | Just (_, latestO, _) -> (before ++
229 | map (
230 | \(t, o, e) ->
231 | let midionset = scheduleTime (midistart s, rstart s) latestO
232 | in (midionset, t,o,makeRawEvent e midionset)
233 | ) resetevts ++ after, later')
234 | where
235 | (before, after) = partition (\(m,_,o,_) -> m > scheduleTime (midistart s, rstart s) o) evts''
236 |
237 | -- 1a. `later` contains a cc to be reset, (omit searching in evts)
238 | -- 1aI. set scheduletime for reset __after__ the latest CC that needs to be reset in `later`
239 | -- 1aII. add `resetevts` to `later`
240 | -- 1aIII. send `evts`
241 | Just (latestT, _, _) -> (evts'', later' ++ map (\(_, _, e) -> (latestT, e)) resetevts)
242 | evtstosend' = map (\(_,_,_,e) -> e) evtstosend
243 | -- filter events that are too late
244 | late = map (toDescriptor midiTime now) $ filter (\(_,_,t,_) -> t < realToFrac (utcTimeToPOSIXSeconds now)) evtstosend
245 | -- drop late CC events to avoid glitches
246 | -- evtstosend'' = map (\(_,_,e,_,_) -> e) $ filter (not.isCC) late
247 | -- write events for this tick to stream
248 | err <- PM.writeEvents output evtstosend'
249 |
250 | case err of
251 | PM.NoError -> return (late, laterevts) -- return events for logging in outer scope
252 | e -> do
253 | putStrLn ("sending failed: " ++ show e)
254 | return (late, laterevts)
255 |
256 | isCC :: SentEvent -> Bool
257 | isCC (_,_,e,_,_) = (0x0f .&. cc) == 0xB0
258 | where
259 | cc = PM.status $ PM.decodeMsg $ PM.message $ e
260 |
261 |
262 |
263 | -- | Buffer a single tick's MIDI events for a single channel of a single connection
264 | store :: Output -> Int -> Tempo -> Tick -> Onset -> Offset -> MidiMap -> ParamMap -> IO ()
265 | store s ch change tick on off ctrls note = storemidi s ch' note' (change, tick, on, offset) ctrls
266 | where
267 | (note', nudge) = computeTiming' change on off note
268 | ch' = fromIntegral ch
269 | cshape' = cshape s
270 | offset = Sound.Tidal.MIDI.Control.latency cshape' + nudge
271 |
272 | {- |
273 | Returns a function to be called on every tick,
274 | splits the given @ParamMap@ into MIDI note information
275 | and CCs.
276 | -}
277 | mkStore :: Int -> Output -> IO ToMessageFunc
278 | mkStore channel s = return $ \ shape change tick (on,off,m) -> do
279 | let ctrls = cutShape shape m
280 | props = cutShape midiShape m
281 | ctrls' = stripDefaults ctrls
282 | ctrls'' = toMidiMap (cshape s) <$> ctrls'
283 | store' = store s channel change tick on off <$> ctrls''
284 | -- store even non-midi params, otherwise removing last ctrl results in a missing reset since diff in `flushBackend` would be empty
285 | -- then buffer ctrl messages to be sent
286 | -- with the appropriate note properties
287 | ($) <$> (storeParams s channel <$> stripDefaults (applyShape' shape m)) <*> (($) <$> store' <*> props)
288 |
289 |
290 | -- | Union the currently stored paramstate for certain channel with the given one
291 | storeParams :: Output -> Int -> ParamMap -> IO () -> IO ()
292 | storeParams o ch m action = do
293 | modifyMVar_ (buffer o) $ \(states, events) -> do
294 | let (before,current:after) = splitAt (ch - 1) states
295 | state' = Map.union m current
296 | states' = before ++ [state'] ++ after
297 | return (states', events)
298 | action
299 |
300 | -- | Thin wrapper around @computeTiming@ to convert onset/offset into onset/duration relative
301 | computeTiming' :: Tempo -> Double -> Double -> ParamMap -> (TimedNote, Double)
302 | computeTiming' tempo on off note = ((fromIntegral n, fromIntegral v, d), nudge)
303 | where
304 | ((n,v,d), nudge) = computeTiming tempo (realToFrac (off - on) / S.ticksPerCycle) note
305 |
306 | {- | Schedule sending all CC's default values.
307 | Produces an `onTick` handler.
308 | -}
309 | connected :: Int -> String -> Output -> IO ToMessageFunc
310 | connected channel displayname s = do
311 | let cshape' = cshape s
312 | shape = toShape $ cshape s
313 | defaultParams = S.defaultMap shape
314 | allctrls = toMidiMap cshape' defaultParams
315 | putStrLn ("Successfully initialized Device '" ++ displayname ++ "'")
316 | changeState goOnline s
317 | now <- getCurrentTime
318 | _ <- storeevents s $ makectrls s (fromIntegral channel) (Tempo now 0 1 False 0,0,0,0) allctrls
319 | mkStore channel s
320 |
321 | -- State handling
322 |
323 | readState :: (OutputState -> b) -> Output -> IO b
324 | readState f o = do
325 | s <- readMVar $ bufferstate o
326 |
327 | return $ f s
328 |
329 | isCycling :: OutputState -> Bool
330 | isCycling (0, _, _, True) = True
331 | isCycling _ = False
332 |
333 | -- displayState :: OutputState -> String
334 | -- displayState (ticked, conns, paramstate, online) = show ticked ++ "/" ++ show conns ++ "[" ++ show online ++ "]" ++ " active params: " ++ show paramstate
335 |
336 | changeState :: (OutputState -> OutputState) -> Output -> IO ()
337 | changeState f o = do
338 | _ <- changeState' f o
339 | return ()
340 |
341 | changeState' :: (OutputState -> OutputState) -> Output -> IO (OutputState, OutputState)
342 | changeState' f o = do
343 | bs <- takeMVar stateM
344 | let fs = f bs
345 | putMVar stateM fs
346 | return (fs, bs)
347 | where
348 | stateM = bufferstate o
349 |
350 | -- | Params in use get overwritten by new ones, except if new ones means _no params_, in this case keep old
351 | resetParamStates :: [ParamMap] -> OutputState -> OutputState
352 | resetParamStates newstates (ticked, conns, paramstates, online) = (ticked, conns, zipWith resetParamState newstates paramstates, online)
353 |
354 | resetParamState :: ParamMap -> ParamMap -> ParamMap
355 | resetParamState newstate currentstate
356 | | Map.empty == newstate = currentstate -- updating with an empty state is a noop
357 | | otherwise = newstate
358 |
359 | goOnline :: OutputState -> OutputState
360 | goOnline (ticked, conns, paramstate, _) = (ticked, conns, paramstate, True)
361 |
362 | addConnection :: OutputState -> OutputState
363 | addConnection (ticked, conns, paramstate, online) = (ticked, conns + 1, paramstate, online)
364 |
365 | tickConnections :: OutputState -> OutputState
366 | tickConnections (ticked, conns, paramstate, online) = ((ticked + 1) `mod` conns, conns, paramstate, online)
367 |
368 | -- | open named MIDI output or use cached (PortMIDI doesn't like opening two connections to the same device!)
369 | useOutput :: MVar MidiDeviceMap -> String -> ControllerShape -> IO (Maybe Output)
370 | useOutput outsM displayname controllershape = do
371 | outs <- readMVar outsM -- blocks
372 | let outM = Map.lookup displayname outs -- maybe
373 | -- if we have a valid output by now, return
374 | case outM of
375 | Just o -> do
376 | putStrLn "Cached Device Output"
377 | changeState addConnection o -- blocks
378 | return $ Just o
379 | Nothing -> do
380 | -- otherwise open a new output and store the result in the mvar
381 | devidM <- (>>= maybe (failed displayname "Failed opening MIDI Output Device ID") return) (getIDForDeviceName displayname)
382 | econn <- outputDevice devidM 1 controllershape -- either
383 | case econn of
384 | Left o -> do
385 | changeState addConnection o
386 | _ <- swapMVar outsM $ Map.insert displayname o outs
387 | return $ Just o
388 | Right _ -> return Nothing
389 |
390 |
391 | -- | Turn logicalOnset into MIDITime
392 | scheduleTime :: (CULong, UTCTime)-> Double -> CULong
393 | scheduleTime (mstart', rstart') logicalOnset = (+) mstart $ floor $ 1000 * (logicalOnset - rstart'')
394 | where
395 | rstart'' = realToFrac $ utcTimeToPOSIXSeconds rstart'
396 | mstart = fromIntegral mstart'
397 |
398 | -- Converters
399 |
400 | {-|
401 | Convert a @Param@'s @Value@ into a MIDI consumable datum.
402 |
403 | Applies range mapping and scaling functions according to @ControllerShape@
404 | -}
405 | toMidiValue :: ControllerShape -> S.Param -> Value -> Maybe Int
406 | toMidiValue s p (VF x) = ($) <$> mscale <*> mrange <*> pure x
407 | where
408 | mrange = fmap range mcc
409 | mscale = fmap scalef mcc
410 | mcc = paramN s p
411 | toMidiValue _ _ (VI x) = Just x
412 | toMidiValue _ _ (VS _) = Nothing -- ignore strings for now, we might 'read' them later
413 |
414 | -- | Translates generic params into midi params
415 | toMidiMap :: ControllerShape -> S.ParamMap -> MidiMap
416 | toMidiMap s m = Map.mapWithKey (toMidiValue s) m
417 |
418 | -- | Keep only params that are in a given shape, replace missing with defaults
419 | cutShape :: S.Shape -> ParamMap -> Maybe ParamMap
420 | cutShape s m = flip Map.intersection (S.defaultMap s) <$> S.applyShape' s m
421 |
422 | -- | Keep only params that are in a given shape
423 | stripShape :: S.Shape -> ParamMap -> ParamMap
424 | stripShape s = Map.intersection p'
425 | where
426 | p' = S.defaultMap s
427 |
428 | -- | Keep only params that are explicitly set (i.e. not default)
429 | stripDefaults :: Maybe ParamMap -> Maybe ParamMap
430 | stripDefaults m = Map.filterWithKey (\k v -> v /= defaultValue k) <$> m
431 |
432 |
433 | -- Event creation
434 |
435 | -- FIXME: throws if param cannot be found
436 | makectrls :: Output -> MIDIChannel -> MIDITime -> MidiMap -> [MIDIEvent]
437 | makectrls o ch t ctrls = concatMap (\(param', ctrl) -> makeCtrl ch (fromJust $ paramN shape param') (fromIntegral ctrl) t) ctrls'
438 | where
439 | shape = cshape o
440 | ctrls' = filter ((>=0) . snd) $ Map.toList $ Map.mapMaybe id ctrls
441 |
442 | makenote :: MIDIChannel -> TimedNote -> MIDITime -> [MIDIEvent]
443 | makenote ch (note,vel,dur) (tempo,tick,onset,offset) = noteon' ++ noteoff'
444 | where
445 | noteon' = noteOn ch midinote vel (tempo,tick,onset,offset)
446 | noteoff' = noteOff ch midinote (tempo,tick,onset,offset + fromRational dur)
447 | midinote = note + 60
448 |
449 | makemidi :: Output -> MIDIChannel -> TimedNote -> MIDITime -> MidiMap -> [MIDIEvent]
450 | makemidi o ch (128,_,_) t ctrls = makectrls o ch t ctrls -- HACK: to send only CC use (n + 60) == 128
451 | makemidi o ch note t ctrls = makectrls o ch t ctrls ++ makenote ch note t
452 |
453 | -- Event buffering
454 | storemidi :: Output -> MIDIChannel -> TimedNote -> MIDITime -> MidiMap -> IO ()
455 | storemidi o ch n t ctrls = do
456 | _ <- storeevents o $ makemidi o ch n t ctrls
457 | return ()
458 |
459 |
460 | makeEvent :: MIDIStatus -> MIDINote -> MIDIChannel -> MIDIVelocity -> MIDITime -> MIDIEvent
461 | makeEvent st n ch v t = (t, msg)
462 | where
463 | msg = (ch, st, n, v)
464 |
465 | storeevents :: Output -> [MIDIEvent] -> IO (Maybe a)
466 | storeevents o evts = do
467 | let buf = buffer o
468 | (paramstate, cbuf) <- takeMVar buf
469 | putMVar buf (paramstate, cbuf ++ evts)
470 | return Nothing
471 |
472 | -- Misc helpers
473 |
474 | showLate :: SentEvent -> String
475 | showLate (o, t, e, m, n) =
476 | unwords ["late",
477 | show $ (\x -> [PM.status x, PM.data1 x, PM.data2 x]) $ PM.decodeMsg $ PM.message e,
478 | "midi now ", show m, " midi onset: ", show o,
479 | "onset (relative): ", show $ showFFloat (Just 3) (t - realToFrac (utcTimeToPOSIXSeconds n)) "",
480 | ", sched: ", show $ PM.timestamp e]
481 |
482 | showEvent :: PM.PMEvent -> String
483 | showEvent e = show t ++ " " ++ show msg
484 | where msg = PM.decodeMsg $ PM.message e
485 | t = PM.timestamp e
486 |
487 | showRawEvent :: (CULong, MIDITime, Double, PM.PMEvent) -> String
488 | showRawEvent (_, (_,_,onset,offset), logicalOnset, e) = "(" ++ show onset ++ "," ++ show offset ++ ") / " ++ show logicalOnset ++ " " ++ showEvent e
489 |
490 | failed :: (Show a, Show b) => a -> b -> c
491 | failed di err = error (show err ++ ": " ++ show di)
492 |
493 |
494 | ---------------
495 | -- LOW LEVEL --
496 | ---------------
497 |
498 | -- MIDI Event wrapping
499 | makeRawEvent :: MIDIMessage -> CULong -> PM.PMEvent
500 | makeRawEvent (ch, st, n, v) = PM.PMEvent msg
501 | where msg = PM.encodeMsg $ PM.PMMsg (encodeChannel ch st) n v
502 |
503 |
504 | -- MIDI Utils
505 | encodeChannel :: MIDIChannel -> MIDIStatus -> CLong
506 | encodeChannel ch cc = (-) ch 1 .|. cc
507 |
508 |
509 | -- MIDI Messages
510 | noteOn :: MIDIChannel -> MIDINote -> MIDIVelocity -> MIDITime -> [MIDIEvent]
511 | noteOn ch val vel t = [makeEvent 0x90 val ch vel t]
512 |
513 | noteOff :: MIDIChannel -> MIDINote -> MIDITime -> [MIDIEvent]
514 | noteOff ch val t = [makeEvent 0x80 val ch 60 t]
515 |
516 | makeCtrl :: MIDIChannel -> ControlChange -> MIDIDatum -> MIDITime -> [MIDIEvent]
517 | makeCtrl ch CC {midi=midi'} n t = makeCC ch (fromIntegral midi') n t -- FIXME: no SysEx support right now
518 | makeCtrl ch NRPN {midi=midi'} n t = makeNRPN ch (fromIntegral midi') n t
519 |
520 | makeCC :: MIDIChannel -> MIDIDatum -> MIDIDatum -> MIDITime -> [MIDIEvent]
521 | makeCC ch c n t = [makeEvent 0xB0 c ch n t]
522 |
523 | makeNRPN :: MIDIChannel -> MIDIDatum -> MIDIDatum -> MIDITime -> [MIDIEvent]
524 | makeNRPN ch c n t = [
525 | nrpn 0x63 ch (shift (c .&. 0x3F80) (-7)) t,
526 | nrpn 0x62 ch (c .&. 0x7F) t,
527 | nrpn 0x06 ch (shift (n .&. 0x3F80) (-7)) t,
528 | nrpn 0x26 ch (n .&. 0x7F) t
529 | ]
530 | where
531 | nrpn = makeEvent 0xB0
532 |
533 |
534 | -- | Creates an 'Output' wrapping a PortMidi device
535 | outputDevice :: PM.DeviceID -> Int -> ControllerShape -> IO (Either Output PM.PMError)
536 | outputDevice deviceID latency' shape = do
537 | _ <- PM.initialize
538 | result <- PM.openOutput deviceID latency'
539 | bs <- newMVar (0, 0, replicate 16 Map.empty, False)
540 | case result of
541 | Left dev ->
542 | do
543 | info <- PM.getDeviceInfo deviceID
544 | time <- getCurrentTime
545 | mstart <- PM.time
546 | putStrLn ("Opened: " ++ show (PM.interface info) ++ ": " ++ show (PM.name info))
547 | b <- newMVar (replicate 16 Map.empty, [])
548 |
549 | return (Left Output { cshape=shape, conn=dev, buffer=b, bufferstate=bs, midistart=mstart, rstart=time })
550 | Right err -> return (Right err)
551 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/Prophet08.hs:
--------------------------------------------------------------------------------
1 | module Sound.Tidal.MIDI.Prophet08 where
2 |
3 | import Sound.Tidal.Params
4 | import Sound.Tidal.MIDI.Control
5 |
6 | prophetController :: ControllerShape
7 | prophetController = ControllerShape { controls = [
8 | mCC osc1_frequency_p 20,
9 | mCC osc1_freq_fine_p 21,
10 | mCC osc1_shape_p 22,
11 | mCC osc1_glide_p 23,
12 | mCC osc2_frequency_p 24,
13 | mCC osc2_freq_fine_p 25,
14 | mCC osc2_shape_p 26,
15 | mCC osc2_glide_p 27,
16 | mCC osc_mix_p 28,
17 | mCC noise_p 29,
18 | mCC filter_frequency_p 102,
19 | mCC resonance_p 103,
20 | mCC filter_key_amt_p 104,
21 | mCC filter_audio_mod_p 105,
22 | mCC filter_env_amt_p 106,
23 | mCC filter_env_vel_amt_p 107,
24 | mCC filter_delay_p 108,
25 | mCC filter_attack_p 109,
26 | mCC filter_decay_p 110,
27 | mCC filter_sustain_p 111,
28 | mCC filter_release_p 112 ,
29 | mCC vca_level_p 113,
30 | mCC pan_spread_p 114,
31 | mCC amp_env_amt_p 115,
32 | mCC amp_velocity_amt_p 116,
33 | mCC amp_delay_p 117,
34 | mCC amp_attack_p 118,
35 | mCC amp_decay_p 119,
36 | mCC amp_sustain_p 75,
37 | mCC amp_release_p 76,
38 | mCC env3_destination_p 85,
39 | mCC env3_amt_p 86,
40 | mCC env3_velocity_amt_p 87,
41 | mCC env3_delay_p 88,
42 | mCC env3_attack_p 89,
43 | mCC env3_decay_p 90,
44 | mCC env3_sustain_p 77,
45 | mCC env3_release_p 78,
46 | mCC bpm_p 14,
47 | mCC clock_divide_p 15
48 | ],
49 | --duration = ("dur", 0.05),
50 | --velocity = ("vel", 0.5),
51 | latency = 0.1
52 | }
53 |
54 | prophet = toShape prophetController
55 |
56 | (osc1_frequency, osc1_frequency_p) = pF "osc1_frequency" (Just 0)
57 | (osc1_freq_fine, osc1_freq_fine_p) = pF "osc1_freq_fine" (Just 0)
58 | (osc1_shape, osc1_shape_p) = pF "osc1_shape" (Just 0)
59 | (osc1_glide, osc1_glide_p) = pF "osc1_glide" (Just 0)
60 | (osc2_frequency, osc2_frequency_p) = pF "osc2_frequency" (Just 0)
61 | (osc2_freq_fine, osc2_freq_fine_p) = pF "osc2_freq_fine" (Just 0)
62 | (osc2_shape, osc2_shape_p) = pF "osc2_shape" (Just 0)
63 | (osc2_glide, osc2_glide_p) = pF "osc2_glide" (Just 0)
64 | (osc_mix, osc_mix_p) = pF "osc_mix" (Just 0)
65 | (noise, noise_p) = pF "noise" (Just 0)
66 | (filter_frequency, filter_frequency_p) = pF "filter_frequency" (Just 0)
67 | --(resonance, resonance_p) = pF "resonance" (Just 0)
68 | (filter_key_amt, filter_key_amt_p) = pF "filter_key_amt" (Just 0)
69 | (filter_audio_mod, filter_audio_mod_p) = pF "filter_audio_mod" (Just 0)
70 | (filter_env_amt, filter_env_amt_p) = pF "filter_env_amt" (Just 0)
71 | (filter_env_vel_amt, filter_env_vel_amt_p) = pF "filter_env_vel_amt" (Just 0)
72 | (filter_delay, filter_delay_p) = pF "filter_delay" (Just 0)
73 | (filter_attack, filter_attack_p) = pF "filter_attack" (Just 0)
74 | (filter_decay, filter_decay_p) = pF "filter_decay" (Just 0)
75 | (filter_sustain, filter_sustain_p) = pF "filter_sustain" (Just 0)
76 | (filter_release, filter_release_p) = pF "filter_release" (Just 0)
77 | (vca_level, vca_level_p) = pF "vca_level" (Just 0)
78 | (pan_spread, pan_spread_p) = pF "pan_spread" (Just 0)
79 | (amp_env_amt, amp_env_amt_p) = pF "amp_env_amt" (Just 0)
80 | (amp_velocity_amt, amp_velocity_amt_p) = pF "amp_velocity_amt" (Just 0)
81 | (amp_delay, amp_delay_p) = pF "amp_delay" (Just 0)
82 | (amp_attack, amp_attack_p) = pF "amp_attack" (Just 0)
83 | (amp_decay, amp_decay_p) = pF "amp_decay" (Just 0)
84 | (amp_sustain, amp_sustain_p) = pF "amp_sustain" (Just 0)
85 | (amp_release, amp_release_p) = pF "amp_release" (Just 0)
86 | (env3_destination, env3_destination_p) = pF "env3_destination" (Just 0)
87 | (env3_amt, env3_amt_p) = pF "env3_amt" (Just 0)
88 | (env3_velocity_amt, env3_velocity_amt_p) = pF "env3_velocity_amt" (Just 0)
89 | (env3_delay, env3_delay_p) = pF "env3_delay" (Just 0)
90 | (env3_attack, env3_attack_p) = pF "env3_attack" (Just 0)
91 | (env3_decay, env3_decay_p) = pF "env3_decay" (Just 0)
92 | (env3_sustain, env3_sustain_p) = pF "env3_sustain" (Just 0)
93 | (env3_release, env3_release_p) = pF "env3_release" (Just 0)
94 | (bpm, bpm_p) = pF "bpm" (Just 0)
95 | (clock_divide, clock_divide_p) = pF "clock_divide" (Just 0)
96 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/Rytm.hs:
--------------------------------------------------------------------------------
1 | module Sound.Tidal.Rytm where
2 |
3 | import Sound.Tidal.Stream (makeI, makeF)
4 |
5 | import Sound.Tidal.MIDI.Control
6 |
7 | keys :: ControllerShape
8 | keys = ControllerShape { params = [
9 |
10 | mCC "synth1" 16,
11 | mCC "synth2" 17,
12 | mCC "synth3" 18,
13 | mCC "synth4" 19,
14 | mCC "synth5" 20,
15 | mCC "synth6" 21,
16 | mCC "synth7" 22,
17 | mCC "synth8" 23,
18 |
19 | mCC "revpre" 24,
20 | mCC "revtime" 25,
21 | mCC "revfrq" 26,
22 | mCC "revgain" 27,
23 | mCC "revhpf" 28,
24 | mCC "revlpf" 29,
25 | mCC "revvol" 31,
26 |
27 | mCC "samptune" 24,
28 | mCC "sampfinetune" 25,
29 | mCC "sampbitreduction" 26,
30 | mCC "sampslot" 27,
31 | mCC "sampstart" 28,
32 | mCC "sampend" 29,
33 | mCC "samploop" 30,
34 | mCC "samplevel" 31,
35 |
36 | mCC "machtype" 15,
37 |
38 | mCC "filtatk" 70,
39 | mCC "filtdec" 71,
40 | mCC "filtsus" 72,
41 | mCC "filtrel" 73,
42 | mCC "filtfrq" 74,
43 | mCC "filtres" 75,
44 | mCC "filttyp" 76,
45 | mCC "filtenv" 77,
46 |
47 | mCC "perf1" 35,
48 | mCC "perf2" 36,
49 | mCC "perf3" 37,
50 | mCC "perf4" 39,
51 | mCC "perf5" 40,
52 | mCC "perf6" 41,
53 | mCC "perf7" 42,
54 | mCC "perf8" 43,
55 |
56 | mCC "atk" 78,
57 | mCC "hld" 79,
58 | mCC "dec" 80,
59 | mCC "ovr" 81,
60 | mCC "del" 82,
61 | mCC "amprev" 83,
62 | mCC "amppan" 10,
63 | mCC "vol" 7
64 | ],
65 | duration = ("dur", 0.05),
66 | velocity = ("vel", 0.5),
67 | latency = 0.1
68 | }
69 |
70 | oscKeys = toOscShape keys
71 |
72 | -- note on/off
73 | note = makeI oscKeys "note"
74 | dur = makeF oscKeys "dur"
75 |
76 | -- standard synth params
77 | synth1 = makeF oscKeys "synth1"
78 | synth2 = makeF oscKeys "synth2"
79 | synth3 = makeF oscKeys "synth3"
80 | synth4 = makeF oscKeys "synth4"
81 | synth5 = makeF oscKeys "synth5"
82 | synth6 = makeF oscKeys "synth6"
83 | synth7 = makeF oscKeys "synth7"
84 | synth8 = makeF oscKeys "synth8"
85 |
86 | -- machine type (e.g. hard snare, classic snare, hard bd, classic bd, etc)
87 | machtype = makeF oscKeys "machtype"
88 |
89 | -- generic synth level and tuning
90 | lev = makeF oscKeys "synth1"
91 | tun = makeF oscKeys "synth2"
92 |
93 | -- generic bd decay and sweep type
94 | bddec = makeF oscKeys "synth3"
95 | bdswt = makeF oscKeys "synth5"
96 |
97 | -- FM bd params
98 | fmbdfmamt = makeF oscKeys "synth4"
99 | fmbdfmswt = makeF oscKeys "synth6"
100 | fmbdfmdec = makeF oscKeys "synth7"
101 | fmbdfmtun = makeF oscKeys "synth8"
102 |
103 | -- hard bd params
104 | hardbdhold = makeF oscKeys "synth4"
105 | hardbdsnap = makeF oscKeys "synth6"
106 | hardbdwav = makeF oscKeys "synth7"
107 | hardbdtic = makeF oscKeys "synth8"
108 |
109 | -- classic bd params
110 | clasbdswd = makeF oscKeys "synth6"
111 | clasbdtra = makeF oscKeys "synth7"
112 | clasbdwav = makeF oscKeys "synth8"
113 |
114 | -- generic sd params (decay, noise decay, noise level)
115 | sddec = makeF oscKeys "synth3"
116 | sdnod = makeF oscKeys "synth6"
117 | sdnol = makeF oscKeys "synth7"
118 |
119 | -- hard sd params
120 | hardsdswd = makeF oscKeys "synth4"
121 | hardsdtic = makeF oscKeys "synth5"
122 | hardsdswt = makeF oscKeys "synth8"
123 |
124 | -- classic sd params
125 | classddet = makeF oscKeys "synth4"
126 | classdsnp = makeF oscKeys "synth5"
127 | classdbal = makeF oscKeys "synth8"
128 |
129 | -- FM sd params
130 | fmsdfmt = makeF oscKeys "synth4"
131 | fmsdfmd = makeF oscKeys "synth5"
132 | fmsdfma = makeF oscKeys "synth8"
133 |
134 | -- BT
135 | btdec = makeF oscKeys "synth3"
136 |
137 | -- CP
138 | cpton = makeF oscKeys "synth2"
139 | cpnod = makeF oscKeys "synth3"
140 | cpnum = makeF oscKeys "synth4"
141 | cprat = makeF oscKeys "synth5"
142 | cpnol = makeF oscKeys "synth6"
143 | cprnd = makeF oscKeys "synth7"
144 | cpcpd = makeF oscKeys "synth8"
145 |
146 | -- filter params
147 | filtatk = makeF oscKeys "filtatk"
148 | filtdec = makeF oscKeys "filtdec"
149 | filtsus = makeF oscKeys "filtsus"
150 | filtrel = makeF oscKeys "filtrel"
151 | filtfrq = makeF oscKeys "filtfrq"
152 | filtres = makeF oscKeys "filtres"
153 | filttyp = makeF oscKeys "filttyp"
154 | filtenv = makeF oscKeys "filtenv"
155 |
156 | -- amplitude params
157 | atk = makeF oscKeys "atk"
158 | hld = makeF oscKeys "hld"
159 | dec = makeF oscKeys "dec"
160 | ovr = makeF oscKeys "ovr"
161 | del = makeF oscKeys "del"
162 | amprev = makeF oscKeys "amprev"
163 | amppan = makeF oscKeys "amppan"
164 | vol = makeF oscKeys "vol"
165 |
166 | -- delay params (only used on FX MIDI channel)
167 | deltime = makeF oscKeys "synth1"
168 | delpingpong = makeF oscKeys "synth2"
169 | delwidth = makeF oscKeys "synth3"
170 | delfeedback = makeF oscKeys "synth4"
171 | delhpf = makeF oscKeys "synth5"
172 | dellpf = makeF oscKeys "synth6"
173 | delrev = makeF oscKeys "synth7"
174 | delvol = makeF oscKeys "synth8"
175 |
176 | -- reverb params (only used on FX MIDI channel)
177 | revpre = makeF oscKeys "revpre"
178 | revtime = makeF oscKeys "revtime"
179 | revfrq = makeF oscKeys "revfrq"
180 | revgain = makeF oscKeys "revgain"
181 | revhpf = makeF oscKeys "revhpf"
182 | revlpf = makeF oscKeys "revlpf"
183 | revvol = makeF oscKeys "revvol"
184 |
185 | -- performance
186 | perf1 = makeF oscKeys "perf1"
187 | perf2 = makeF oscKeys "perf2"
188 | perf3 = makeF oscKeys "perf3"
189 | perf4 = makeF oscKeys "perf4"
190 | perf5 = makeF oscKeys "perf5"
191 | perf6 = makeF oscKeys "perf6"
192 | perf7 = makeF oscKeys "perf7"
193 | perf8 = makeF oscKeys "perf8"
194 |
195 | -- sample
196 | samptune = makeF oscKeys "samptune"
197 | sampfinetune = makeF oscKeys "sampfinetune"
198 | sampbitreduction = makeF oscKeys "sampbitreduction"
199 | sampslot = makeF oscKeys "sampslot"
200 | sampstart = makeF oscKeys "sampstart"
201 | sampend = makeF oscKeys "sampend"
202 | samploop = makeF oscKeys "samploop"
203 | samplevel = makeF oscKeys "samplevel"
204 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/Stream.hs:
--------------------------------------------------------------------------------
1 | {-|
2 | Entry functions for interacting with MIDI devices through Tidal.
3 | -}
4 | module Sound.Tidal.MIDI.Stream (midiStream, midiBackend, midiState, midiSetters, midiDevices, displayOutputDevices) where
5 |
6 | -- generics
7 | import Control.Concurrent
8 | import Control.Concurrent.MVar ()
9 | import qualified Data.Map as Map
10 |
11 | -- Tidal specific
12 | import Sound.Tidal.Stream as S
13 | import Sound.Tidal.Time
14 | import Sound.Tidal.Transition (transition)
15 |
16 | -- MIDI specific
17 | import Sound.Tidal.MIDI.Control
18 | import Sound.Tidal.MIDI.Output
19 |
20 |
21 | {-|
22 | Create a handle for all currently used 'Output's indexed by their device name.
23 |
24 | We use this to cache once opened devices.
25 |
26 | This will be passed to _every_ initialization of a virtual stream to a MIDI device
27 | and is necessary since, 'PortMidi' only allows a single connection to a device.
28 | -}
29 | midiDevices :: IO (MVar MidiDeviceMap)
30 | midiDevices = newMVar $ Map.fromList []
31 |
32 |
33 | {-|
34 | Connect to a MIDI device with a given name and channel,
35 | using a 'ControllerShape' to allow customized interaction
36 | with specific MIDI synths.
37 |
38 | Needs a 'MidiDeviceMap' to operate, create on using 'midiDevices'!
39 |
40 | Usage:
41 |
42 | @
43 | (m1, mt1) <- midiSetters devices "My Synth Controller Device name" 1 synthController getNow
44 | @
45 |
46 | To find the correct name for your device see 'displayOutputDevices'
47 | -}
48 | midiSetters :: MVar MidiDeviceMap -- ^ A list of MIDI output devices
49 | -> String -- ^ The name of the output device to connect
50 | -> Int -- ^ The MIDI Channel to use
51 | -> ControllerShape -- ^ The definition of params to be usable
52 | -> IO Time -- ^ a method to get the current time
53 | -> IO (ParamPattern -> IO (), (Time -> [ParamPattern] -> ParamPattern) -> ParamPattern -> IO ())
54 | midiSetters d n c s getNow = do
55 | ds <- midiState d n c s
56 | return (setter ds, transition getNow ds)
57 |
58 |
59 | {-|
60 | Creates a single virtual stream to a MIDI device using a specific 'ControllerShape'
61 |
62 | Needs a 'MidiDeviceMap' to operate, create one using 'midiDevices'!
63 | -}
64 | midiStream :: MVar MidiDeviceMap -> String -> Int -> ControllerShape -> IO (ParamPattern -> IO ())
65 | midiStream d n c s = do
66 | backend <- midiBackend d n c s
67 | stream backend (toShape s)
68 |
69 | {-|
70 | Creates a single virtual state for a MIDI device using a specific 'ControllerShape'
71 |
72 | This state can be used to either create a 'Sound.Tidal.Stream.setter' or a 'Sound.Tidal.Transition.transition' from it.
73 |
74 | Needs a 'MidiDeviceMap' to operate, create one using 'midiDevices'!
75 | -}
76 | midiState :: MVar MidiDeviceMap -> String -> Int -> ControllerShape -> IO (MVar (ParamPattern, [ParamPattern]))
77 | midiState d n c s = do
78 | backend <- midiBackend d n c s
79 | S.state backend (toShape s)
80 |
81 |
82 | {-|
83 | Opens a connection to a MIDI device and wraps it in a 'Sound.Tidal.Stream.Backend' implementation.
84 |
85 | Needs a 'MidiDeviceMap' to operate, create one using 'midiDevices'!
86 | -}
87 | midiBackend :: MVar MidiDeviceMap -> String -> Int -> ControllerShape -> IO (Backend a)
88 | midiBackend d n c cs = do
89 | (s, o) <- makeConnection d n c cs
90 | return $ Backend s (flushBackend o)
91 |
92 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/Synth.hs:
--------------------------------------------------------------------------------
1 | module Sound.Tidal.MIDI.Synth where
2 |
3 | import Sound.Tidal.MIDI.Control
4 | import Sound.Tidal.Params
5 |
6 | synthController :: ControllerShape
7 | synthController =
8 | ControllerShape
9 | { controls =
10 | [ mCC modwheel_p 1
11 | , mCC pan_p 10
12 | , mCC expression_p 11
13 | , mCC sustainpedal_p 64
14 | ]
15 | , latency = 0.1
16 | }
17 |
18 | synth = toShape synthController
19 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/Synthino.hs:
--------------------------------------------------------------------------------
1 | module Sound.Tidal.MIDI.Synthino where
2 |
3 | import Sound.Tidal.MIDI.Control
4 | import Sound.Tidal.Params
5 |
6 | synthinoController :: ControllerShape
7 | synthinoController =
8 | ControllerShape
9 | { controls =
10 | [ mCC attack_p 73
11 | , mCC decay_p 75
12 | , mCC sustain_p 79
13 | , mCC release_p 72
14 | , mCC waveform_p 70
15 | , mCC pitchlforate_p 76
16 | , mCC pitchlfodepth_p 1
17 | , mCC lfowaveform_p 12
18 | , mCC filterlforate_p 13
19 | , mCC filterlfodepth_p 91
20 | , mCC peak_p 71
21 | , mCC cutoff_p 74
22 | , mCC bpm_p 16
23 | , mCC arplength_p 17
24 | , mCC arptranspose_p 18
25 | , mCC vol_p 7
26 | , mCC off_p 123
27 | ]
28 | , latency = 0.1
29 | }
30 |
31 | synthino = toShape synthinoController
32 |
33 | (waveform, waveform_p) = pF "waveform" (Just 0)
34 |
35 | (pitchlforate, pitchlforate_p) = pF "pitchlforate" (Just 0)
36 |
37 | (pitchlfodepth, pitchlfodepth_p) = pF "pitchlfodepth" (Just 0)
38 |
39 | (lfowaveform, lfowaveform_p) = pF "lfowaveform" (Just 0)
40 |
41 | (filterlforate, filterlforate_p) = pF "filterlforate" (Just 0)
42 |
43 | (filterlfodepth, filterlfodepth_p) = pF "filterlfodepth" (Just 0)
44 |
45 | (peak, peak_p) = pF "peak" (Just 0)
46 |
47 | (bpm, bpm_p) = pF "bpm" (Just 0)
48 |
49 | (arplength, arplength_p) = pF "arplength" (Just 0)
50 |
51 | (arptranspose, arptranspose_p) = pF "arptranspose" (Just 0)
52 |
53 | (vol, vol_p) = pF "vol" (Just 0)
54 |
55 | (off, off_p) = pF "off" (Just 0)
56 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/System1M.hs:
--------------------------------------------------------------------------------
1 | module Sound.Tidal.MIDI.System1M where
2 |
3 | import Sound.Tidal.MIDI.Control
4 | import Sound.Tidal.Params
5 |
6 | system1mController :: ControllerShape
7 | system1mController =
8 | ControllerShape
9 | { controls =
10 | [ mCC rmod_p 1
11 | , mCC rlpcutoff_p 3
12 | , mCC rport_p 5
13 | , mCC rres_p 9
14 | , mCC rcrush_p 12
15 | , mCC rdelaytime_p 13
16 | , mCC rosc1_p 16
17 | , mCC rosc2_p 17
18 | , mCC rsub_p 18
19 | , mCC rnoise_p 19
20 | , mCC rpitchenv_p 22
21 | , mCC rpitchatk_p 23
22 | , mCC rpitchdecay_p 24
23 | , mCC rlfopitch_p 26
24 | , mCC rlfofade_p 27
25 | , mCC rlfofilter_p 28
26 | , mCC rlforate_p 29
27 | , mCC rlfoamp_p 30
28 | , mCC rlfotype_p 35
29 | , mCC rosc1type_p 46
30 | , mCC rosc1range_p 47
31 | , mCC rosc1color_p 50
32 | , mCC rosc1xmod_p 52
33 | , mCC rosc2color_p 55
34 | , mCC rosc2tune_p 56
35 | , mCC rosc1mod_p 60
36 | , mCC rosc2type_p 61
37 | , mCC rosc2range_p 62
38 | , mCC rosc2mod_p 63
39 | , mCC ramptone_p 69
40 | , mCC rhpcutoff_p 79
41 | , mCC rfilterenv_p 81
42 | , mCC rfilterkey_p 82
43 | , mCC rfilteratk_p 83
44 | , mCC rfilterdecay_p 84
45 | , mCC rfiltersustain_p 85
46 | , mCC rfilterrelease_p 86
47 | , mCC rampatk_p 89
48 | , mCC rampdecay_p 90
49 | , mCC rreverb_p 91
50 | , mCC rdelay_p 94
51 | , mCC rampsustain_p 96
52 | , mCC ramprelease_p 97
53 | , mCC rosc2ring_p 111
54 | , mCC rosc2sync_p 112
55 | , mCC rsubtype_p 113
56 | , mCC rnoisetype_p 114
57 | , mCC rlpftype_p 115
58 | , mCC rlegato_p 116
59 | , mCC rlfokeytrig_p 117
60 | , mCC rtemposync_p 118
61 | , mCC rmono_p 119
62 | ]
63 | , latency = 0.1
64 | }
65 |
66 | system1m = toShape system1mController
67 |
68 | (rmod, rmod_p) = pF "rmod" (Just 0)
69 |
70 | (rlpcutoff, rlpcutoff_p) = pF "rlpcutoff" (Just 0)
71 |
72 | (rport, rport_p) = pF "rport" (Just 0)
73 |
74 | (rres, rres_p) = pF "rres" (Just 0)
75 |
76 | (rcrush, rcrush_p) = pF "rcrush" (Just 0)
77 |
78 | (rdelaytime, rdelaytime_p) = pF "rdelaytime" (Just 0)
79 |
80 | (rosc1, rosc1_p) = pF "rosc1" (Just 0)
81 |
82 | (rosc2, rosc2_p) = pF "rosc2" (Just 0)
83 |
84 | (rsub, rsub_p) = pF "rsub" (Just 0)
85 |
86 | (rnoise, rnoise_p) = pF "rnoise" (Just 0)
87 |
88 | (rpitchenv, rpitchenv_p) = pF "rpitchenv" (Just 0)
89 |
90 | (rpitchatk, rpitchatk_p) = pF "rpitchatk" (Just 0)
91 |
92 | (rpitchdecay, rpitchdecay_p) = pF "rpitchdecay" (Just 0)
93 |
94 | (rlfopitch, rlfopitch_p) = pF "rlfopitch" (Just 0)
95 |
96 | (rlfofade, rlfofade_p) = pF "rlfofade" (Just 0)
97 |
98 | (rlfofilter, rlfofilter_p) = pF "rlfofilter" (Just 0)
99 |
100 | (rlforate, rlforate_p) = pF "rlforate" (Just 0)
101 |
102 | (rlfoamp, rlfoamp_p) = pF "rlfoamp" (Just 0)
103 |
104 | (rlfotype, rlfotype_p) = pF "rlfotype" (Just 0)
105 |
106 | (rosc1type, rosc1type_p) = pF "rosc1type" (Just 0)
107 |
108 | (rosc1range, rosc1range_p) = pF "rosc1range" (Just 0)
109 |
110 | (rosc1color, rosc1color_p) = pF "rosc1color" (Just 0)
111 |
112 | (rosc1xmod, rosc1xmod_p) = pF "rosc1xmod" (Just 0)
113 |
114 | (rosc2color, rosc2color_p) = pF "rosc2color" (Just 0)
115 |
116 | (rosc2tune, rosc2tune_p) = pF "rosc2tune" (Just 0)
117 |
118 | (rosc1mod, rosc1mod_p) = pF "rosc1mod" (Just 0)
119 |
120 | (rosc2type, rosc2type_p) = pF "rosc2type" (Just 0)
121 |
122 | (rosc2range, rosc2range_p) = pF "rosc2range" (Just 0)
123 |
124 | (rosc2mod, rosc2mod_p) = pF "rosc2mod" (Just 0)
125 |
126 | (ramptone, ramptone_p) = pF "ramptone" (Just 0)
127 |
128 | (rhpcutoff, rhpcutoff_p) = pF "rhpcutoff" (Just 0)
129 |
130 | (rfilterenv, rfilterenv_p) = pF "rfilterenv" (Just 0)
131 |
132 | (rfilterkey, rfilterkey_p) = pF "rfilterkey" (Just 0)
133 |
134 | (rfilteratk, rfilteratk_p) = pF "rfilteratk" (Just 0)
135 |
136 | (rfilterdecay, rfilterdecay_p) = pF "rfilterdecay" (Just 0)
137 |
138 | (rfiltersustain, rfiltersustain_p) = pF "rfiltersustain" (Just 0)
139 |
140 | (rfilterrelease, rfilterrelease_p) = pF "rfilterrelease" (Just 0)
141 |
142 | (rampatk, rampatk_p) = pF "rampatk" (Just 0)
143 |
144 | (rampdecay, rampdecay_p) = pF "rampdecay" (Just 0)
145 |
146 | (rreverb, rreverb_p) = pF "rreverb" (Just 0)
147 |
148 | (rdelay, rdelay_p) = pF "rdelay" (Just 0)
149 |
150 | (rampsustain, rampsustain_p) = pF "rampsustain" (Just 0)
151 |
152 | (ramprelease, ramprelease_p) = pF "ramprelease" (Just 0)
153 |
154 | (rosc2ring, rosc2ring_p) = pF "rosc2ring" (Just 0)
155 |
156 | (rosc2sync, rosc2sync_p) = pF "rosc2sync" (Just 0)
157 |
158 | (rsubtype, rsubtype_p) = pF "rsubtype" (Just 0)
159 |
160 | (rnoisetype, rnoisetype_p) = pF "rnoisetype" (Just 0)
161 |
162 | (rlpftype, rlpftype_p) = pF "rlpftype" (Just 0)
163 |
164 | (rlegato, rlegato_p) = pF "rlegato" (Just 0)
165 |
166 | (rlfokeytrig, rlfokeytrig_p) = pF "rlfokeytrig" (Just 0)
167 |
168 | (rtemposync, rtemposync_p) = pF "rtemposync" (Just 0)
169 |
170 | (rmono, rmono_p) = pF "rmono" (Just 0)
171 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/Tanzbar.hs:
--------------------------------------------------------------------------------
1 | module Sound.Tidal.MIDI.Tanzbar where
2 |
3 | import Sound.Tidal.Params
4 | import Sound.Tidal.MIDI.Control
5 |
6 |
7 | (bd1_attack, bd1_attack_p) = pF "bd1_attack" (Just 0)
8 | (bd1_decay, bd1_decay_p) = pF "bd1_decay" (Just 0)
9 | (bd1_tune, bd1_tune_p) = pF "bd1_tune" (Just 0)
10 | (bd1_noise, bd1_noise_p) = pF "bd1_noise" (Just 0)
11 | (bd1_filter, bd1_filter_p) = pF "bd1_filter" (Just 0)
12 | (bd1_dist, bd1_dist_p) = pF "bd1_dist" (Just 0)
13 | (bd1_trigger, bd1_trigger_p) = pF "bd1_trigger" (Just 0)
14 | (bd2_decay, bd2_decay_p) = pF "bd2_decay" (Just 0)
15 | (bd2_tune, bd2_tune_p) = pF "bd2_tune" (Just 0)
16 | (bd2_tone, bd2_tone_p) = pF "bd2_tone" (Just 0)
17 | (sd_tune, sd_tune_p) = pF "sd_tune" (Just 0)
18 | (sd_d_tune, sd_d_tune_p) = pF "sd_d_tune" (Just 0)
19 | (sd_snappy, sd_snappy_p) = pF "sd_snappy" (Just 0)
20 | (sd_sn_decay, sd_sn_decay_p) = pF "sd_sn_decay" (Just 0)
21 | (sd_tone, sd_tone_p) = pF "sd_tone" (Just 0)
22 | (sd_tone_decay, sd_tone_decay_p) = pF "sd_tone_decay" (Just 0)
23 | (sd_pitch, sd_pitch_p) = pF "sd_pitch" (Just 0)
24 | (rs_tune, rs_tune_p) = pF "rs_tune" (Just 0)
25 | (cy_decay, cy_decay_p) = pF "cy_decay" (Just 0)
26 | (cy_tone, cy_tone_p) = pF "cy_tone" (Just 0)
27 | (cy_tune, cy_tune_p) = pF "cy_tune" (Just 0)
28 | (oh_decay, oh_decay_p) = pF "oh_decay" (Just 0)
29 | (hh_tune, hh_tune_p) = pF "hh_tune" (Just 0)
30 | (hh_decay, hh_decay_p) = pF "hh_decay" (Just 0)
31 | (cl_tune, cl_tune_p) = pF "cl_tune" (Just 0)
32 | (cl_decay, cl_decay_p) = pF "cl_decay" (Just 0)
33 | (cp_decay, cp_decay_p) = pF "cp_decay" (Just 0)
34 | (cp_filter, cp_filter_p) = pF "cp_filter" (Just 0)
35 | (cp_attack, cp_attack_p) = pF "cp_attack" (Just 0)
36 | (cp_trigger, cp_trigger_p) = pF "cp_trigger" (Just 0)
37 | (htc_tune, htc_tune_p) = pF "htc_tune" (Just 0)
38 | (htc_decay, htc_decay_p) = pF "htc_decay" (Just 0)
39 | (htc_noise_on_off, htc_noise_on_off_p) = pF "htc_noise_on_off" (Just 0)
40 | (htc_tom_conga, htc_tom_conga_p) = pF "htc_tom_conga" (Just 0)
41 | (mtc_tune, mtc_tune_p) = pF "mtc_tune" (Just 0)
42 | (mtc_decay, mtc_decay_p) = pF "mtc_decay" (Just 0)
43 | (mtc_noise_on_off, mtc_noise_on_off_p) = pF "mtc_noise_on_off" (Just 0)
44 | (mtc_tom_conga, mtc_tom_conga_p) = pF "mtc_tom_conga" (Just 0)
45 | (ltc_tune, ltc_tune_p) = pF "ltc_tune" (Just 0)
46 | (ltc_decay, ltc_decay_p) = pF "ltc_decay" (Just 0)
47 | (ltc_noise_on_off, ltc_noise_on_off_p) = pF "ltc_noise_on_off" (Just 0)
48 | (ltc_tom_conga, ltc_tom_conga_p) = pF "ltc_tom_conga" (Just 0)
49 | (tom_noise, tom_noise_p) = pF "tom_noise" (Just 0)
50 | (cb_tune, cb_tune_p) = pF "cb_tune" (Just 0)
51 | (cb_decay, cb_decay_p) = pF "cb_decay" (Just 0)
52 | (ma_decay, ma_decay_p) = pF "ma_decay" (Just 0)
53 | (set_select, set_select_p) = pF "set_select" (Just 0)
54 | (track_delay_cv1, track_delay_cv1_p) = pF "track_delay_cv1" (Just 0)
55 | (track_delay_cv23, track_delay_cv23_p) = pF "track_delay_cv23" (Just 0)
56 | (track_delay_bd1, track_delay_bd1_p) = pF "track_delay_bd1" (Just 0)
57 | (track_delay_bd2, track_delay_bd2_p) = pF "track_delay_bd2" (Just 0)
58 | (track_delay_sd, track_delay_sd_p) = pF "track_delay_sd" (Just 0)
59 | (track_delay_rs, track_delay_rs_p) = pF "track_delay_rs" (Just 0)
60 | (track_delay_cy, track_delay_cy_p) = pF "track_delay_cy" (Just 0)
61 | (track_delay_oh, track_delay_oh_p) = pF "track_delay_oh" (Just 0)
62 | (track_delay_hh, track_delay_hh_p) = pF "track_delay_hh" (Just 0)
63 | (track_delay_cl, track_delay_cl_p) = pF "track_delay_cl" (Just 0)
64 | (track_delay_cp, track_delay_cp_p) = pF "track_delay_cp" (Just 0)
65 | (track_delay_ltc, track_delay_ltc_p) = pF "track_delay_ltc" (Just 0)
66 | (track_delay_mtc, track_delay_mtc_p) = pF "track_delay_mtc" (Just 0)
67 | (track_delay_htc, track_delay_htc_p) = pF "track_delay_htc" (Just 0)
68 | (track_delay_cb, track_delay_cb_p) = pF "track_delay_cb" (Just 0)
69 | (track_delay_ma, track_delay_ma_p) = pF "track_delay_ma" (Just 0)
70 | (bd1, bd1_p) = pF "bd1" (Just 0)
71 | (bd2, bd2_p) = pF "bd2" (Just 0)
72 | (sd, sd_p) = pF "sd" (Just 0)
73 | (rs, rs_p) = pF "rs" (Just 0)
74 | (cy, cy_p) = pF "cy" (Just 0)
75 | (oh, oh_p) = pF "oh" (Just 0)
76 | (hh, hh_p) = pF "hh" (Just 0)
77 | (cl, cl_p) = pF "cl" (Just 0)
78 | (cp, cp_p) = pF "cp" (Just 0)
79 | (ltc, ltc_p) = pF "ltc" (Just 0)
80 | (mtc, mtc_p) = pF "mtc" (Just 0)
81 | (htc, htc_p) = pF "htc" (Just 0)
82 | (cb, cb_p) = pF "cb" (Just 0)
83 | (ma, ma_p) = pF "ma" (Just 0)
84 |
85 | tanzController :: ControllerShape
86 | tanzController = ControllerShape {
87 | controls = [
88 | mCC bd1_attack_p 2,
89 | mCC bd1_decay_p 64,
90 | mCC bd1_tune_p 3,
91 | mCC bd1_noise_p 4,
92 | mCC bd1_filter_p 5,
93 | mCC bd1_dist_p 6,
94 | mCC bd1_trigger_p 66,
95 | mCC bd2_decay_p 8,
96 | mCC bd2_tune_p 9,
97 | mCC bd2_tone_p 10,
98 | mCC sd_tune_p 11,
99 | mCC sd_d_tune_p 12,
100 | mCC sd_snappy_p 13,
101 | mCC sd_sn_decay_p 67,
102 | mCC sd_tone_p 14,
103 | mCC sd_tone_decay_p 68,
104 | mCC sd_pitch_p 69,
105 | mCC rs_tune_p 88,
106 | mCC cy_decay_p 70,
107 | mCC cy_tone_p 15,
108 | mCC cy_tune_p 71,
109 | mCC oh_decay_p 75,
110 | mCC hh_tune_p 73,
111 | mCC hh_decay_p 74,
112 | mCC cl_tune_p 16,
113 | mCC cl_decay_p 17,
114 | mCC cp_decay_p 75,
115 | mCC cp_filter_p 18,
116 | mCC cp_attack_p 76,
117 | mCC cp_trigger_p 77,
118 | mCC htc_tune_p 19,
119 | mCC htc_decay_p 20,
120 | mCC htc_noise_on_off_p 78,
121 | mCC htc_tom_conga_p 79,
122 | mCC mtc_tune_p 21,
123 | mCC mtc_decay_p 22,
124 | mCC mtc_noise_on_off_p 80,
125 | mCC mtc_tom_conga_p 81,
126 | mCC ltc_tune_p 23,
127 | mCC ltc_decay_p 24,
128 | mCC ltc_noise_on_off_p 82,
129 | mCC ltc_tom_conga_p 83,
130 | mCC tom_noise_p 84,
131 | mCC cb_tune_p 85,
132 | mCC cb_decay_p 86,
133 | mCC ma_decay_p 87,
134 | mCC set_select_p 0,
135 | mCC track_delay_cv1_p 89,
136 | mCC track_delay_cv23_p 90,
137 | mCC track_delay_bd1_p 91,
138 | mCC track_delay_bd2_p 92,
139 | mCC track_delay_sd_p 93,
140 | mCC track_delay_rs_p 94,
141 | mCC track_delay_cy_p 95,
142 | mCC track_delay_oh_p 96,
143 | mCC track_delay_hh_p 97,
144 | mCC track_delay_cl_p 98,
145 | mCC track_delay_cp_p 99,
146 | mCC track_delay_ltc_p 100,
147 | mCC track_delay_mtc_p 101,
148 | mCC track_delay_htc_p 102,
149 | mCC track_delay_cb_p 103,
150 | mCC track_delay_ma_p 104,
151 | mCC bd1_p 36,
152 | mCC bd2_p 37,
153 | mCC sd_p 38,
154 | mCC rs_p 39,
155 | mCC cy_p 40,
156 | mCC oh_p 41,
157 | mCC hh_p 42,
158 | mCC cl_p 43,
159 | mCC cp_p 44,
160 | mCC ltc_p 45,
161 | mCC mtc_p 46,
162 | mCC htc_p 47,
163 | mCC cb_p 48,
164 | mCC ma_p 49
165 | ],
166 | latency = 0.1
167 | }
168 |
169 |
170 |
171 |
172 |
173 | tanz = midinote . (tanzN <$>)
174 |
175 | tanzN :: String -> Int
176 | tanzN "bd1" = 36
177 | tanzN "bd2" = 37
178 | tanzN "sd" = 38
179 | tanzN "rs" = 39
180 | tanzN "cy" = 40
181 | tanzN "oh" = 41
182 | tanzN "hh" = 42
183 | tanzN "cl" = 43
184 | tanzN "cp" = 44
185 | tanzN "ltc" = 45
186 | tanzN "mtc" = 46
187 | tanzN "htc" = 47
188 | tanzN "cb" = 48
189 | tanzN "ma" = 49
190 |
191 |
192 | -- general shape for stream
193 | tanzShape = toShape tanzController
194 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/Tetra.hs:
--------------------------------------------------------------------------------
1 | {-# LANGUAGE OverloadedStrings #-}
2 | {-|
3 | Mapping and Abstractions for the analog four-voice synthesizer, TETR4 by Dave Smith Instruments.
4 |
5 | Rather than being a tutorial on how to write your own mappings for your MIDI devices, this is more like the kitchen sink: it shows what is possible.
6 |
7 | The DSI TETR4 has four separate voices that can (when set to multi-mode) be controlled via four different MIDI channels. Almost everything you can control directly on the device can be automated via MIDI messages.
8 | -}
9 | module Sound.Tidal.MIDI.Tetra where
10 |
11 | import Sound.Tidal.MIDI.Control
12 |
13 | import Sound.Tidal.Params
14 | hiding (cutoff_p, attack_p, decay_p, sustain_p, release_p)
15 | import Sound.Tidal.Pattern (Pattern(..), atom)
16 | import Sound.Tidal.Stream
17 | ((|+|), (|=|), ( # ), merge, ParamPattern)
18 |
19 | import Control.Applicative
20 |
21 | {-|
22 | The controller mapping for TETR4
23 |
24 | To get the most out of this device with tidal, I chose to use the non-registered parameter (NRPN) variant to control it. This allows to use the full spectrum for controls like @cutoff@ that allow more granular stepping than standard MIDI (164 instead of 128 steps).
25 |
26 | Many parameters diverge from the default ranges of 0 to 127 and therefore this mapping uses the @mapRange@ functionality for controls to allow you to always use double params, e.g.:
27 |
28 | >>> t1 $ n (run 4) # famt "0.5" # cutoff "0.3" # resonance "0.8"
29 |
30 | while @famt@, @cutoff@ and @resonance@ all have different ranges of operation (0..254, 0..14 and 0..127 respectively)
31 |
32 | Some parameters are essentially mode switches and I chose to pass the values you enter into patterns directly through to the resulting control change. The method @passThru@ on control specification simply skips the scaling of values (you can write your own scaler if you want).
33 |
34 | For very generic control I reused Tidal's own params, like @cutoff@, @attack@, @gain@, @pan@ and @release@. Sometimes the defaults for Tidal do not make sense for MIDI. See @(_, cutoff_p)@ below the actual controller shape for examples on how to deal with this.
35 | -}
36 | tetraController :: ControllerShape
37 | tetraController =
38 | ControllerShape
39 | { controls =
40 | [ mrNRPN osc1freq_p 0 (0, 120)
41 | , mrNRPN osc1detune_p 1 (0, 100)
42 | , NRPN osc1shape_p 2 (0, 103) passThru
43 | , mNRPN osc1glide_p 3
44 | , NRPN osc1kbd_p 4 (0, 1) passThru
45 | , mrNRPN osc2freq_p 5 (0, 120)
46 | , mrNRPN osc2detune_p 6 (0, 100)
47 | , NRPN osc2shape_p 7 (0, 103) passThru
48 | , mNRPN osc2glide_p 8
49 | , NRPN osc2kbd_p 9 (0, 1) passThru
50 | , NRPN oscsync_p 10 (0, 1) passThru
51 | , NRPN glidemode_p 11 (0, 3) passThru
52 | , NRPN oscslop_p 12 (0, 5) passThru
53 | , mrNRPN oscmix_p 13 (0, 127)
54 | , mNRPN noise_p 14
55 | , mrNRPN cutoff_p 15 (0, 164)
56 | , mNRPN resonance_p 16
57 | , mNRPN kamt_p 17
58 | , mNRPN audiomod_p 18
59 | , NRPN fpoles_p 19 (0, 1) passThru
60 | -- filter envelope
61 | , mrNRPN famt_p 20 (0, 254)
62 | , mNRPN fvel_p 21
63 | , mNRPN fdel_p 22
64 | , mNRPN fatk_p 23
65 | , mNRPN fdcy_p 24
66 | , mNRPN fsus_p 25
67 | , mNRPN frel_p 26
68 | , mNRPN vcavol_p 27
69 | , mNRPN pan_p 28
70 | , mNRPN gain_p 29 -- max volume by default
71 | , mrNRPN vamt_p 30 (0, 127) -- max vca envelope amount
72 | , mNRPN vvel_p 31
73 | , mNRPN vdel_p 32
74 | , mNRPN attack_p 33
75 | , mrNRPN decay_p 34 (0, 127)
76 | , mrNRPN sustain_p 35 (0, 127)
77 | , mNRPN release_p 36
78 | , NRPN lfo1rate_p 37 (0, 166) passThru
79 | , NRPN lfo1shape_p 38 (0, 4) passThru
80 | , mNRPN lfo1amt_p 39
81 | , NRPN lfo1dest_p 40 (0, 43) passThru
82 | , NRPN lfo1sync_p 41 (0, 1) passThru
83 | , NRPN lfo2rate_p 42 (0, 166) passThru -- unsynced
84 | , NRPN lfo2shape_p 43 (0, 4) passThru
85 | , mNRPN lfo2amt_p 44
86 | , NRPN lfo2dest_p 45 (0, 43) passThru
87 | , NRPN lfo2sync_p 46 (0, 1) passThru
88 | , NRPN lfo3rate_p 47 (0, 166) passThru -- unsynced
89 | , NRPN lfo3shape_p 48 (0, 4) passThru
90 | , mNRPN lfo3amt_p 49
91 | , NRPN lfo3dest_p 50 (0, 43) passThru
92 | , NRPN lfo3sync_p 51 (0, 1) passThru
93 | , NRPN lfo4rate_p 52 (0, 166) passThru -- unsynced
94 | , NRPN lfo4shape_p 53 (0, 4) passThru
95 | , mNRPN lfo4amt_p 54
96 | , NRPN lfo4dest_p 55 (0, 43) passThru
97 | , NRPN lfo4sync_p 56 (0, 1) passThru
98 | , NRPN emod_p 57 (0, 43) passThru
99 | , mrNRPN eamt_p 58 (0, 254)
100 | , mNRPN evel_p 59
101 | , mNRPN edel_p 60
102 | , mNRPN eatk_p 61
103 | , mNRPN edcy_p 62
104 | , mNRPN esus_p 63
105 | , mNRPN erel_p 64
106 | , NRPN mod1src_p 65 (0, 20) passThru
107 | , mrNRPN mod1amt_p 66 (0, 254)
108 | , NRPN mod1dst_p 67 (0, 47) passThru
109 | , NRPN mod2src_p 68 (0, 20) passThru
110 | , mrNRPN mod2amt_p 69 (0, 254)
111 | , NRPN mod2dst_p 70 (0, 47) passThru
112 | , NRPN mod3src_p 71 (0, 20) passThru
113 | , mrNRPN mod3amt_p 72 (0, 254)
114 | , NRPN mod3dst_p 73 (0, 47) passThru
115 | , NRPN mod4src_p 74 (0, 20) passThru
116 | , mrNRPN mod4amt_p 75 (0, 254)
117 | , NRPN mod4dst_p 76 (0, 47) passThru
118 | , NRPN seq1dst_p 77 (0, 47) passThru
119 | , NRPN seq2dst_p 78 (0, 47) passThru
120 | , NRPN seq3dst_p 79 (0, 47) passThru
121 | , NRPN seq4dst_p 80 (0, 47) passThru
122 | , mrNRPN mwhl_p 81 (0, 254)
123 | , NRPN mwhldst_p 82 (0, 47) passThru
124 | , mrNRPN aftt_p 83 (0, 254)
125 | , NRPN afttdst_p 84 (0, 47) passThru
126 | , mrNRPN breath_p 85 (0, 254)
127 | , NRPN breathdst_p 86 (0, 47) passThru
128 | , mrNRPN mvel_p 87 (0, 254)
129 | , NRPN mveldst_p 88 (0, 47) passThru
130 | , mrNRPN foot_p 89 (0, 254)
131 | , NRPN footdst_p 90 (0, 47) passThru
132 | , NRPN kbpm_p 91 (30, 250) passThru
133 | , NRPN clockdiv_p 92 (0, 12) passThru -- TODO: document values
134 | , NRPN bendrng_p 93 (0, 12) passThru
135 | , NRPN sqntrig_p 94 (0, 4) passThru -- TODO: document values
136 | , NRPN unisonkey_p 95 (0, 5) passThru -- TODO: document values
137 | , NRPN unisonmode_p 96 (0, 4) passThru -- TODO: document values
138 | , NRPN arpmode_p 97 (0, 14) passThru
139 | , NRPN erepeat_p 98 (0, 1) passThru
140 | , NRPN unison_p 99 (0, 1) passThru
141 | , NRPN arp_p 100 (0, 1) passThru
142 | , NRPN sqn_p 101 (0, 1) passThru
143 | , NRPN mcr1_p 105 (0, 183) passThru
144 | , NRPN mcr2_p 106 (0, 183) passThru
145 | , NRPN mcr3_p 107 (0, 183) passThru
146 | , NRPN mcr4_p 108 (0, 183) passThru
147 | , mNRPN shape_p 110
148 | , mrNRPN btnfreq_p 111 (0, 127)
149 | , mrNRPN btnvel_p 112 (0, 127)
150 | , NRPN btnmode_p 113 (0, 1) passThru
151 | , mNRPN pitch1_p 114
152 | , mNRPN pitch2_p 115
153 | , mNRPN fbvol_p 116
154 | -- left out: editor byte,
155 | , mrNRPN ksplitpoint_p 118 (0, 127)
156 | -- each patch has layer a/b
157 | , NRPN kmode_p 119 (0, 2) passThru -- 0: normal, 1: stack, both layers respond to full key range, 2: split at ksplitpoint
158 | , mCC notesoff_p 123
159 | , mCC ccreset_p 121
160 | , mCC damp_p 64
161 | ]
162 | , latency = 0.1
163 | }
164 |
165 | tetra = toShape tetraController
166 |
167 | (notesoff, notesoff_p) = pF "notesoff" (Just 0)
168 |
169 | (ccreset, ccreset_p) = pF "ccreset" (Just 0)
170 |
171 | (damp, damp_p) = pF "damp" (Just (-1))
172 |
173 | (osc1freq, osc1freq_p) = pF "osc1freq" (Just 0.2)
174 |
175 | (osc1detune, osc1detune_p) = pF "osc1detune" (Just 0.5)
176 |
177 | (osc1shape, osc1shape_p) = pI "osc1shape" (Just 1)
178 |
179 | (osc1glide, osc1glide_p) = pF "osc1glide" (Just 0)
180 |
181 | (osc1kbd, osc1kbd_p) = pI "osc1kbd" (Just 1)
182 |
183 | (osc2freq, osc2freq_p) = pF "osc2freq" (Just 0.2)
184 |
185 | (osc2detune, osc2detune_p) = pF "osc2detune" (Just 0.5)
186 |
187 | (osc2shape, osc2shape_p) = pI "osc2shape" (Just 1)
188 |
189 | (osc2glide, osc2glide_p) = pF "osc2glide" (Just 0)
190 |
191 | (osc2kbd, osc2kbd_p) = pI "osc2kbd" (Just 1)
192 |
193 | (oscsync, oscsync_p) = pF "oscsync" (Just 0)
194 |
195 | (glidemode, glidemode_p) = pI "glidemode" (Just 0)
196 |
197 | (oscslop, oscslop_p) = pF "oscslop" (Just 0)
198 |
199 | (oscmix, oscmix_p) = pF "oscmix" (Just 0.5)
200 |
201 | (noise, noise_p) = pF "noise" (Just 0)
202 |
203 | (kamt, kamt_p) = pF "kamt" (Just 0.5)
204 |
205 | -- overridden defaults for MIDI
206 | (_, cutoff_p) = pF "cutoff" (Just 1)
207 |
208 | (_, attack_p) = pF "attack" (Just 0.12)
209 |
210 | (_, release_p) = pF "release" (Just 0.01)
211 |
212 | (_, decay_p) = pF "decay" (Just 0.5)
213 |
214 | (_, sustain_p) = pF "sustain" (Just 0.5)
215 |
216 | (audiomod, audiomod_p) = pF "audiomod" (Just 0)
217 |
218 | (fpoles, fpoles_p) = pI "fpoles" (Just 0)
219 |
220 | twopole = fpoles "0"
221 |
222 | fourpole = fpoles "1"
223 |
224 | -- filter envelope
225 | (famt, famt_p) = pF "famt" (Just 0.5)
226 |
227 | (fvel, fvel_p) = pF "fvel" (Just 0)
228 |
229 | (fdel, fdel_p) = pF "fdel" (Just 0)
230 |
231 | (fatk, fatk_p) = pF "fatk" (Just 0.01)
232 |
233 | (fdcy, fdcy_p) = pF "fdcy" (Just 0)
234 |
235 | (fsus, fsus_p) = pF "fsus" (Just 0)
236 |
237 | (frel, frel_p) = pF "frel" (Just 0.01)
238 |
239 | (vcavol, vcavol_p) = pF "vcavol" (Just 0)
240 |
241 | (vamt, vamt_p) = pF "vamt" (Just 1)
242 |
243 | (vvel, vvel_p) = pF "vvel" (Just 0)
244 |
245 | (vdel, vdel_p) = pF "vdel" (Just 0)
246 |
247 | (lfo1rate, lfo1rate_p) = pF "lfo1rate" (Just 0)
248 |
249 | (lfo1shape, lfo1shape_p) = pI "lfo1shape" (Just 0)
250 |
251 | (lfo1amt, lfo1amt_p) = pF "lfo1amt" (Just 0)
252 |
253 | (lfo1dest, lfo1dest_p) = pF "lfo1dest" (Just 0)
254 |
255 | (lfo1sync, lfo1sync_p) = pI "lfo1sync" (Just 0)
256 |
257 | (lfo2rate, lfo2rate_p) = pF "lfo2rate" (Just 0)
258 |
259 | (lfo2shape, lfo2shape_p) = pI "lfo2shape" (Just 0)
260 |
261 | (lfo2amt, lfo2amt_p) = pF "lfo2amt" (Just 0)
262 |
263 | (lfo2dest, lfo2dest_p) = pF "lfo2dest" (Just 0)
264 |
265 | (lfo2sync, lfo2sync_p) = pI "lfo2sync" (Just 0)
266 |
267 | (lfo3rate, lfo3rate_p) = pF "lfo3rate" (Just 0)
268 |
269 | (lfo3shape, lfo3shape_p) = pI "lfo3shape" (Just 0)
270 |
271 | (lfo3amt, lfo3amt_p) = pF "lfo3amt" (Just 0)
272 |
273 | (lfo3dest, lfo3dest_p) = pF "lfo3dest" (Just 0)
274 |
275 | (lfo3sync, lfo3sync_p) = pI "lfo3sync" (Just 0)
276 |
277 | (lfo4rate, lfo4rate_p) = pF "lfo4rate" (Just 0)
278 |
279 | (lfo4shape, lfo4shape_p) = pI "lfo4shape" (Just 0)
280 |
281 | (lfo4amt, lfo4amt_p) = pF "lfo4amt" (Just 0)
282 |
283 | (lfo4dest, lfo4dest_p) = pF "lfo4dest" (Just 0)
284 |
285 | (lfo4sync, lfo4sync_p) = pI "lfo4sync" (Just 0)
286 |
287 | (emod, emod_p) = pF "emod" (Just 0)
288 |
289 | (eamt, eamt_p) = pF "eamt" (Just 0.5)
290 |
291 | (evel, evel_p) = pF "evel" (Just 0)
292 |
293 | (edel, edel_p) = pF "edel" (Just 0)
294 |
295 | (eatk, eatk_p) = pF "eatk" (Just 0.01)
296 |
297 | (edcy, edcy_p) = pF "edcy" (Just 0)
298 |
299 | (esus, esus_p) = pF "esus" (Just 0)
300 |
301 | (erel, erel_p) = pF "erel" (Just 0.01)
302 |
303 | (mod1src, mod1src_p) = pF "mod1src" (Just 0)
304 |
305 | (mod1amt, mod1amt_p) = pF "mod1amt" (Just 0.5)
306 |
307 | (mod1dst, mod1dst_p) = pF "mod1dst" (Just 0)
308 |
309 | (mod2src, mod2src_p) = pF "mod2src" (Just 0)
310 |
311 | (mod2amt, mod2amt_p) = pF "mod2amt" (Just 0.5)
312 |
313 | (mod2dst, mod2dst_p) = pF "mod2dst" (Just 0)
314 |
315 | (mod3src, mod3src_p) = pF "mod3src" (Just 0)
316 |
317 | (mod3amt, mod3amt_p) = pF "mod3amt" (Just 0.5)
318 |
319 | (mod3dst, mod3dst_p) = pF "mod3dst" (Just 0)
320 |
321 | (mod4src, mod4src_p) = pF "mod4src" (Just 0)
322 |
323 | (mod4amt, mod4amt_p) = pF "mod4amt" (Just 0.5)
324 |
325 | (mod4dst, mod4dst_p) = pF "mod4dst" (Just 0)
326 |
327 | (seq1dst, seq1dst_p) = pF "seq1dst" (Just 0)
328 |
329 | (seq2dst, seq2dst_p) = pF "seq2dst" (Just 0)
330 |
331 | (seq3dst, seq3dst_p) = pF "seq3dst" (Just 0)
332 |
333 | (seq4dst, seq4dst_p) = pF "seq4dst" (Just 0)
334 |
335 | (mwhl, mwhl_p) = pF "mwhl" (Just 0.5)
336 |
337 | (mwhldst, mwhldst_p) = pI "mwhldst" (Just 0)
338 |
339 | (aftt, aftt_p) = pF "aftt" (Just 0.5)
340 |
341 | (afttdst, afttdst_p) = pI "afttdst" (Just 0)
342 |
343 | (breath, breath_p) = pF "breath" (Just 0.5)
344 |
345 | (breathdst, breathdst_p) = pI "breathdst" (Just 0)
346 |
347 | (mvel, mvel_p) = pF "mvel" (Just 0.5)
348 |
349 | (mveldst, mveldst_p) = pI "mveldst" (Just 0)
350 |
351 | (foot, foot_p) = pF "foot" (Just 0.5)
352 |
353 | (footdst, footdst_p) = pI "footdst" (Just 0)
354 |
355 | (bendrng, bendrng_p) = pI "bendrng" (Just 0)
356 |
357 | -- left out: modwheel, breath, footctrl, pressure, velocity
358 | (kbpm, kbpm_p) = pI "kbpm" (Just 0)
359 |
360 | (clockdiv, clockdiv_p) = pI "clockdiv" (Just 0)
361 |
362 | -- left out: pitchbend range
363 | (sqntrig, sqntrig_p) = pF "sqntrig" (Just 0)
364 |
365 | (unisonkey, unisonkey_p) = pF "unisonkey" (Just 0)
366 |
367 | (unisonmode, unisonmode_p) = pF "unisonmode" (Just 0)
368 |
369 | (arpmode, arpmode_p) = pF "arpmode" (Just 0)
370 |
371 | (erepeat, erepeat_p) = pF "erepeat" (Just 0)
372 |
373 | (unison, unison_p) = pF "unison" (Just 0)
374 |
375 | (arp, arp_p) = pF "arp" (Just 0)
376 |
377 | (sqn, sqn_p) = pF "sqn" (Just 0)
378 |
379 | (mcr1, mcr1_p) = pI "mcr1" (Just 0)
380 |
381 | (mcr2, mcr2_p) = pI "mcr2" (Just 0)
382 |
383 | (mcr3, mcr3_p) = pI "mcr3" (Just 0)
384 |
385 | (mcr4, mcr4_p) = pI "mcr4" (Just 0)
386 |
387 | (btnfreq, btnfreq_p) = pF "btnfreq" (Just 0.25)
388 |
389 | (btnvel, btnvel_p) = pF "btnvel" (Just 1)
390 |
391 | (btnmode, btnmode_p) = pF "btnmode" (Just 0)
392 |
393 | (sub1vol, sub1vol_p) = pF "sub1vol" (Just 0)
394 |
395 | (sub2vol, sub2vol_p) = pF "sub2vol" (Just 0)
396 |
397 | (fbvol, fbvol_p) = pF "fbvol" (Just 0)
398 |
399 | (ksplitpoint, ksplitpoint_p) = pF "ksplitpoint" (Just 0.5)
400 |
401 | (kmode, kmode_p) = pF "kmode" (Just 0)
402 |
403 | knormal = kmode "0"
404 |
405 | kstack = kmode "0.5"
406 |
407 | ksplit = kmode "1"
408 |
409 | {-| Abstractions
410 |
411 | Though not yet finished, these are some examples on how to combine multiple parameters into one single function you can use within your patterns.
412 |
413 | Since Tidal 0.7 you can use the @grp@ method to allow things like:
414 |
415 | >>> t1 $ n (run 4) # adsr "0.1:0.6:0.3:0.9 0.8:0.3:0.9:0.1"
416 |
417 | which alternates between two filter envelope shapes, the first one with a sharp attack and a long decay/release and the latter with a long attack, high sustain and a short release.
418 |
419 | -}
420 | -- adsr
421 | adsr = grp [attack_p, decay_p, sustain_p, release_p]
422 |
423 | atk3 = grp [attack_p, fatk_p, eatk_p]
424 |
425 | dcy3 = grp [decay_p, fdcy_p, edcy_p]
426 |
427 | sus3 = grp [sustain_p, fsus_p, esus_p]
428 |
429 | rel3' = grp [release_p, frel_p, erel_p]
430 |
431 | -- lfo
432 | lfotri = doublePattern 0
433 |
434 | lforsaw = doublePattern 1
435 |
436 | lfosaw = doublePattern 2
437 |
438 | lfopulse = doublePattern 3
439 |
440 | lforand = doublePattern 4
441 |
442 | {-|
443 | A hack to handle a param with completely different behavior for certain parts of the range:
444 |
445 | @lrate@ is limited from 0 to 150 and specifies values that will produce an lfo frequency
446 |
447 | @lstep@ however is essentially limited from 0 to 16 and specifies values that will produce rhythmic lfo based on the _sequence speed_. as taken from the manual:
448 |
449 | 0: 32 steps
450 | 1: 16 steps
451 | 2: 8 steps
452 | 3: 6 steps
453 | 4: 4 steps
454 | 5: 3 steps
455 | 6: 2 steps
456 | 7: 1.5 steps
457 | 8: 1 step
458 | 9: 2/3 steps
459 | 10: 1/2 step
460 | 11: 1/3 step
461 | 12: 1/4 step
462 | 13: 1/6 step
463 | 14: 1/8 step
464 | 15: 1/16 step
465 |
466 | -}
467 | lrate r = min 150 . max 0 <$> r
468 |
469 | lstep s = min 166 . max 151 . (+ 150) <$> s
470 |
471 | lfo1 s d r a = lfo1shape s |+| lfo1dest d |+| lfo1rate r |+| lfo1amt a
472 |
473 | lfo2 s d r a = lfo2shape s |+| lfo2dest d |+| lfo2rate r |+| lfo2amt a
474 |
475 | lfo3 s d r a = lfo3shape s |+| lfo3dest d |+| lfo3rate r |+| lfo3amt a
476 |
477 | lfo4 s d r a = lfo4shape s |+| lfo4dest d |+| lfo4rate r |+| lfo4amt a
478 |
479 | -- mod
480 | mod1 s d a = mod1src s |+| mod1dst d |+| mod1amt a
481 |
482 | mod2 s d a = mod2src s |+| mod2dst d |+| mod2amt a
483 |
484 | mod3 s d a = mod3src s |+| mod3dst d |+| mod3amt a
485 |
486 | mod4 s d a = mod4src s |+| mod4dst d |+| mod4amt a
487 |
488 | {-| Modulation
489 |
490 | named sources and destinations to able to refer them for lfos, mods and also sequences.
491 | -}
492 | doublePattern d = atom d :: Pattern Double
493 |
494 | dosc1 = doublePattern 1
495 |
496 | dosc2 = doublePattern 2
497 |
498 | dosc = doublePattern 3
499 |
500 | dmix = doublePattern 4
501 |
502 | dnoise = doublePattern 5
503 |
504 | dpw1 = doublePattern 6
505 |
506 | dpw2 = doublePattern 7
507 |
508 | dpw = doublePattern 8
509 |
510 | dcut = doublePattern 9
511 |
512 | dres = doublePattern 10
513 |
514 | damod = doublePattern 11
515 |
516 | dvca = doublePattern 12
517 |
518 | dspread = doublePattern 13
519 |
520 | dlfo1f = doublePattern 14
521 |
522 | dlfo2f = doublePattern 15
523 |
524 | dlfo3f = doublePattern 16
525 |
526 | dlfo4f = doublePattern 17
527 |
528 | dlfof = doublePattern 18
529 |
530 | dlfo1a = doublePattern 19
531 |
532 | dlfo2a = doublePattern 20
533 |
534 | dlfo3a = doublePattern 21
535 |
536 | dlfo4a = doublePattern 22
537 |
538 | dlfoa = doublePattern 23
539 |
540 | dfamt = doublePattern 24
541 |
542 | dvamt = doublePattern 25
543 |
544 | deamt = doublePattern 26
545 |
546 | damt = doublePattern 27
547 |
548 | dfatk = doublePattern 28
549 |
550 | dvatk = doublePattern 29
551 |
552 | deatk = doublePattern 30
553 |
554 | datk = doublePattern 31
555 |
556 | dfdcy = doublePattern 32
557 |
558 | dvdcy = doublePattern 33
559 |
560 | dedcy = doublePattern 34
561 |
562 | ddcy = doublePattern 35
563 |
564 | dfrel = doublePattern 36
565 |
566 | dvrel = doublePattern 37
567 |
568 | derel = doublePattern 38
569 |
570 | drel = doublePattern 39
571 |
572 | dmod1 = doublePattern 40
573 |
574 | dmod2 = doublePattern 41
575 |
576 | dmod3 = doublePattern 42
577 |
578 | dmod4 = doublePattern 43
579 |
580 | dfb = doublePattern 44
581 |
582 | dsub1 = doublePattern 45
583 |
584 | dsub2 = doublePattern 46
585 |
586 | dshape = doublePattern 47
587 |
588 | dslew = doublePattern 48
589 |
590 | -- mod sources
591 | sseq1 = doublePattern 1
592 |
593 | sseq2 = doublePattern 2
594 |
595 | sseq3 = doublePattern 3
596 |
597 | sseq4 = doublePattern 4
598 |
599 | slfo1 = doublePattern 5
600 |
601 | slfo2 = doublePattern 6
602 |
603 | slfo3 = doublePattern 7
604 |
605 | slfo4 = doublePattern 8
606 |
607 | sfenv = doublePattern 9
608 |
609 | svenv = doublePattern 10
610 |
611 | seenv = doublePattern 11
612 |
613 | spitchb = doublePattern 12
614 |
615 | smodwh = doublePattern 13
616 |
617 | saftert = doublePattern 14
618 |
619 | sbreath = doublePattern 15
620 |
621 | sfoot = doublePattern 16
622 |
623 | sexpr = doublePattern 17
624 |
625 | svel = doublePattern 18
626 |
627 | snote = doublePattern 19
628 |
629 | snoise = doublePattern 20
630 |
631 | {-|
632 | Presets suck, but I constantly forget how to make drums
633 | with the TETR4, so here are some defaults (that can mostly be changed when using them)
634 | to make a snare and a kick.
635 |
636 | Use the snare like this:
637 |
638 | >>> t1 $ n "0(3,8)" # snare
639 |
640 | To make it shorter:
641 |
642 | >>> t1 $ n "0(3,8)" # snare |-| release "0.1" |-| decay "0.1"
643 | -}
644 | snare =
645 | fourpole |=| osc1shape "0" |+| osc1kbd "0" |+| osc2shape "0" |+| osc2kbd "0" |+|
646 | noise "1" |+|
647 | shape "0.7" |+|
648 | fbvol "0.3" |=|
649 | resonance "0.2" |+|
650 | release "0.3" |+|
651 | sustain "0" |+|
652 | decay "0.3" |+|
653 | cutoff "1" |+|
654 | dur "0.02"
655 |
656 | {-|
657 | usage would be:
658 |
659 | >>> t1 $ n "0 [[0 1] 1]" # kick
660 |
661 | you can change the defaults by applying merge operations for certain params:
662 |
663 | >>> t1 $ n "0(3,8)" # kick |+| edcy "0.05"
664 |
665 | will give the kick more resonance
666 |
667 | >>> t1 $ n "0(3,8)" # kick |-| edcy "0.15"
668 |
669 | will make it really dry
670 | -}
671 | kick =
672 | fourpole |+| osc1shape "0" |+| osc1kbd "0" |+| osc2shape "0" |+| osc2kbd "0" |+|
673 | sustain "0" |+|
674 | decay "0.95" |+|
675 | release "0.5" |+|
676 | resonance "0.99" |+|
677 | cutoff "0.001" |+|
678 | eamt "0.8" |+|
679 | emod "9" |+|
680 | edcy "0.2"
681 |
682 | {-|
683 | Since the TETR4 lacks a high-pass filter, things like snares and especially cymbals are somewhat limited to filtered noise which sounds okish.
684 |
685 | Therefore some presets for the different types of sounds you can get from the TETR4 can come in handy and can also be combined and modified with and through others:
686 | -}
687 | {-|
688 | A chip tune like sound, reminds me of gameboys
689 | -}
690 | chip =
691 | osc1shape "2" # osc2shape "2" |+| osc2freq "0.23" # osc1glide "0.05" #
692 | osc2glide "0.05" #
693 | glidemode "3" #
694 | release "0.78"
695 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/VolcaBass.hs:
--------------------------------------------------------------------------------
1 | module Sound.Tidal.MIDI.VolcaBass where
2 |
3 | import Sound.Tidal.MIDI.Control
4 | import Sound.Tidal.Params
5 |
6 | volcabassController :: ControllerShape
7 | volcabassController =
8 | ControllerShape
9 | { controls =
10 | [ mCC slide_p 5
11 | , mCC expression_p 11
12 | , mCC octave_p 40
13 | , mCC lfo_p 41
14 | , mCC lfoint_p 42
15 | , mCC pitch1_p 43
16 | , mCC pitch2_p 44
17 | , mCC pitch3_p 45
18 | , mCC attack_p 46
19 | , mCC decay_p 47
20 | , mCC cutoff_p 48
21 | , mCC gate_p 49
22 | ]
23 | , latency = 0.1
24 | }
25 |
26 | volcabass = toShape volcabassController
27 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/VolcaBeats.hs:
--------------------------------------------------------------------------------
1 | module Sound.Tidal.MIDI.VolcaBeats where
2 |
3 | import Sound.Tidal.MIDI.Control
4 | import Sound.Tidal.Params
5 |
6 | volcabeatsController :: ControllerShape
7 | volcabeatsController =
8 | ControllerShape
9 | { controls =
10 | [ mCC lkick_p 40
11 | , mCC lsnare_p 41
12 | , mCC llotom_p 42
13 | , mCC lhitom_p 43
14 | , mCC lclhat_p 44
15 | , mCC lophat_p 45
16 | , mCC lclap_p 46
17 | , mCC lclaves_p 47
18 | , mCC lagogo_p 48
19 | , mCC lcrash_p 49
20 | , mCC sclap_p 50
21 | , mCC sclaves_p 51
22 | , mCC sagogo_p 52
23 | , mCC scrash_p 53
24 | , mCC stuttertime_p 54
25 | , mCC stutterdepth_p 55
26 | , mCC tomdecay_p 56
27 | , mCC clhatdecay_p 57
28 | , mCC ophatdecay_p 58
29 | , mCC hatgrain_p 59
30 | ]
31 | , latency = 0.1
32 | }
33 |
34 | volcabeats = toShape volcabeatsController
35 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/VolcaFM.hs:
--------------------------------------------------------------------------------
1 | module Sound.Tidal.MIDI.VolcaFM where
2 |
3 | import Sound.Tidal.MIDI.Control
4 | import Sound.Tidal.Params
5 |
6 | volcafmController :: ControllerShape
7 | volcafmController =
8 | ControllerShape
9 | { controls =
10 | [ mCC octave_p 40
11 | , mCC velocity_p 41
12 | , mCC modattack_p 42
13 | , mCC moddecay_p 43
14 | , mCC carattack_p 44
15 | , mCC cardecay_p 45
16 | , mCC lfo_p 46
17 | , mCC lfopitchint_p 47
18 | , mCC algrtm_p 48
19 | , mCC arp_p 49
20 | , mCC arpdiv_p 50
21 | ]
22 | , latency = 0.1
23 | }
24 |
25 | (modattack, modattack_p) = pF "modattack" (Just 0)
26 |
27 | (moddecay, moddecay_p) = pF "moddecay" (Just 0)
28 |
29 | (carattack, carattack_p) = pF "carattack" (Just 0)
30 |
31 | (cardecay, cardecay_p) = pF "cardecay" (Just 0)
32 |
33 | (algrtm, algrtm_p) = pF "algrtm" (Just 0)
34 | algtm = algrtm
35 | algorithm = algrtm
36 |
37 | (arp, arp_p) = pF "arp" (Just 0)
38 |
39 | (arpdiv, arpdiv_p) = pF "arpdiv" (Just 0)
40 |
41 | volcafm = toShape volcafmController
42 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/VolcaKeys.hs:
--------------------------------------------------------------------------------
1 | module Sound.Tidal.MIDI.VolcaKeys where
2 |
3 | import Sound.Tidal.MIDI.Control
4 | import Sound.Tidal.Params
5 |
6 | volcakeysController :: ControllerShape
7 | volcakeysController =
8 | ControllerShape
9 | { controls =
10 | [ mCC portamento_p 5
11 | , mCC expression_p 11
12 | , mCC voice_p 40 -- voi
13 | , mCC octave_p 41 -- oct
14 | , mCC detune_p 42 -- det
15 | , mCC vcoegint_p 43 -- vco
16 | , mCC cutoff_p 44 -- ctf
17 | , mCC vcfegint_p 45 -- vcf
18 | , mCC lfo_p 46
19 | , mCC lfopitchint_p 47 -- lfop
20 | , mCC lfocutoffint_p 48 -- lfoc
21 | , mCC attack_p 49 -- att
22 | , mCC decay_p 50 -- dec
23 | , mCC sustain_p 51 -- sus
24 | , mCC delaytime_p 52 -- delayt
25 | , mCC delayfeedback_p 53 -- delayfb
26 | ]
27 | , latency = 0.1
28 | }
29 |
30 | volcakeys = toShape volcakeysController
31 |
--------------------------------------------------------------------------------
/Sound/Tidal/MIDI/VolcaKick.hs:
--------------------------------------------------------------------------------
1 | module Sound.Tidal.MIDI.VolcaKick where
2 |
3 | import Sound.Tidal.Params
4 | import Sound.Tidal.MIDI.Control
5 |
6 |
7 | volcakickController :: ControllerShape
8 | volcakickController =
9 | ControllerShape
10 | { controls =
11 | [ mCC pulsecolour_p 40
12 | , mCC pulselevel_p 41
13 | , mCC ampattack_p 42
14 | , mCC ampdecay_p 43
15 | , mCC drive_p 44
16 | , mCC tone_p 45
17 | , mCC pitch_p 46
18 | , mCC bend_p 47
19 | , mCC time_p 48
20 | , mCC accent_p 49
21 | ]
22 | , latency = 0.1
23 | }
24 |
25 | (pulsecolour, pulsecolour_p) = pF "pulsecolour" (Just 0)
26 |
27 | (pulselevel, pulselevel_p) = pF "pulselevel" (Just 0)
28 |
29 | (ampattack, ampattack_p) = pF "ampattack" (Just 0)
30 |
31 | (ampdecay, ampdecay_p) = pF "ampdecay" (Just 0)
32 |
33 | (drive, drive_p) = pF "drive" (Just 0)
34 |
35 | (tone, tone_p) = pF "tone" (Just 0)
36 |
37 | (pitch, pitch_p) = pF "pitch" (Just 0)
38 |
39 | (bend, bend_p) = pF "bend" (Just 0)
40 |
41 | (time, time_p) = pF "time" (Just 0)
42 |
43 | (accent, accent_p) = pF "accent" (Just 0)
44 |
45 | VolcaKick = toShape volcakickController
46 |
--------------------------------------------------------------------------------
/doc/blofeld-params.md:
--------------------------------------------------------------------------------
1 | #### Tidal params for Waldorf Blofeld
2 |
3 | | Blofeld | Tidal |
4 | |:-------------:|:-------------:|
5 | | mod wheel | mod_w |
6 | | breath control | br_ctrl |
7 | | foot control | ft_ctrl |
8 | | glide rate | gl_rate |
9 | | channel volume | ch_vol |
10 | | pan | pan_ |
11 | | arp range | arp_rng |
12 | | arp length | arp_len |
13 | | arp active | arp_act |
14 | | lfo 1 shape | lfo1shape |
15 | | lfo 1 speed | lfo1speed |
16 | | lfo 1 sync | lfo1sync |
17 | | lfo 1 delay | lfo1delay |
18 | | lfo 2 shape | lfo2shape |
19 | | lfo 2 speed | lfo2speed |
20 | | lfo 2 sync | lfo2sync |
21 | | lfo 2 delay | lfo2delay |
22 | | lfo 3 shape | lfo3shape |
23 | | lfo 3 speed | lfo3speed |
24 | | lfo 3 sync | lfo3sync |
25 | | lfo 3 delay | lfo3delay |
26 | | osc 1 octave | osc1oct |
27 | | osc 1 semitone | osc1semi |
28 | | osc 1 detune | osc1detune |
29 | | osc 1 fm | osc1fm |
30 | | osc 1 shape | osc1shape |
31 | | bank select LSB | bank_sel |
32 | | osc 1 pw | osc1pw |
33 | | osc 1 pwm | osc1pwm |
34 | | osc 2 octave | osc2oct |
35 | | osc 2 semitone | osc2semi |
36 | | osc 2 detune | osc2detune |
37 | | osc 2 fm | osc2fm |
38 | | osc 2 shape | osc2shape |
39 | | osc 2 pw | osc2pw |
40 | | osc 2 pwm | osc2pwm |
41 | | osc 3 octave | osc3oct |
42 | | osc 3 semitone | osc3semi |
43 | | osc 3 detune | osc3detune |
44 | | osc 3 fm | osc3fm |
45 | | osc 3 shape | osc3shape |
46 | | osc 3 pw | osc3pw |
47 | | osc 3 pwm | osc3pwm |
48 | | sync | sync |
49 | | pitchmod | pitchmod |
50 | | glide mode | glide_mode |
51 | | osc 1 level | osc1lvl |
52 | | osc 1 balance | osc1bal |
53 | | ringmod level | ringmod_lvl |
54 | | ringmod bal | ringmod_bal |
55 | | osc 2 level | osc2lvl |
56 | | osc 2 balance | osc2bal |
57 | | osc 3 level | osc3lvl |
58 | | osc 3 balance | osc3bal |
59 | | noise level | noise_lvl |
60 | | noise balance | noise_bal |
61 | | noise colour | noise_col |
62 | | sustain pedal | sus_ped |
63 | | glide active | glide_act |
64 | | sostenuto | sostenuto |
65 | | routing | routing |
66 | | filter 1 type | fil1tp |
67 | | filter 1 cutoff | fil1cut |
68 | | filter 1 resonance | fil1res |
69 | | filter 1 drive | fil1drv |
70 | | filter 1 keytrack | fil1key |
71 | | filter 1 env amnt | fil1enva |
72 | | filter 1 env vel | fil1envv |
73 | | filter 1 cutoff mod | fil1cutmo |
74 | | filter 1 fm | fil1fm |
75 | | filter 1 pan | fil1pan |
76 | | filter 1 panmod | fil1panmod |
77 | | filter 2 type | fil2tp |
78 | | filter 2 cutoff | fil2cut |
79 | | filter 2 resonance | fil2res |
80 | | filter 2 drive | fil2drv |
81 | | filter 2 keytrack | fil2key |
82 | | filter 2 env amnt | fil2enva |
83 | | filter 2 env vel | fil2envv |
84 | | filter 2 cutoff mod | fil2cutmo |
85 | | filter 2 fm | fil2fm |
86 | | filter 2 pan | fil2pan |
87 | | filter 2 panmod | fil2panmod |
88 | | amp volume | amp_vol |
89 | | amp velocity | amp_vel |
90 | | amp mod | amp_mod |
91 | | fx 1 mix | fx1mix |
92 | | fx 2 mix | fx2mix |
93 | | fe attack | fe_att |
94 | | fe decay | fe_dec |
95 | | fe sustain | fe_sus |
96 | | fe decay 2 | fe_dec2 |
97 | | fe sustain 2 | fe_sus2 |
98 | | fe release | fe_rel |
99 | | ae attack | ae_att |
100 | | ae decay | ae_dec |
101 | | ae sustain | ae_sus |
102 | | ae decay 2 | ae_dec2 |
103 | | ae sustain 2 | ae_sus2 |
104 | | ae release | ae_rel |
105 | | e3 attack | e3_att |
106 | | e3 decay | e3_dec |
107 | | e3 sustain | e3_sus |
108 | | e3 decay 2 | e3_dec2 |
109 | | e3 sustain 2 | e3_sus2 |
110 | | e3 release | e3_rel |
111 | | e4 attack | e4_att |
112 | | e4 decay | e4_dec |
113 | | e4 sustain | e4_sus |
114 | | e4 decay 2 | e4_dec2 |
115 | | e4 sustain 2 | e4_sus2 |
116 | | e4 release | e4_rel |
117 | | all sounds off | soff |
118 | | reset all controls | res_ctrl |
119 | | local control | loc_cont |
120 | | all notes off | noff |
121 |
122 |
--------------------------------------------------------------------------------
/doc/synth-mapping.md:
--------------------------------------------------------------------------------
1 | # Writing a new synth mapping
2 |
3 | If a MIDI device you own is not yet supported by tidal-midi you can write a Haskell module to map specific functions to certain parameters of your synth. Since every synth has a more or less different **set of parameters** the documentation of the various synthesizer parameters and their **corresponding MIDI CC** number is crucial for writing such a module.
4 |
5 | Most user guides for MIDI devices contain an appendix listing all of the supported MIDI commands it can receive. If you haven't got a digital copy of the user guide a simple way to get one is googling it. Due to recent request I will use the Waldorf Streichfett as an example of how to write such a mapping, starting with finding the original user guide pdf and the MIDI mapping information therein.
6 |
7 | Note that for your own synth MIDI CC values will be different and not all synths have the same capabilities (i.e. you cannot control the same parameters).
8 |
9 | ## A new synth mapping for _Waldorf Streichfett_
10 |
11 | ### Find the MIDI control table
12 |
13 | We Google up the user guide for the synthesizer: waldorf streichfett user guide pdf
14 |
15 | Top hit is the [original download link by waldorf music](http://www.waldorf-music.info/downloads/Streichfett/Streichfett%20Manual%20EN.pdf). In any case you should resort to the manufacturers downloads to avoid using an incorrect or otherwise different documentation. Make sure you have the same version of the device as written in the PDF, in this case there doesn't seem to be any revised or newer version of the Streichfett, so we choose this one.
16 |
17 | Within the PDF find the section with MIDI Controller numbers and implementation. Most of the time and certainly in this case it can be found within the appendix of the manual. Page 21 lists the MIDI Controller numbers for the synth.
18 |
19 | (To keep things simple, I'll not dig into the MIDI implementation listed afterwards, which makes it possible to gain even more control over the synth, this can be done in another tutorial)
20 |
21 | As soon as we have these information at hand, we can fire up an editor and start writing our new Haskell module for tidal-midi. ([Make sure you have cloned this repository first](https://github.com/tidalcycles/tidal-midi))
22 |
23 | ### Write the Haskell Module file
24 |
25 | We create a new file within `Sound/Tidal/MIDI/` from the source folder of tidal-midi called `Streichfett.hs`.
26 |
27 | Within this file we first declare our module within Tidal namespace:
28 |
29 | ```haskell
30 | module Sound.Tidal.MIDI.Streichfett where
31 | ```
32 |
33 | followed by two needed imports that give access to a few functions:
34 |
35 | ```haskell
36 | import Sound.Tidal.Params
37 | ```
38 |
39 | taken from Tidal itself we import `Params` to create parameter functions. These will be used to map our parameter names to named functions. We'll see how these are used later on.
40 |
41 | ```haskell
42 | import Sound.Tidal.MIDI.Control
43 | ```
44 |
45 | To create a configuration for Streichfett we need to import the `ControllerShape` type to define what kind of parameters this synthesizer has and which Midi controller numbers it uses.
46 |
47 | We start by defining a new `ControllerShape` that will be passed to any new streams to talk to the Streichfett. You can think of this shape as a way to tell tidal how to create messages sent to the Streichfett. Every time you want to talk to Streichfett, make sure you pass in this shape.
48 |
49 |
50 | #### Defining our own `ControllerShape`
51 | At first we define the simplest controller shape we can imagine defining only one parameter for the Streichfett along all need configuration options for a full shape:
52 |
53 | ```haskell
54 | fettController :: ControllerShape
55 | fettController = ControllerShape {
56 | controls = [
57 | mCC phaser_p 93
58 | ],
59 | latency = 0.1
60 | }
61 | ```
62 |
63 | That's a lot to take in at first and some things may not be of interest for you now, so let's focus on the main parts. We define our shape named `fett` which is of type `ControllerShape`. We give it two options: `controls` and `latency`.
64 |
65 | `controls` is a list to tell tidal how to map `Param` to MIDI control numbers. We map a new `Param` `phaser_p` to control change number `93` (see Streichfett manual).
66 | `latency` in seconds, tells tidal-midi streams to delay sending of midi messages by given time, so in this case **100ms**. Increase if you experience **late messages**!
67 |
68 | #### Creating our parameter functions
69 | Great, tidal-midi now knows about the shape of Streichfett messages, but it doesn't _yet_ know what `phaser_p` is.
70 |
71 | ```haskell
72 | (phaser, phaser_p) = pF "phaser" (Just 0)
73 | ```
74 |
75 | `phaser_p` is a floating point tidal param, `pF` named "phaser" and has a default of `0`.
76 | `phaser` is an action to make a pattern using our new param.
77 |
78 | We already use `phaser_p` in our controller shape and can play with `phaser` later!
79 |
80 | ...and that's it! If you really cannot wait, this is the minimal working example of your own synth mapping.
81 |
82 | #### Installing the mapping
83 |
84 | One last step is needed for really making use of it, namely telling the tidal-midi package about your module. Just add a line to `tidal-midi.cabal` under the key `exposed-modules`:
85 |
86 | ```
87 | ...
88 | library
89 | Exposed-modules: Sound.Tidal.MIDI.Context
90 | Sound.Tidal.MIDI.Control
91 | Sound.Tidal.MIDI.Device
92 | Sound.Tidal.MIDI.KorgKP3
93 | Sound.Tidal.MIDI.Stream
94 | Sound.Tidal.MIDI.Streichfett
95 | Sound.Tidal.MIDI.Synth
96 | Sound.Tidal.MIDI.SynthParams
97 | Sound.Tidal.MIDI.System1M
98 | Sound.Tidal.MIDI.VolcaBass
99 | Sound.Tidal.MIDI.VolcaBeats
100 | Sound.Tidal.MIDI.VolcaKeys
101 | ...
102 | ```
103 |
104 | After that do a ```cabal install``` within tidal-midi source.
105 |
106 | ## Tying it all together in Tidal
107 |
108 | ### Recap: tidal-midi boot
109 |
110 | Maybe you remember: we `import Sound.Tidal.MIDI.Context` to make tidal-midi work. This also gives us a simple synth that defines its own `ControllerShape` named __synthController__.
111 |
112 | So without having a custom tidal mapping for a synthesizer we just needed to create a stream to use from within Haskell. This stream wrote messages any simple synth could understand, and the __synthController__ shape told tidal how to do it:
113 |
114 | ```haskell
115 | devices <- midiDevices
116 | k1 <- midiStream devices "USB MIDI Device" 1 synthController
117 | ```
118 |
119 | notice how we passed __synthController__ to the midiStream that in turn created a stream for us that we can later use via `k1`, e.g. `k1 $ note "50" |+| modwheel "0.4"`
120 |
121 | So when you are finished with your new module, additionally `import Sound.Tidal.MIDI.YourSynthName` pass in your own controller shape `yourSynthNameController` instead of `synthController`.
122 |
123 | In the following example, we stick to `Streichfett` as _your synth name_.
124 |
125 | ### Using the Streichfett module
126 |
127 | To try your module, open or restart your editor for tidal (or `cd ~ && ghci -XOverloadedStrings`) and evaluate each of the following codes line by line, first imports:
128 |
129 | ```haskell
130 | import Sound.Tidal.MIDI.Context
131 | import Sound.Tidal.MIDI.Streichfett
132 | ```
133 |
134 | Then the usual steps to list the midi output devices and create the MIDI devices:
135 |
136 | ```haskell
137 | displayOutputDevices >>= putStrLn
138 | devices <- midiDevices
139 | ```
140 |
141 | Finally, we can define our midi stream `f1`:
142 |
143 | ```haskell
144 | f1 <- midiStream devices "USB Midi MIDI 1" 1 fettController
145 | ```
146 |
147 | Double check the device **name** **channel** and `ControllerShape` when you are finished,
148 | otherwise weird things, or, what would be worse: _nothing happens_.
149 |
150 | Then try out your new param:
151 |
152 | ```haskell
153 | f1 $ note "50(5,8)" |+| slow 3 (phaser sine1)
154 | ```
155 |
156 | Have fun and implement all the parameters but remember to reinstall via `cabal install` and restart your editor before you can use newly written parameters!
157 |
158 |
159 | ### Using our custom synth mapping in emacs
160 |
161 | To use your mapping, we need to integrate it within emacs. If you already have a setup for tidal-midi the following changes need to be made within your `tidal.el`. In addition to importing `Sound.Tidal.MIDI.Context` import `Sound.Tidal.MIDI.Streichfett` and create a new stream `f1` and pass `fettController` to `midiStream` instead of `synthController`.
162 |
163 | Restart emacs, start up tidal and try out the Streichfett specific phaser param on `f1`.
164 |
--------------------------------------------------------------------------------
/doc/synths.md:
--------------------------------------------------------------------------------
1 | # Supported Synths
2 |
3 | In addition to the simple synth (implemented by `synthController`), there are
4 | other custom implementations that support popular hardware synths:
5 |
6 | ## Korg Volca Keys
7 |
8 |
9 | Example:
10 | ```haskell
11 | import Sound.Tidal.MIDI.Context
12 | import Sound.Tidal.MIDI.VolcaKeys
13 |
14 | devices <- midiDevices
15 | m1 <- midiStream devices "USB MIDI Device" 1 keysController
16 | ```
17 |
18 | ## Korg Volca Bass
19 |
20 |
21 | Example:
22 | ```haskell
23 | import Sound.Tidal.MIDI.Context
24 | import Sound.Tidal.MIDI.VolcaBass
25 |
26 | devices <- midiDevices
27 | m1 <- midiStream devices "USB MIDI Device" 1 bassController
28 | ```
29 |
30 |
31 | ## Korg Volca Beats
32 |
33 |
34 | Example:
35 | ```haskell
36 | import Sound.Tidal.MIDI.Context
37 | import Sound.Tidal.MIDI.VolcaBeats
38 |
39 | devices <- midiDevices
40 | m1 <- midiStream devices "USB MIDI Device" 1 beatsController
41 | ```
42 |
43 | ## Waldorf Blofeld
44 |
45 |
46 | Example:
47 |
48 | ```haskell
49 | import Sound.Tidal.MIDI.Context
50 | import Sound.Tidal.Blofeld
51 |
52 | devices <- midiDevices
53 | m1 <- midiStream devices "USB MIDI Device" 1 blofeldController
54 |
55 | m1
56 | $ note "[7,14] ~ 4 9"
57 | # ae_rel "0.5"
58 | # osc1shape "4"
59 | ```
60 | * [Complete List](blofeld-params.md)
61 |
62 |
63 | ## DSI Tetra
64 |
65 |
66 | ### Example
67 |
68 | assumes the following Tetra Global parameters:
69 |
70 | * `Multi mode`: __On__
71 | * `M Param Rec`: __NRPN__
72 | * `MIDI Channel`: __1__
73 |
74 | ```haskell
75 | import Sound.Tidal.MIDI.Context
76 | import Sound.Tidal.Tetra
77 |
78 | devices <- midiDevices
79 | m1 <- midiStream devices "USB MIDI Device" 1 polysynth
80 | m2 <- midiStream devices "USB MIDI Device" 2 polysynth
81 | m3 <- midiStream devices "USB MIDI Device" 3 polysynth
82 | m4 <- midiStream devices "USB MIDI Device" 4 polysynth
83 | ```
84 |
--------------------------------------------------------------------------------
/tidal-midi.cabal:
--------------------------------------------------------------------------------
1 | name: tidal-midi
2 | version: 0.9.9
3 | synopsis: MIDI support for tidal
4 | -- description:
5 | homepage: http://tidal.lurk.org/
6 | license: GPL-3
7 | license-file: LICENSE
8 | author: Alex McLean
9 | maintainer: Alex McLean , Mike Hodnick
10 | Stability: Experimental
11 | Copyright: (c) Alex McLean and other contributors, 2015
12 | category: Sound
13 | build-type: Simple
14 | cabal-version: >=1.6
15 | -- Travis CI integration
16 | tested-with: GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.1
17 |
18 | Description: MIDI support for Tidal. Supports Volca Keys, Bass and Beats and other synths. Interface is likely to change significantly.
19 |
20 | library
21 | Exposed-modules: Sound.Tidal.MIDI.Context
22 | Sound.Tidal.MIDI.Control
23 | Sound.Tidal.MIDI.Device
24 | Sound.Tidal.MIDI.Stream
25 | Sound.Tidal.MIDI.Output
26 | Sound.Tidal.MIDI.CC
27 | Sound.Tidal.MIDI.GMPerc
28 | Sound.Tidal.MIDI.Synth
29 | Sound.Tidal.MIDI.Synthino
30 | Sound.Tidal.MIDI.Blofeld
31 | Sound.Tidal.MIDI.MBase01
32 | Sound.Tidal.MIDI.Tetra
33 | Sound.Tidal.MIDI.Ambika
34 | Sound.Tidal.MIDI.MiniAtmegatron
35 | Sound.Tidal.MIDI.VolcaBeats
36 | Sound.Tidal.MIDI.VolcaBass
37 | Sound.Tidal.MIDI.VolcaKeys
38 | Sound.Tidal.MIDI.VolcaFM
39 | Sound.Tidal.MIDI.System1M
40 | Sound.Tidal.MIDI.KorgKP3
41 | Sound.Tidal.MIDI.VolcaKick
42 |
43 | Build-depends: base < 5, tidal >= 0.9.9, PortMidi >= 0.1.6.0 && <0.2, time, containers, transformers
44 |
45 | source-repository head
46 | type: git
47 | location: https://github.com/tidalcycles/tidal-midi
48 |
--------------------------------------------------------------------------------