Browse Source

Cbox is now a system-wide library and the python module is integrated locally into the template without python sys searchpath injections

master
Nils 2 years ago
parent
commit
b5f271d5c5
  1. 32
      template/calfbox/.gitignore
  2. 133
      template/calfbox/API
  3. 1
      template/calfbox/AUTHORS
  4. 674
      template/calfbox/COPYING
  5. 0
      template/calfbox/ChangeLog
  6. 365
      template/calfbox/INSTALL
  7. 152
      template/calfbox/Makefile.am
  8. 0
      template/calfbox/NEWS
  9. 1
      template/calfbox/README
  10. 63
      template/calfbox/README.md
  11. 0
      template/calfbox/__init__.py
  12. 18
      template/calfbox/_cbox2.py
  13. 47
      template/calfbox/adhoc_example.py
  14. 391
      template/calfbox/app.c
  15. 51
      template/calfbox/app.h
  16. 466
      template/calfbox/appmenu.c
  17. 6
      template/calfbox/autogen.sh
  18. 102
      template/calfbox/auxbus.c
  19. 47
      template/calfbox/auxbus.h
  20. 6
      template/calfbox/background_example.py
  21. 398
      template/calfbox/biquad-float.h
  22. 130
      template/calfbox/blob.c
  23. 39
      template/calfbox/blob.h
  24. 11
      template/calfbox/cbox.py
  25. 574
      template/calfbox/cboxrc-example
  26. 175
      template/calfbox/chorus.c
  27. 11
      template/calfbox/cleanpythonbuild.sh
  28. 208
      template/calfbox/cmd.c
  29. 64
      template/calfbox/cmd.h
  30. 155
      template/calfbox/compressor.c
  31. 357
      template/calfbox/config-api.c
  32. 53
      template/calfbox/config-api.h
  33. 162
      template/calfbox/configure.ac
  34. 139
      template/calfbox/delay.c
  35. 138
      template/calfbox/distortion.c
  36. 372
      template/calfbox/dom.c
  37. 155
      template/calfbox/dom.h
  38. 0
      template/calfbox/drum_pattern_editor.py
  39. 0
      template/calfbox/drumkit_editor.py
  40. 152
      template/calfbox/drvjunk/miditest.py
  41. 255
      template/calfbox/drvjunk/omega.c
  42. 243
      template/calfbox/dspmath.h
  43. 445
      template/calfbox/engine.c
  44. 72
      template/calfbox/engine.h
  45. 324
      template/calfbox/envelope.h
  46. 194
      template/calfbox/eq.c
  47. 31
      template/calfbox/eq.h
  48. 70
      template/calfbox/errors.c
  49. 44
      template/calfbox/errors.h
  50. 554
      template/calfbox/example.py
  51. 57
      template/calfbox/experiments/interactive.py
  52. 602
      template/calfbox/experiments/meta.py
  53. 51
      template/calfbox/experiments/playPatternsAsMeasures.py
  54. 32
      template/calfbox/experiments/printAllMidiEvents.py
  55. 35
      template/calfbox/experiments/printAllMidiEventsSpecificPort.py
  56. 79
      template/calfbox/experiments/printNotesOnlyDuringPlayback.py
  57. 30
      template/calfbox/experiments/simplePlayback.py
  58. 25
      template/calfbox/experiments/simplerPlayback.py
  59. 82
      template/calfbox/experiments/testmetadata.py
  60. 373
      template/calfbox/fbr.c
  61. 22
      template/calfbox/fifo.c
  62. 136
      template/calfbox/fifo.h
  63. 444
      template/calfbox/fluid.c
  64. 173
      template/calfbox/fuzz.c
  65. 0
      template/calfbox/fx_gui.py
  66. 231
      template/calfbox/fxchain.c
  67. 181
      template/calfbox/gate.c
  68. 0
      template/calfbox/gui_tools.py
  69. 172
      template/calfbox/hwcfg.c
  70. 28
      template/calfbox/hwcfg.h
  71. 251
      template/calfbox/instr.c
  72. 61
      template/calfbox/instr.h
  73. 0
      template/calfbox/instr_gui.py
  74. 625
      template/calfbox/io.c
  75. 194
      template/calfbox/io.h
  76. 46
      template/calfbox/ioenv.h
  77. 177
      template/calfbox/jack_api_example.py
  78. 65
      template/calfbox/jack_audio_routing.py
  79. 50
      template/calfbox/jack_output_routing.py
  80. 36
      template/calfbox/jack_scene_routing.py
  81. 153
      template/calfbox/jackinput.c
  82. 1429
      template/calfbox/jackio.c
  83. 293
      template/calfbox/layer.c
  84. 63
      template/calfbox/layer.h
  85. 154
      template/calfbox/limiter.c
  86. 450
      template/calfbox/main.c
  87. 389
      template/calfbox/master.c
  88. 100
      template/calfbox/master.h
  89. 288
      template/calfbox/menu.c
  90. 67
      template/calfbox/menu.h
  91. 303
      template/calfbox/menuitem.c
  92. 133
      template/calfbox/menuitem.h
  93. 5
      template/calfbox/metadata.py
  94. 137
      template/calfbox/meter.c
  95. 38
      template/calfbox/meter.h
  96. 113
      template/calfbox/midi.c
  97. 125
      template/calfbox/midi.h
  98. 254
      template/calfbox/mididest.c
  99. 76
      template/calfbox/mididest.h
  100. 270
      template/calfbox/module.c

32
template/calfbox/.gitignore

@ -1,32 +0,0 @@
aclocal.m4
autom4te.cache
config.h.in
config.h.in~
config.h
configure
configure~
compile
depcomp
install-sh
ltmain.sh
missing
*.o
*.lo
.libs/
.deps/
libcalfbox.la
libtool
Makefile.in
Makefile
config.log
config.status
stamp-h1
calfbox
calfbox_tests
__pycache__/
*.py[cod]
*$py.class
build/
config.guess
config.sub

133
template/calfbox/API

@ -1,133 +0,0 @@
@module >> @chorus, @phaser, ...
@moduleslot/status() ->
/insert_engine(string engine),
/insert_preset(string preset),
/bypass(int bypassed)
@moduleslot/insert_engine(string engine)
@moduleslot/insert_preset(string engine)
@moduleslot/engine/{add: @module}
@moduleslot/set_bypass(int bypassed)
@track/add_clip(int pos, int offset, int length, string pattern)
/master/
/master/status() -> /sample_rate, /tempo, /timesig, /playing, /pos, /pos_ppqn
/master/tell() -> /playing, /pos, /pos_ppqn
/master/set_tempo(float tempo)
/master/set_timesig(int num, int denom)
/master/play()
/master/stop()
/master/seek_samples(int samples)
/master/seek_ppqn(int ppqn)
/meter/
/meter/get_peak() -> /peak(float left, float right)
/meter/get_rms() -> /rms(float left, float right)
/config/
/config/sections([string prefix]) -> [/section(string name)]
/config/keys(string section, string ?prefix) -> [/section(string name)]
/config/get(string section, string key) -> /value(string value)
/config/set(string section, string key, string value)
/config/delete(string section, string key)
/config/delete_section(string section)
/config/save(string ?filename)
/engine/
/engine/status() -> /scene(object scene)
/engine/render_stereo(int nframes)
/engine/master_effect/{add: @moduleslot}
/engine/new_scene() -> uuid
/engine/new_recorder() -> uuid
/scene/
/scene/transpose(int semitones)
/scene/clear()
/scene/load(string scene_name)
/scene/add_layer(int layer_pos, string layer_name)
/scene/add_instrument_layer(int layer_pos, string instrument_name)
/scene/delete_layer(int pos)
/scene/move_layer(int oldpos, int newpos)
/scene/instr/
/scene/instr/<name>/status() ->
/engine(string name),
/aux_offset(int first_aux_output_no),
/outputs(int stereo_output_count)
/scene/instr/<name>/output/<index>/status() ->
/gain_linear(float gain),
/gain(float gain_dB),
/output(int output_bus),
{add: @moduleslot/status()}
/scene/instr/<name>/output/<index>/gain(float gain_dB),
/scene/instr/<name>/output/<index>/output(int output_bus)
/scene/instr/<name>/output/<index>/{add: @moduleslot}
/scene/instr/<name>/aux/<index>/status() ->
/gain_linear(float gain),
/gain(float gain_dB),
/bus(string output_bus),
{add: @moduleslot/status()} XXXKF ????
/scene/instr/<name>/aux/<index>/gain(float gain_dB)
/scene/instr/<name>/aux/<index>/bus(string bus)
/scene/instr/<name>/aux/<index>/{add: @moduleslot}
/scene/layer/<index>/
/scene/layer/<index>/status() ->
/enable(int),
/instrument_name(string iname),
/instrument_uuid(string uuid),
/consume(int consume),
/ignore_scene_transpose(int ignore),
/disable_aftertouch(int disable),
/transpose(int semitones),
/fixed_note(int note),
/low_note(int note),
/high_note(int note),
/in_channel(int channel),
/out_channel(int channel)
/scene/layer/<index>/enable(int)
/scene/layer/<index>/instrument_name(string iname)
/scene/layer/<index>/consume(int consume)
/scene/layer/<index>/ignore_scene_transpose(int ignore)
/scene/layer/<index>/disable_aftertouch(int disable)
/scene/layer/<index>/transpose(int semitones)
/scene/layer/<index>/fixed_note(int note)
/scene/layer/<index>/low_note(int note)
/scene/layer/<index>/high_note(int note)
/scene/layer/<index>/in_channel(int channel)
/scene/layer/<index>/out_channel(int channel)
/scene/aux/<name>/status
/scene/aux/<name>/slot/{add: @module}
/scene/load_aux(string name)
/scene/delete_aux(string name)
/scene/status() ->
/name(string),
/title(string),
/transpose(int semitones),
[/layer(string uuid)],
[/instrument(string instance, string engine)],
[/aux(string name, string uuid)]
/rt/
/rt/status() -> /audio_channels(int inputs, int outputs)
/song/
/song/status() -> [/track(int index, string name, int items)], [/pattern(int index, string name, int length)]
/waves/
/waves/status() -> /bytes(int bytes), /max_bytes(int max_bytes), /count(int count)
/waves/list() -> [/waveform(int id)]
/waves/info(int id) -> /filename(string), /name(string), /bytes(int)
/on_idle() -> {any}
/send_event_to(string output, int)
/send_event_to(string output, int, int)
/send_event_to(string output, int, int, int)
/play_note(int ch, int note, int velocity) (plays a note with duration=1 on the next buffer)
/play_drum_pattern(string pattern)
/play_drum_track(string track)
/play_blob(blob serialized_pattern, int length_ticks)
/stop_pattern()
/get_pattern() -> /pattern(blob serialized_pattern, int length_ticks)
/print_s(string)
/print_i(int)
/print_f(float)
/new_meter() -> /uuid
/new_recorder(string filename) -> /uuid

1
template/calfbox/AUTHORS

@ -1 +0,0 @@
Krzysztof Foltman <wdev@foltman.com>

674
template/calfbox/COPYING

@ -1,674 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

0
template/calfbox/ChangeLog

365
template/calfbox/INSTALL

@ -1,365 +0,0 @@
Installation Instructions
*************************
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
2006, 2007, 2008, 2009 Free Software Foundation, Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. This file is offered as-is,
without warranty of any kind.
Basic Installation
==================
Briefly, the shell commands `./configure; make; make install' should
configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for
instructions specific to this package. Some packages provide this
`INSTALL' file but do not implement all of the features documented
below. The lack of an optional feature in a given package is not
necessarily a bug. More recommendations for GNU packages can be found
in *note Makefile Conventions: (standards)Makefile Conventions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. Caching is
disabled by default to prevent problems with accidental use of stale
cache files.
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You need `configure.ac' if
you want to change it or regenerate `configure' using a newer version
of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system.
Running `configure' might take a while. While running, it prints
some messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package, generally using the just-built uninstalled binaries.
4. Type `make install' to install the programs and any data files and
documentation. When installing into a prefix owned by root, it is
recommended that the package be configured and built as a regular
user, and only the `make install' phase executed with root
privileges.
5. Optionally, type `make installcheck' to repeat any self-tests, but
this time using the binaries in their final installed location.
This target does not install anything. Running this target as a
regular user, particularly if the prior `make install' required
root privileges, verifies that the installation completed
correctly.
6. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
7. Often, you can also type `make uninstall' to remove the installed
files again. In practice, not all packages have tested that
uninstallation works correctly, even though it is required by the
GNU Coding Standards.
8. Some packages, particularly those that use Automake, provide `make
distcheck', which can by used by developers to test that all other
targets like `make install' and `make uninstall' work correctly.
This target is generally not run by end users.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. Run `./configure --help'
for details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
is an example:
./configure CC=c99 CFLAGS=-g LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you can use GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'. This
is known as a "VPATH" build.
With a non-GNU `make', it is safer to compile the package for one
architecture at a time in the source code directory. After you have
installed the package for one architecture, use `make distclean' before
reconfiguring for another architecture.
On MacOS X 10.5 and later systems, you can create libraries and
executables that work on multiple system types--known as "fat" or
"universal" binaries--by specifying multiple `-arch' options to the
compiler but only a single `-arch' option to the preprocessor. Like
this:
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CPP="gcc -E" CXXCPP="g++ -E"
This is not guaranteed to produce working output in all cases, you
may have to build one architecture at a time and combine the results
using the `lipo' tool if you have problems.
Installation Names
==================
By default, `make install' installs the package's commands under
`/usr/local/bin', include files under `/usr/local/include', etc. You
can specify an installation prefix other than `/usr/local' by giving
`configure' the option `--prefix=PREFIX', where PREFIX must be an
absolute file name.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=DIR' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them. In general, the
default for these options is expressed in terms of `${prefix}', so that
specifying just `--prefix' will affect all of the other directory
specifications that were not explicitly provided.
The most portable way to affect installation locations is to pass the
correct locations to `configure'; however, many packages provide one or
both of the following shortcuts of passing variable assignments to the
`make install' command line to change installation locations without
having to reconfigure or recompile.
The first method involves providing an override variable for each
affected directory. For example, `make install
prefix=/alternate/directory' will choose an alternate location for all
directory configuration variables that were expressed in terms of
`${prefix}'. Any directories that were specified during `configure',
but not in terms of `${prefix}', must each be overridden at install
time for the entire installation to be relocated. The approach of
makefile variable overrides for each directory variable is required by
the GNU Coding Standards, and ideally causes no recompilation.
However, some platforms have known limitations with the semantics of
shared libraries that end up requiring recompilation when using this
method, particularly noticeable in packages that use GNU Libtool.
The second method involves providing the `DESTDIR' variable. For
example, `make install DESTDIR=/alternate/directory' will prepend
`/alternate/directory' before all installation names. The approach of
`DESTDIR' overrides is not required by the GNU Coding Standards, and
does not work on platforms that have drive letters. On the other hand,
it does better at avoiding recompilation issues, and works well even
when some directory options were not specified in terms of `${prefix}'
at `configure' time.
Optional Features
=================
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Some packages offer the ability to configure how verbose the
execution of `make' will be. For these packages, running `./configure
--enable-silent-rules' sets the default to minimal output, which can be
overridden with `make V=1'; while running `./configure
--disable-silent-rules' sets the default to verbose, which can be
overridden with `make V=0'.
Particular systems
==================
On HP-UX, the default C compiler is not ANSI C compatible. If GNU
CC is not installed, it is recommended to use the following options in
order to use an ANSI C compiler:
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
parse its `<wchar.h>' header file. The option `-nodtk' can be used as
a workaround. If GNU CC is not installed, it is therefore recommended
to try
./configure CC="cc"
and if that doesn't work, try
./configure CC="cc -nodtk"
On Solaris, don't put `/usr/ucb' early in your `PATH'. This
directory contains several dysfunctional programs; working variants of
these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
in your `PATH', put it _after_ `/usr/bin'.
On Haiku, software installed for all users goes in `/boot/common',
not `/usr/local'. It is recommended to use the following options:
./configure --prefix=/boot/common
Specifying the System Type
==========================
There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of machine the package
will run on. Usually, assuming the package is built to be run on the
_same_ architectures, `configure' can figure that out, but if it prints
a message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS
KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the option `--target=TYPE' to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
causes the specified `gcc' to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
an Autoconf bug. Until the bug is fixed you can use this workaround:
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
`configure' Invocation
======================
`configure' recognizes the following options to control how it
operates.
`--help'
`-h'
Print a summary of all of the options to `configure', and exit.
`--help=short'
`--help=recursive'
Print a summary of the options unique to this package's
`configure', and exit. The `short' variant lists options used
only in the top level, while the `recursive' variant lists options
also present in any nested packages.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--prefix=DIR'
Use DIR as the installation prefix. *note Installation Names::
for more details, including other options available for fine-tuning
the installation locations.
`--no-create'
`-n'
Run the configure checks, but stop before creating any output
files.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

152
template/calfbox/Makefile.am

@ -1,152 +0,0 @@
AM_CPPFLAGS = -I$(srcdir) -Wall -Wsign-compare -D_GNU_SOURCE
AM_CFLAGS = $(JACK_DEPS_CFLAGS) $(GLIB_DEPS_CFLAGS) $(FLUIDSYNTH_DEPS_CFLAGS) $(PYTHON_DEPS_CFLAGS) $(LIBSMF_DEPS_CFLAGS) $(LIBSNDFILE_DEPS_CFLAGS) $(LIBUSB_DEPS_CFLAGS) $(ARCH_OPT_CFLAGS) $(NCURSES_DEPS_CFLAGS)
lib_LTLIBRARIES = libcalfbox.la
bin_PROGRAMS = calfbox
noinst_PROGRAMS = calfbox_tests
calfbox_SOURCES = \
appmenu.c \
main.c \
menu.c \
menuitem.c \
ui.c
calfbox_LDADD = libcalfbox.la $(JACK_DEPS_LIBS) $(GLIB_DEPS_LIBS) $(FLUIDSYNTH_DEPS_LIBS) $(PYTHON_DEPS_LIBS) $(LIBSMF_DEPS_LIBS) $(LIBSNDFILE_DEPS_LIBS) $(LIBUSB_DEPS_LIBS) $(NCURSES_DEPS_LIBS) -lpthread -luuid -lm -lrt
calfbox_tests_SOURCES = \
tests.c
calfbox_tests_LDADD = libcalfbox.la $(GLIB_DEPS_LIBS) -lpthread -lm -lrt
libcalfbox_la_SOURCES = \
app.c \
auxbus.c \
blob.c \
chorus.c \
cmd.c \
compressor.c \
config-api.c \
delay.c \
distortion.c \
dom.c \
engine.c \
eq.c \
errors.c \
fbr.c \
fifo.c \
fluid.c \
fuzz.c \
fxchain.c \
gate.c \
hwcfg.c \
instr.c \
io.c \
jackinput.c \
jackio.c \
layer.c \
limiter.c \
master.c \
meter.c \
midi.c \
mididest.c \
module.c \
pattern.c \
pattern-maker.c \
phaser.c \
prefetch_pipe.c \
recsrc.c \
reverb.c \
rt.c \
sampler.c \
sampler_channel.c \
sampler_gen.c \
sampler_layer.c \
sampler_nif.c \
sampler_prevoice.c \
sampler_prg.c \
sampler_rll.c \
sampler_voice.c \
scene.c \
scripting.c \
seq.c \
seq-adhoc.c \
sfzloader.c \
sfzparser.c \
song.c \
streamplay.c \
streamrec.c \
tarfile.c \
tonectl.c \
tonewheel.c \
track.c \
usbaudio.c \
usbio.c \
usbmidi.c \
usbprobe.c \
wavebank.c
libcalfbox_la_LIBADD = $(JACK_DEPS_LIBS) $(GLIB_DEPS_LIBS) $(FLUIDSYNTH_DEPS_LIBS) $(PYTHON_DEPS_LIBS) $(LIBSMF_DEPS_LIBS) $(LIBSNDFILE_DEPS_LIBS) $(LIBUSB_DEPS_LIBS) -lpthread -luuid -lm -lrt
if USE_SSE
ARCH_OPT_CFLAGS=-msse -ffast-math
else
if USE_NEON
ARCH_OPT_CFLAGS=-mfloat-abi=hard -mfpu=neon -ffast-math
endif
endif
noinst_HEADERS = \
app.h \
auxbus.h \
biquad-float.h \
blob.h \
cmd.h \
config-api.h \
dom.h \
dspmath.h \
envelope.h \
engine.h \
eq.h \
errors.h \
fifo.h \
hwcfg.h \
instr.h \
io.h \
ioenv.h \
layer.h \
master.h \
menu.h \
menuitem.h \
meter.h \
midi.h \
mididest.h \
module.h \
onepole-int.h \
onepole-float.h \
pattern.h \
pattern-maker.h \
prefetch_pipe.h \
recsrc.h \
rt.h \
sampler.h \
sampler_impl.h \
sampler_layer.h \
sampler_prg.h \
scene.h \
scripting.h \
seq.h \
sfzloader.h \
sfzparser.h \
song.h \
stm.h \
tarfile.h \
tests.h \
track.h \
ui.h \
usbio_impl.h \
wavebank.h
EXTRA_DIST = cboxrc-example

0
template/calfbox/NEWS

1
template/calfbox/README

@ -1 +0,0 @@
README.md

63
template/calfbox/README.md

@ -1,63 +0,0 @@
# Calfbox
Website: https://github.com/kfoltman/calfbox
Calfbox, the "open source musical instrument", offers assorted music-related code.
Originally intended as a standalone instrument for Linux and embedded devices (USB TV Sticks)
it can be used as Python module as well.
# Packaging
If you are a packager and want to create a binary package for your distribution please package only the python module.
The binary executable is not maintained and untested at the moment. It should not be used by anyone.
# Calfbox as Python Module
Calfbox can be used as a Python module that can be imported to create short scripts or
full fledged programs ( https://www.laborejo.org/software ).
Most notably it features a midi sequencer and an audio sampler (for sfz files and sf2 via fluidsynth).
## Building
A convenience script `cleanpythonbuild.py` has been supplied to quickly build and install the cbox python module.
```
make clean
rm build -rf
sh autogen.sh
./configure
make
python3 setup.py build
sudo python3 setup.py install
```
## How to write programs with cbox
You can find several `.py` files in the main directory, such as `sampler_api_example.py` or
`song_api_example.py`.
Also there is a directory `/experiments` which contains a small example framework.
# Using Calfbox as standalone instrument
Using Calfbox as standalone instrument requires a .cfg config file.
This part of the program is currently unmaintained and untested. Please do not use it.
# License
This code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
For the full license see the file COPYING

0
template/calfbox/py/__init__.py → template/calfbox/__init__.py

18
template/calfbox/py/_cbox2.py → template/calfbox/_cbox2.py

@ -96,13 +96,23 @@ class PyCmdTarget(CmdTarget):
def find_calfbox():
if "CALFBOXLIBABSPATH" in os.environ:
assert os.path.exists(os.environ["CALFBOXLIBABSPATH"])
logging.info("Searching for calfbox shared library with absolute path: %s", (os.environ["CALFBOXLIBABSPATH"]))
assert os.path.exists(os.environ["CALFBOXLIBABSPATH"]), os.environ["CALFBOXLIBABSPATH"]
cblib = os.environ["CALFBOXLIBABSPATH"]
elif "CALFBOXLIBFILENAME" in os.environ:
#This should be just name of the lib, not a filename and no "lib"-prefix. For example "calfbox" if the real name is libcalfbox.so.1
logging.info("Searching for calfbox shared library with just the filename: %s", (os.environ["CALFBOXLIBFILENAME"]))
cblib = find_library(os.environ["CALFBOXLIBFILENAME"])
else:
cblib = find_library('calfbox')
logging.info("Loading calfbox shared library: %s" % (cblib))
cb = cdll.LoadLibrary(cblib)
return cb
if cblib:
logging.info("Loading calfbox shared library: %s" % (cblib))
cb = cdll.LoadLibrary(cblib)
return cb
else:
raise FileNotFoundError("Calfbox shared library not found: %s" % (cblib))
cb = find_calfbox()
cb.cbox_embed_get_cmd_root.restype = CmdTargetPtr

47
template/calfbox/adhoc_example.py

@ -1,47 +0,0 @@
import os
import sys
import struct
import time
import unittest
sys.path = ["./py"] + sys.path
import cbox
global Document
global Transport
Document = cbox.Document
Transport = cbox.Transport
song = Document.get_song()
# Delete all the tracks and patterns
song.clear()
# Create a binary blob that contains the MIDI events
pblob = bytes()
for noteindex in range(20):
# note on
pblob += cbox.Pattern.serialize_event(noteindex * 12, 0x90, 36+noteindex*3, 127)
# note off
pblob += cbox.Pattern.serialize_event(noteindex * 12 + 11, 0x90, 36+noteindex*3, 0)
# This will be the length of the pattern (in pulses). It should be large enough
# to fit all the events
pattern_len = 10 * 24 * 2
# Create a new pattern object using events from the blob
pattern = song.pattern_from_blob(pblob, pattern_len)
retrig = 10
i = 0
while i < 50:
i += 1
retrig -= 1
if retrig <= 0:
print ("Triggering adhoc pattern with ID 1")
Document.get_scene().play_pattern(pattern, 240, 0)
retrig = 5
# Query JACK ports, new USB devices etc.
cbox.call_on_idle()
time.sleep(0.1)

391
template/calfbox/app.c

@ -1,391 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2013 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "app.h"
#include "blob.h"
#include "config-api.h"
#include "engine.h"
#include "instr.h"
#include "io.h"
#include "layer.h"
#include "menu.h"
#include "menuitem.h"
#include "meter.h"
#include "midi.h"
#include "module.h"
#include "scene.h"
#include "seq.h"
#include "song.h"
#include "track.h"
#include "ui.h"
#include "wavebank.h"
#include <assert.h>
#include <glib.h>
#include <glob.h>
#include <getopt.h>
#include <math.h>
#include <ncurses.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
static gboolean lookup_midi_merger(const char *output, struct cbox_midi_merger **pmerger, GError **error)
{
if (*output)
{
struct cbox_uuid uuid;
if (!cbox_uuid_fromstring(&uuid, output, error))
return FALSE;
*pmerger = cbox_rt_get_midi_output(app.rt, &uuid);
if (!*pmerger)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Unknown MIDI output UUID: '%s'", output);
return FALSE;
}
}
else
{
if (!app.engine->scene_count)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Scene not set");
return FALSE;
}
*pmerger = &app.engine->scenes[0]->scene_input_merger;
}
return TRUE;
}
static gboolean app_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
if (!cmd->command)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "NULL command");
return FALSE;
}
if (cmd->command[0] != '/')
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Invalid global command path '%s'", cmd->command);
return FALSE;
}
const char *obj = &cmd->command[1];
const char *pos = strchr(obj, '/');
if (pos)
{
if (!strncmp(obj, "master/", 7))
return cbox_execute_sub(&app.engine->master->cmd_target, fb, cmd, pos, error);
else
if (!strncmp(obj, "config/", 7))
return cbox_execute_sub(&app.config_cmd_target, fb, cmd, pos, error);
else
if (!strncmp(obj, "scene/", 6))
return cbox_execute_sub(&app.engine->scenes[0]->cmd_target, fb, cmd, pos, error);
else
if (!strncmp(obj, "engine/", 7))
return cbox_execute_sub(&app.engine->cmd_target, fb, cmd, pos, error);
else
if (!strncmp(obj, "rt/", 3))
return cbox_execute_sub(&app.rt->cmd_target, fb, cmd, pos, error);
else
if (!strncmp(obj, "io/", 3))
return cbox_execute_sub(&app.io.cmd_target, fb, cmd, pos, error);
else
if (!strncmp(obj, "song/", 5) && app.engine->master->song)
return cbox_execute_sub(&app.engine->master->song->cmd_target, fb, cmd, pos, error);
else
if (!strncmp(obj, "waves/", 6))
return cbox_execute_sub(&cbox_waves_cmd_target, fb, cmd, pos, error);
else
if (!strncmp(obj, "doc/", 4))
return cbox_execute_sub(cbox_document_get_cmd_target(app.document), fb, cmd, pos, error);
else
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Unknown combination of target path and argument: '%s', '%s'", cmd->command, cmd->arg_types);
return FALSE;
}
}
else
if (!strcmp(obj, "on_idle") && !strcmp(cmd->arg_types, ""))
{
return cbox_app_on_idle(fb, error);
}
else
if (!strcmp(obj, "send_event_to") && (!strcmp(cmd->arg_types, "siii") || !strcmp(cmd->arg_types, "sii") || !strcmp(cmd->arg_types, "si")))
{
const char *output = CBOX_ARG_S(cmd, 0);
struct cbox_midi_merger *merger = NULL;
if (!lookup_midi_merger(output, &merger, error))
return FALSE;
int mcmd = CBOX_ARG_I(cmd, 1);
int arg1 = 0, arg2 = 0;
if (cmd->arg_types[2] == 'i')
{
arg1 = CBOX_ARG_I(cmd, 2);
if (cmd->arg_types[3] == 'i')
arg2 = CBOX_ARG_I(cmd, 3);
}
struct cbox_midi_buffer buf;
cbox_midi_buffer_init(&buf);
cbox_midi_buffer_write_inline(&buf, 0, mcmd, arg1, arg2);
cbox_engine_send_events_to(app.engine, merger, &buf);
return TRUE;
}
else
if (!strcmp(obj, "send_sysex_to") && !strcmp(cmd->arg_types, "sb"))
{
const char *output = CBOX_ARG_S(cmd, 0);
struct cbox_midi_merger *merger = NULL;
if (!lookup_midi_merger(output, &merger, error))
return FALSE;
const struct cbox_blob *blob = CBOX_ARG_B(cmd, 1);
struct cbox_midi_buffer buf;
cbox_midi_buffer_init(&buf);
cbox_midi_buffer_write_event(&buf, 0, blob->data, blob->size);
cbox_engine_send_events_to(app.engine, merger, &buf);
return TRUE;
}
else
if (!strcmp(obj, "update_playback") && !strcmp(cmd->arg_types, ""))
{
cbox_engine_update_song_playback(app.engine);
return TRUE;
}
else
if (!strcmp(obj, "get_pattern") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
if (app.engine->master->song && app.engine->master->song->tracks)
{
struct cbox_track *track = app.engine->master->song->tracks->data;
if (track)
{
struct cbox_track_item *item = track->items->data;
struct cbox_midi_pattern *pattern = item->pattern;
int length = 0;
struct cbox_blob *blob = cbox_midi_pattern_to_blob(pattern, &length);
gboolean res = cbox_execute_on(fb, NULL, "/pattern", "bi", error, blob, length);
cbox_blob_destroy(blob);
if (!res)
return FALSE;
}
}
return TRUE;
}
else
if (!strcmp(obj, "new_meter") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
struct cbox_meter *meter = cbox_meter_new(app.document, app.rt->io_env.srate);
return cbox_execute_on(fb, NULL, "/uuid", "o", error, meter);
}
else
if (!strcmp(obj, "new_engine") && !strcmp(cmd->arg_types, "ii"))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
struct cbox_engine *e = cbox_engine_new(app.document, NULL);
e->io_env.srate = CBOX_ARG_I(cmd, 0);
e->io_env.buffer_size = CBOX_ARG_I(cmd, 1);
return e ? cbox_execute_on(fb, NULL, "/uuid", "o", error, e) : FALSE;
}
else
if (!strcmp(obj, "print_s") && !strcmp(cmd->arg_types, "s"))
{
g_message("Print: %s", CBOX_ARG_S(cmd, 0));
return TRUE;
}
else
if (!strcmp(obj, "print_i") && !strcmp(cmd->arg_types, "i"))
{
g_message("Print: %d", CBOX_ARG_I(cmd, 0));
return TRUE;
}
else
if (!strcmp(obj, "print_f") && !strcmp(cmd->arg_types, "f"))
{
g_message("Print: %f", CBOX_ARG_F(cmd, 0));
return TRUE;
}
else
if (!strcmp(obj, "print_b") && !strcmp(cmd->arg_types, "b"))
{
g_message("Print: %s", (char *)CBOX_ARG_B(cmd, 0)->data);
return TRUE;
}
else
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Unknown combination of target path and argument: '%s', '%s'", cmd->command, cmd->arg_types);
return FALSE;
}
}
struct config_foreach_data
{
const char *prefix;
const char *command;
struct cbox_command_target *fb;
GError **error;
gboolean success;
};
void api_config_cb(void *user_data, const char *key)
{
struct config_foreach_data *cfd = user_data;
if (!cfd->success)
return;
if (cfd->prefix && strncmp(cfd->prefix, key, strlen(cfd->prefix)))
return;
if (!cbox_execute_on(cfd->fb, NULL, cfd->command, "s", cfd->error, key))
{
cfd->success = FALSE;
return;
}
}
static gboolean config_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
if (!strcmp(cmd->command, "/sections") && (!strcmp(cmd->arg_types, "") || !strcmp(cmd->arg_types, "s")))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
struct config_foreach_data cfd = {cmd->arg_types[0] == 's' ? CBOX_ARG_S(cmd, 0) : NULL, "/section", fb, error, TRUE};
cbox_config_foreach_section(api_config_cb, &cfd);
return cfd.success;
}
else if (!strcmp(cmd->command, "/keys") && (!strcmp(cmd->arg_types, "s") || !strcmp(cmd->arg_types, "ss")))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
struct config_foreach_data cfd = {cmd->arg_types[1] == 's' ? CBOX_ARG_S(cmd, 1) : NULL, "/key", fb, error, TRUE};
cbox_config_foreach_key(api_config_cb, CBOX_ARG_S(cmd, 0), &cfd);
return cfd.success;
}
else if (!strcmp(cmd->command, "/get") && !strcmp(cmd->arg_types, "ss"))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
const char *value = cbox_config_get_string(CBOX_ARG_S(cmd, 0), CBOX_ARG_S(cmd, 1));
if (!value)
return TRUE;
return cbox_execute_on(fb, NULL, "/value", "s", error, value);
}
else if (!strcmp(cmd->command, "/set") && !strcmp(cmd->arg_types, "sss"))
{
cbox_config_set_string(CBOX_ARG_S(cmd, 0), CBOX_ARG_S(cmd, 1), CBOX_ARG_S(cmd, 2));
return TRUE;
}
else if (!strcmp(cmd->command, "/delete") && !strcmp(cmd->arg_types, "ss"))
{
cbox_config_remove_key(CBOX_ARG_S(cmd, 0), CBOX_ARG_S(cmd, 1));
return TRUE;
}
else if (!strcmp(cmd->command, "/delete_section") && !strcmp(cmd->arg_types, "s"))
{
cbox_config_remove_section(CBOX_ARG_S(cmd, 0));
return TRUE;
}
else if (!strcmp(cmd->command, "/save") && !strcmp(cmd->arg_types, ""))
{
return cbox_config_save(NULL, error);
}
else if (!strcmp(cmd->command, "/save") && !strcmp(cmd->arg_types, "s"))
{
return cbox_config_save(CBOX_ARG_S(cmd, 0), error);
}
else
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Unknown combination of target path and argument: '%s', '%s'", cmd->command, cmd->arg_types);
return FALSE;
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
gboolean cbox_app_on_idle(struct cbox_command_target *fb, GError **error)
{
if (app.rt->io)
{
GError *error2 = NULL;
if (cbox_io_get_disconnect_status(&app.io, &error2))
cbox_io_poll_ports(&app.io, fb);
else
{
if (error2)
g_error_free(error2);
int auto_reconnect = cbox_config_get_int("io", "auto_reconnect", 0);
if (auto_reconnect > 0)
{
sleep(auto_reconnect);
GError *error2 = NULL;
if (!cbox_io_cycle(&app.io, fb, &error2))
{
gboolean suppress = FALSE;
if (fb)
suppress = cbox_execute_on(fb, NULL, "/io/cycle_failed", "s", NULL, error2->message);
if (!suppress)
g_warning("Cannot cycle the I/O: %s", (error2 && error2->message) ? error2->message : "Unknown error");
g_error_free(error2);
}
else
{
if (fb)
cbox_execute_on(fb, NULL, "/io/cycled", "", NULL);
}
}
}
}
if (app.rt)
{
// Process results of asynchronous commands
cbox_rt_handle_cmd_queue(app.rt);
if (!cbox_midi_appsink_send_to(&app.engine->appsink, fb, error))
return FALSE;
}
return TRUE;
}
struct cbox_app app =
{
.rt = NULL,
.current_scene_name = NULL,
.cmd_target =
{
.process_cmd = app_process_cmd,
.user_data = &app
},
.config_cmd_target =
{
.process_cmd = config_process_cmd,
.user_data = &app
},
};

51
template/calfbox/app.h

@ -1,51 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_APP_H
#define CBOX_APP_H
#include "cmd.h"
#include "dom.h"
#include "io.h"
#include "rt.h"
#include <glib.h>
struct cbox_song;
struct cbox_tarpool;
struct cbox_app
{
struct cbox_io io;
struct cbox_document *document;
struct cbox_rt *rt;
struct cbox_engine *engine;
struct cbox_command_target cmd_target;
struct cbox_command_target config_cmd_target;
gchar *current_scene_name;
struct cbox_tarpool *tarpool;
};
struct cbox_menu;
extern struct cbox_app app;
struct cbox_menu *create_main_menu(void);
extern gboolean cbox_app_on_idle(struct cbox_command_target *fb, GError **error);
#endif

466
template/calfbox/appmenu.c

@ -1,466 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2013 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "app.h"
#include "blob.h"
#include "config-api.h"
#include "engine.h"
#include "instr.h"
#include "io.h"
#include "layer.h"
#include "menu.h"
#include "menuitem.h"
#include "meter.h"
#include "midi.h"
#include "module.h"
#include "scene.h"
#include "seq.h"
#include "song.h"
#include "track.h"
#include "ui.h"
#include "wavebank.h"
#if USE_NCURSES
#include <assert.h>
#include <glib.h>
#include <glob.h>
#include <getopt.h>
#include <math.h>
#include <ncurses.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
int cmd_quit(struct cbox_menu_item_command *item, void *context)
{
return 1;
}
static void set_current_scene_name(gchar *name)
{
if (app.current_scene_name)
g_free(app.current_scene_name);
app.current_scene_name = name;
}
int cmd_load_scene(struct cbox_menu_item_command *item, void *context)
{
GError *error = NULL;
struct cbox_scene *scene = app.engine->scenes[0];
cbox_scene_clear(scene);
if (!cbox_scene_load(scene, item->item.item_context, &error))
cbox_print_error(error);
set_current_scene_name(g_strdup_printf("scene:%s", (const char *)item->item.item_context));
return 0;
}
int cmd_load_instrument(struct cbox_menu_item_command *item, void *context)
{
GError *error = NULL;
struct cbox_scene *scene = app.engine->scenes[0];
cbox_scene_clear(scene);
struct cbox_layer *layer = cbox_layer_new_with_instrument(scene, (char *)item->item.item_context, &error);
if (layer)
{
if (!cbox_scene_add_layer(scene, layer, &error))
cbox_print_error(error);
set_current_scene_name(g_strdup_printf("instrument:%s", (const char *)item->item.item_context));
}
else
{
cbox_print_error(error);
}
return 0;
}
int cmd_load_layer(struct cbox_menu_item_command *item, void *context)
{
GError *error = NULL;
struct cbox_scene *scene = app.engine->scenes[0];
cbox_scene_clear(scene);
struct cbox_layer *layer = cbox_layer_new_from_config(scene, (char *)item->item.item_context, &error);
if (layer)
{
if (!cbox_scene_add_layer(scene, layer, &error))
cbox_print_error(error);
set_current_scene_name(g_strdup_printf("layer:%s", (const char *)item->item.item_context));
}
else
{
cbox_print_error(error);
CBOX_DELETE(scene);
}
return 0;
}
gchar *scene_format_value(const struct cbox_menu_item_static *item, void *context)
{
if (app.current_scene_name)
return g_strdup(app.current_scene_name);
else
return g_strdup("- No scene -");
}
gchar *transport_format_value(const struct cbox_menu_item_static *item, void *context)
{
// XXXKF
// struct cbox_bbt bbt;
// cbox_master_to_bbt(app.engine->master, &bbt);
if (app.engine->master->spb == NULL)
return g_strdup("N/A");
if (!strcmp((const char *)item->item.item_context, "pos"))
return g_strdup_printf("%d", (int)app.engine->master->spb->song_pos_samples);
else
return g_strdup_printf("%d", (int)app.engine->master->spb->song_pos_ppqn);
}
struct cbox_config_section_cb_data
{
struct cbox_menu *menu;
cbox_menu_item_execute_func func;
const char *prefix;
};
static void config_key_process(void *user_data, const char *key)
{
struct cbox_config_section_cb_data *data = user_data;
if (!strncmp(key, data->prefix, strlen(data->prefix)))
{
char *title = cbox_config_get_string(key, "title");
if (title)
cbox_menu_add_item(data->menu, cbox_menu_item_new_command(title, data->func, strdup(key + strlen(data->prefix)), mif_dup_label | mif_free_context));
else
cbox_menu_add_item(data->menu, cbox_menu_item_new_command(key, data->func, strdup(key + strlen(data->prefix)), mif_dup_label | mif_free_context));
}
}
struct cbox_menu *create_scene_menu(struct cbox_menu_item_menu *item, void *menu_context)
{
struct cbox_menu *scene_menu = cbox_menu_new();
struct cbox_config_section_cb_data cb = { .menu = scene_menu };
cbox_menu_add_item(scene_menu, cbox_menu_item_new_static("Scenes", NULL, NULL, 0));
cb.prefix = "scene:";
cb.func = cmd_load_scene;
cbox_config_foreach_section(config_key_process, &cb);
cbox_menu_add_item(scene_menu, cbox_menu_item_new_static("Layers", NULL, NULL, 0));
cb.prefix = "layer:";
cb.func = cmd_load_layer;
cbox_config_foreach_section(config_key_process, &cb);
cbox_menu_add_item(scene_menu, cbox_menu_item_new_static("Instruments", NULL, NULL, 0));
cb.prefix = "instrument:";
cb.func = cmd_load_instrument;
cbox_config_foreach_section(config_key_process, &cb);
cbox_menu_add_item(scene_menu, cbox_menu_item_new_ok());
return scene_menu;
}
///////////////////////////////////////////////////////////////////////////////
static struct cbox_command_target *find_module_target(const struct cbox_menu_item_command *item)
{
struct cbox_instrument *instr = item->item.item_context;
return &instr->module->cmd_target;
}
int cmd_stream_rewind(struct cbox_menu_item_command *item, void *context)
{
GError *error = NULL;
struct cbox_command_target *target = find_module_target(item);
if (target)
cbox_execute_on(target, NULL, "/seek", "i", &error, 0);
cbox_print_error_if(error);
return 0;
}
int cmd_stream_play(struct cbox_menu_item_command *item, void *context)
{
GError *error = NULL;
struct cbox_command_target *target = find_module_target(item);
if (target)
cbox_execute_on(target, NULL, "/play", "", &error);
cbox_print_error_if(error);
return 0;
}
int cmd_stream_stop(struct cbox_menu_item_command *item, void *context)
{
GError *error = NULL;
struct cbox_command_target *target = find_module_target(item);
if (target)
cbox_execute_on(target, NULL, "/stop", "", &error);
cbox_print_error_if(error);
return 0;
}
int cmd_stream_unload(struct cbox_menu_item_command *item, void *context)
{
GError *error = NULL;
struct cbox_command_target *target = find_module_target(item);
if (target)
cbox_execute_on(target, NULL, "/unload", "", &error);
cbox_print_error_if(error);
return 0;
}
struct stream_response_data
{
gchar *filename;
uint32_t pos, length, sample_rate, channels;
};
gboolean result_parser_status(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
struct stream_response_data *res = ct->user_data;
if (!strcmp(cmd->command, "/filename"))
res->filename = g_strdup(cmd->arg_values[0]);
if (!strcmp(cmd->command, "/pos"))
res->pos = *((uint32_t **)cmd->arg_values)[0];
if (!strcmp(cmd->command, "/length"))
res->length = *((uint32_t **)cmd->arg_values)[0];
if (!strcmp(cmd->command, "/sample_rate"))
res->sample_rate = *((uint32_t **)cmd->arg_values)[0];
if (!strcmp(cmd->command, "/channels"))
res->channels = *((uint32_t **)cmd->arg_values)[0];
//cbox_osc_command_dump(cmd);
return TRUE;
}
char *cmd_stream_status(const struct cbox_menu_item_static *item, void *context)
{
struct stream_response_data data = { NULL, 0, 0, 0, 0 };
struct cbox_command_target response = { &data, result_parser_status };
GError *error = NULL;
struct cbox_command_target *target = find_module_target((struct cbox_menu_item_command *)item);
if (target)
cbox_execute_on(target, &response, "/status", "", &error);
cbox_print_error_if(error);
gchar *res = NULL;
if (data.filename && data.length && data.sample_rate)
{
double duration = data.length * 1.0 / data.sample_rate;
res = g_strdup_printf("%s (%um%0.2fs, %uch, %uHz) (%0.2f%%)", data.filename, (unsigned)floor(duration / 60), duration - 60 * floor(duration / 60), (unsigned)data.channels, (unsigned)data.sample_rate, data.pos * 100.0 / data.length);
}
else
res = g_strdup("-");
g_free(data.filename);
return res;
}
struct load_waveform_context
{
struct cbox_menu_item_context header;
struct cbox_instrument *instrument;
char *filename;
};
static void destroy_load_waveform_context(void *p)
{
struct load_waveform_context *context = p;
g_free(context->filename);
free(context);
}
int cmd_stream_load(struct cbox_menu_item_command *item, void *context)
{
struct load_waveform_context *ctx = item->item.item_context;
GError *error = NULL;
struct cbox_command_target *target = &ctx->instrument->module->cmd_target;
if (target)
cbox_execute_on(target, NULL, "/load", "si", &error, ctx->filename, 0);
cbox_print_error_if(error);
return 0;
}
struct cbox_menu *create_streamplay_menu(struct cbox_menu_item_menu *item, void *menu_context)
{
struct cbox_menu *menu = cbox_menu_new();
struct cbox_instrument *instr = item->item.item_context;
assert(instr);
cbox_menu_add_item(menu, cbox_menu_item_new_static("Current stream", NULL, NULL, 0));
cbox_menu_add_item(menu, cbox_menu_item_new_static("File", cmd_stream_status, instr, 0));
cbox_menu_add_item(menu, cbox_menu_item_new_static("Module commands", NULL, NULL, 0));
cbox_menu_add_item(menu, cbox_menu_item_new_command("Play stream", cmd_stream_play, instr, 0));
cbox_menu_add_item(menu, cbox_menu_item_new_command("Stop stream", cmd_stream_stop, instr, 0));
cbox_menu_add_item(menu, cbox_menu_item_new_command("Rewind stream", cmd_stream_rewind, instr, 0));
cbox_menu_add_item(menu, cbox_menu_item_new_command("Unload stream", cmd_stream_unload, instr, 0));
cbox_menu_add_item(menu, cbox_menu_item_new_static("Files available", NULL, NULL, 0));
glob_t g;
gboolean found = (glob("*.wav", GLOB_TILDE_CHECK, NULL, &g) == 0);
found = glob("*.ogg", GLOB_TILDE_CHECK | (found ? GLOB_APPEND : 0), NULL, &g) || found;
if (found)
{
for (size_t i = 0; i < g.gl_pathc; i++)
{
struct load_waveform_context *context = calloc(1, sizeof(struct load_waveform_context));
context->header.destroy_func = destroy_load_waveform_context;
context->instrument = instr;
context->filename = g_strdup(g.gl_pathv[i]);
cbox_menu_add_item(menu, cbox_menu_item_new_command(g_strdup_printf("Load: %s", g.gl_pathv[i]), cmd_stream_load, context, mif_free_label | mif_context_is_struct));
}
}
globfree(&g);
cbox_menu_add_item(menu, cbox_menu_item_new_ok());
return menu;
}
///////////////////////////////////////////////////////////////////////////////
struct cbox_menu *create_module_menu(struct cbox_menu_item_menu *item, void *menu_context)
{
struct cbox_menu *menu = cbox_menu_new();
cbox_menu_add_item(menu, cbox_menu_item_new_static("Scene instruments", NULL, NULL, 0));
struct cbox_scene *scene = app.engine->scenes[0];
for (uint32_t i = 0; i < scene->instrument_count; ++i)
{
struct cbox_instrument *instr = scene->instruments[i];
create_menu_func menufunc = NULL;
if (!strcmp(instr->module->engine_name, "stream_player"))
menufunc = create_streamplay_menu;
if (menufunc)
cbox_menu_add_item(menu, cbox_menu_item_new_dynamic_menu(g_strdup_printf("%s (%s)", instr->module->instance_name, instr->module->engine_name), menufunc, instr, mif_free_label));
else
cbox_menu_add_item(menu, cbox_menu_item_new_static(g_strdup_printf("%s (%s)", instr->module->instance_name, instr->module->engine_name), NULL, NULL, mif_free_label));
}
cbox_menu_add_item(menu, cbox_menu_item_new_ok());
return menu;
}
///////////////////////////////////////////////////////////////////////////////
static void restart_song()
{
cbox_master_stop(app.engine->master);
cbox_master_seek_ppqn(app.engine->master, 0);
cbox_master_play(app.engine->master);
}
int cmd_pattern_none(struct cbox_menu_item_command *item, void *context)
{
cbox_song_clear(app.engine->master->song);
cbox_engine_update_song_playback(app.engine);
return 0;
}
int cmd_pattern_simple(struct cbox_menu_item_command *item, void *context)
{
cbox_song_use_looped_pattern(app.engine->master->song, cbox_midi_pattern_new_metronome(app.engine->master->song, 1, app.engine->master->ppqn_factor));
restart_song();
return 0;
}
int cmd_pattern_normal(struct cbox_menu_item_command *item, void *context)
{
cbox_song_use_looped_pattern(app.engine->master->song, cbox_midi_pattern_new_metronome(app.engine->master->song, app.engine->master->timesig_num, app.engine->master->ppqn_factor));
restart_song();
return 0;
}
int cmd_load_drumpattern(struct cbox_menu_item_command *item, void *context)
{
cbox_song_use_looped_pattern(app.engine->master->song, cbox_midi_pattern_load(app.engine->master->song, item->item.item_context, 1, app.engine->master->ppqn_factor));
restart_song();
return 0;
}
int cmd_load_drumtrack(struct cbox_menu_item_command *item, void *context)
{
cbox_song_use_looped_pattern(app.engine->master->song, cbox_midi_pattern_load_track(app.engine->master->song, item->item.item_context, 1, app.engine->master->ppqn_factor));
restart_song();
return 0;
}
int cmd_load_pattern(struct cbox_menu_item_command *item, void *context)
{
cbox_song_use_looped_pattern(app.engine->master->song, cbox_midi_pattern_load(app.engine->master->song, item->item.item_context, 0, app.engine->master->ppqn_factor));
restart_song();
return 0;
}
int cmd_load_track(struct cbox_menu_item_command *item, void *context)
{
cbox_song_use_looped_pattern(app.engine->master->song, cbox_midi_pattern_load_track(app.engine->master->song, item->item.item_context, 0, app.engine->master->ppqn_factor));
restart_song();
return 0;
}
struct cbox_menu *create_pattern_menu(struct cbox_menu_item_menu *item, void *menu_context)
{
struct cbox_menu *menu = cbox_menu_new();
struct cbox_config_section_cb_data cb = { .menu = menu };
cbox_menu_add_item(menu, cbox_menu_item_new_static("Pattern commands", NULL, NULL, 0));
cbox_menu_add_item(menu, cbox_menu_item_new_command("No pattern", cmd_pattern_none, NULL, 0));
cbox_menu_add_item(menu, cbox_menu_item_new_command("Simple metronome", cmd_pattern_simple, NULL, 0));
cbox_menu_add_item(menu, cbox_menu_item_new_command("Normal metronome", cmd_pattern_normal, NULL, 0));
cbox_menu_add_item(menu, cbox_menu_item_new_static("Drum tracks", NULL, NULL, 0));
cb.prefix = "drumtrack:";
cb.func = cmd_load_drumtrack;
cbox_config_foreach_section(config_key_process, &cb);
cbox_menu_add_item(menu, cbox_menu_item_new_static("Melodic tracks", NULL, NULL, 0));
cb.prefix = "track:";
cb.func = cmd_load_track;
cbox_config_foreach_section(config_key_process, &cb);
cbox_menu_add_item(menu, cbox_menu_item_new_static("Drum patterns", NULL, NULL, 0));
cb.prefix = "drumpattern:";
cb.func = cmd_load_drumpattern;
cbox_config_foreach_section(config_key_process, &cb);
cbox_menu_add_item(menu, cbox_menu_item_new_static("Melodic patterns", NULL, NULL, 0));
cb.prefix = "pattern:";
cb.func = cmd_load_pattern;
cbox_config_foreach_section(config_key_process, &cb);
cbox_menu_add_item(menu, cbox_menu_item_new_ok());
return menu;
}
struct cbox_menu *create_main_menu()
{
struct cbox_menu *main_menu = cbox_menu_new();
cbox_menu_add_item(main_menu, cbox_menu_item_new_static("Current scene:", scene_format_value, NULL, 0));
cbox_menu_add_item(main_menu, cbox_menu_item_new_dynamic_menu("Set scene", create_scene_menu, NULL, 0));
cbox_menu_add_item(main_menu, cbox_menu_item_new_dynamic_menu("Module control", create_module_menu, NULL, 0));
cbox_menu_add_item(main_menu, cbox_menu_item_new_dynamic_menu("Pattern control", create_pattern_menu, NULL, 0));
cbox_menu_add_item(main_menu, cbox_menu_item_new_static("Variables", NULL, NULL, 0));
// cbox_menu_add_item(main_menu, cbox_menu_item_new_int("foo:", &var1, 0, 127, NULL));
// cbox_menu_add_item(main_menu, "bar:", menu_item_value_double, &mx_double_var2, &var2);
//cbox_menu_add_item(main_menu, cbox_menu_item_new_static("pos:", transport_format_value, "pos", 0));
//cbox_menu_add_item(main_menu, cbox_menu_item_new_static("bbt:", transport_format_value, "bbt", 0));
cbox_menu_add_item(main_menu, cbox_menu_item_new_static("Commands", NULL, NULL, 0));
cbox_menu_add_item(main_menu, cbox_menu_item_new_command("Quit", cmd_quit, NULL, 0));
return main_menu;
}
#endif

6
template/calfbox/autogen.sh

@ -1,6 +0,0 @@
aclocal --force || exit 1
libtoolize --force --automake --copy || exit 1
autoheader --force || exit 1
autoconf --force || exit 1
automake --add-missing --copy || exit 1

102
template/calfbox/auxbus.c

@ -1,102 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "auxbus.h"
#include "scene.h"
#include <assert.h>
#include <glib.h>
extern gboolean cbox_scene_insert_aux_bus(struct cbox_scene *scene, struct cbox_aux_bus *aux_bus);
extern void cbox_scene_remove_aux_bus(struct cbox_scene *scene, struct cbox_aux_bus *bus);
CBOX_CLASS_DEFINITION_ROOT(cbox_aux_bus)
static gboolean cbox_aux_bus_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
struct cbox_aux_bus *aux_bus = ct->user_data;
struct cbox_rt *rt = (struct cbox_rt *)cbox_document_get_service(CBOX_GET_DOCUMENT(aux_bus), "rt");
if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
return cbox_execute_on(fb, NULL, "/name", "s", error, aux_bus->name) &&
CBOX_OBJECT_DEFAULT_STATUS(aux_bus, fb, error);
}
else
if (!strncmp(cmd->command, "/slot/", 6))
{
return cbox_module_slot_process_cmd(&aux_bus->module, fb, cmd, cmd->command + 5, CBOX_GET_DOCUMENT(aux_bus), rt, aux_bus->owner->engine, error);
}
else
return cbox_object_default_process_cmd(ct, fb, cmd, error);
}
struct cbox_aux_bus *cbox_aux_bus_load(struct cbox_scene *scene, const char *name, struct cbox_rt *rt, GError **error)
{
struct cbox_module *module = cbox_module_new_from_fx_preset(name, CBOX_GET_DOCUMENT(scene), rt, scene->engine, error);
if (!module)
return NULL;
struct cbox_aux_bus *p = malloc(sizeof(struct cbox_aux_bus));
CBOX_OBJECT_HEADER_INIT(p, cbox_aux_bus, CBOX_GET_DOCUMENT(scene));
cbox_command_target_init(&p->cmd_target, cbox_aux_bus_process_cmd, p);
p->name = g_strdup(name);
p->owner = scene;
p->module = module;
p->refcount = 0;
// XXXKF this work up to buffer size of 8192 floats, this should be determined from JACK settings and updated when
// JACK buffer size changes
p->input_bufs[0] = malloc(8192 * sizeof(float));
p->input_bufs[1] = malloc(8192 * sizeof(float));
p->output_bufs[0] = malloc(8192 * sizeof(float));
p->output_bufs[1] = malloc(8192 * sizeof(float));
CBOX_OBJECT_REGISTER(p);
cbox_scene_insert_aux_bus(scene, p);
return p;
}
void cbox_aux_bus_ref(struct cbox_aux_bus *bus)
{
++bus->refcount;
}
void cbox_aux_bus_unref(struct cbox_aux_bus *bus)
{
assert(bus->refcount > 0);
--bus->refcount;
}
void cbox_aux_bus_destroyfunc(struct cbox_objhdr *objhdr)
{
struct cbox_aux_bus *bus = CBOX_H2O(objhdr);
if (bus->owner)
{
cbox_scene_remove_aux_bus(bus->owner, bus);
bus->owner = NULL;
}
CBOX_DELETE(bus->module);
bus->module = NULL;
assert(!bus->refcount);
g_free(bus->name);
free(bus->input_bufs[0]);
free(bus->input_bufs[1]);
free(bus);
}

47
template/calfbox/auxbus.h

@ -1,47 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_AUXBUS_H
#define CBOX_AUXBUS_H
#include "dom.h"
#include "module.h"
struct cbox_scene;
CBOX_EXTERN_CLASS(cbox_aux_bus)
struct cbox_aux_bus
{
CBOX_OBJECT_HEADER()
struct cbox_command_target cmd_target;
struct cbox_scene *owner;
gchar *name;
struct cbox_module *module;
int refcount;
float *input_bufs[2];
float *output_bufs[2];
};
extern struct cbox_aux_bus *cbox_aux_bus_load(struct cbox_scene *scene, const char *name, struct cbox_rt *rt, GError **error);
extern void cbox_aux_bus_ref(struct cbox_aux_bus *bus);
extern void cbox_aux_bus_unref(struct cbox_aux_bus *bus);
#endif

6
template/calfbox/background_example.py

@ -1,6 +0,0 @@
import _cbox
import time
while True:
_cbox.do_cmd("/on_idle", None, [])
time.sleep(0.1)

398
template/calfbox/biquad-float.h

@ -1,398 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_BIQUAD_FLOAT_H
#define CBOX_BIQUAD_FLOAT_H
#include "config.h"
#include "dspmath.h"
struct cbox_biquadf_state
{
float x1;
float y1;
float x2;
float y2;
};
struct cbox_biquadf_coeffs
{
float a0;
float a1;
float a2;
float b1;
float b2;
};
static inline void cbox_biquadf_reset(struct cbox_biquadf_state *state)
{
state->x1 = state->y1 = state->x2 = state->y2 = 0.f;
}
static inline float cbox_biquadf_is_audible(struct cbox_biquadf_state *state, float level)
{
return fabs(state->x1) + fabs(state->x2) + fabs(state->y1) + fabs(state->y2) >= level;
}
// Based on filter coefficient equations by Robert Bristow-Johnson
static inline void cbox_biquadf_set_lp_rbj(struct cbox_biquadf_coeffs *coeffs, float fc, float q, float sr)
{
float omega=(float)(2*M_PI*fc/sr);
float sn=sin(omega);
float cs=cos(omega);
float alpha=(float)(sn/(2*q));
float inv=(float)(1.0/(1.0+alpha));
coeffs->a2 = coeffs->a0 = (float)(inv*(1 - cs)*0.5f);
coeffs->a1 = coeffs->a0 + coeffs->a0;
coeffs->b1 = (float)(-2*cs*inv);
coeffs->b2 = (float)((1 - alpha)*inv);
}
static inline void cbox_biquadf_set_lp_rbj_lookup(struct cbox_biquadf_coeffs *coeffs, const struct cbox_sincos *sincos, float q)
{
float sn=sincos->sine;
float cs=sincos->cosine;
float alpha=(float)(sn/(2*q));
float inv=(float)(1.0/(1.0+alpha));
coeffs->a2 = coeffs->a0 = (float)(inv*(1 - cs)*0.5f);
coeffs->a1 = coeffs->a0 + coeffs->a0;
coeffs->b1 = (float)(-2*cs*inv);
coeffs->b2 = (float)((1 - alpha)*inv);
}
// Based on filter coefficient equations by Robert Bristow-Johnson
static inline void cbox_biquadf_set_hp_rbj(struct cbox_biquadf_coeffs *coeffs, float fc, float q, float sr)
{
float omega=(float)(2*M_PI*fc/sr);
float sn=sin(omega);
float cs=cos(omega);
float alpha=(float)(sn/(2*q));
float inv=(float)(1.0/(1.0+alpha));
coeffs->a2 = coeffs->a0 = (float)(inv*(1 + cs)*0.5f);
coeffs->a1 = -2 * coeffs->a0;
coeffs->b1 = (float)(-2*cs*inv);
coeffs->b2 = (float)((1 - alpha)*inv);
}
static inline void cbox_biquadf_set_hp_rbj_lookup(struct cbox_biquadf_coeffs *coeffs, const struct cbox_sincos *sincos, float q)
{
float sn=sincos->sine;
float cs=sincos->cosine;
float alpha=(float)(sn/(2*q));
float inv=(float)(1.0/(1.0+alpha));
coeffs->a2 = coeffs->a0 = (float)(inv*(1 + cs)*0.5f);
coeffs->a1 = -2 * coeffs->a0;
coeffs->b1 = (float)(-2*cs*inv);
coeffs->b2 = (float)((1 - alpha)*inv);
}
// Based on filter coefficient equations by Robert Bristow-Johnson
static inline void cbox_biquadf_set_bp_rbj(struct cbox_biquadf_coeffs *coeffs, float fc, float q, float sr)
{
float omega=(float)(2*M_PI*fc/sr);
float sn=sin(omega);
float cs=cos(omega);
float alpha=(float)(sn/(2*q));
float inv=(float)(1.0/(1.0+alpha));
coeffs->a0 = (float)(inv*alpha);
coeffs->a1 = 0.f;
coeffs->a2 = -coeffs->a0;
coeffs->b1 = (float)(-2*cs*inv);
coeffs->b2 = (float)((1 - alpha)*inv);
}
static inline void cbox_biquadf_set_bp_rbj_lookup(struct cbox_biquadf_coeffs *coeffs, const struct cbox_sincos *sincos, float q)
{
float sn=sincos->sine;
float cs=sincos->cosine;
float alpha=(float)(sn/(2*q));
float inv=(float)(1.0/(1.0+alpha));
coeffs->a0 = (float)(inv*alpha);
coeffs->a1 = 0.f;
coeffs->a2 = -coeffs->a0;
coeffs->b1 = (float)(-2*cs*inv);
coeffs->b2 = (float)((1 - alpha)*inv);
}
// Based on filter coefficient equations by Robert Bristow-Johnson
static inline void cbox_biquadf_set_peakeq_rbj(struct cbox_biquadf_coeffs *coeffs, float freq, float q, float peak, float sr)
{
float A = sqrt(peak);
float w0 = freq * 2 * M_PI * (1.0 / sr);
float alpha = sin(w0) / (2 * q);
float ib0 = 1.0 / (1 + alpha/A);
coeffs->a1 = coeffs->b1 = -2*cos(w0) * ib0;
coeffs->a0 = ib0 * (1 + alpha*A);
coeffs->a2 = ib0 * (1 - alpha*A);
coeffs->b2 = ib0 * (1 - alpha/A);
}
static inline void cbox_biquadf_set_peakeq_rbj_scaled(struct cbox_biquadf_coeffs *coeffs, float freq, float q, float A, float sr)
{
float w0 = freq * 2 * M_PI * (1.0 / sr);
float alpha = sin(w0) / (2 * q);
float ib0 = 1.0 / (1 + alpha/A);
coeffs->a1 = coeffs->b1 = -2*cos(w0) * ib0;
coeffs->a0 = ib0 * (1 + alpha*A);
coeffs->a2 = ib0 * (1 - alpha*A);
coeffs->b2 = ib0 * (1 - alpha/A);
}
// This is my math, and it's rather suspect
static inline void cbox_biquadf_set_1plp(struct cbox_biquadf_coeffs *coeffs, float freq, float sr)
{
float w = hz2w(freq, sr);
float x = tan (w * 0.5f);
float q = 1 / (1 + x);
float a01 = x*q;
float b1 = a01 - q;
coeffs->a0 = a01;
coeffs->a1 = a01;
coeffs->b1 = b1;
coeffs->a2 = 0;
coeffs->b2 = 0;
}
static inline void cbox_biquadf_set_1php(struct cbox_biquadf_coeffs *coeffs, float freq, float sr)
{
float w = hz2w(freq, sr);
float x = tan (w * 0.5f);
float q = 1 / (1 + x);
float a01 = x*q;
float b1 = a01 - q;
coeffs->a0 = q;
coeffs->a1 = -q;
coeffs->b1 = b1;
coeffs->a2 = 0;
coeffs->b2 = 0;
}
static inline void cbox_biquadf_set_1p(struct cbox_biquadf_coeffs *coeffs, float a0, float a1, float b1, int two_copies)
{
if (two_copies)
{
// (a0 + a1z) * (a0 + a1z) = a0^2 + 2*a0*a1*z + a1^2*z^2
// (1 - b1z) * (1 - b1z) = 1 - 2b1*z + b1^2*z^2
coeffs->a0 = a0*a0;
coeffs->a1 = 2*a0*a1;
coeffs->b1 = 2 * b1;
coeffs->a2 = a1*a1;
coeffs->b2 = b1*b1;
}
else
{
coeffs->a0 = a0;
coeffs->a1 = a1;
coeffs->b1 = b1;
coeffs->a2 = 0;
coeffs->b2 = 0;
}
}
static inline void cbox_biquadf_set_1plp_lookup(struct cbox_biquadf_coeffs *coeffs, const struct cbox_sincos *sincos, int two_copies)
{
float x = sincos->prewarp;
float q = sincos->prewarp2;
float a01 = x*q;
float b1 = a01 - q;
cbox_biquadf_set_1p(coeffs, a01, a01, b1, two_copies);
}
static inline void cbox_biquadf_set_1php_lookup(struct cbox_biquadf_coeffs *coeffs, const struct cbox_sincos *sincos, int two_copies)
{
float x = sincos->prewarp;
float q = sincos->prewarp2;
float a01 = x*q;
float b1 = a01 - q;
cbox_biquadf_set_1p(coeffs, q, -q, b1, two_copies);
}
#if USE_NEON
#include <arm_neon.h>
static inline void cbox_biquadf_process(struct cbox_biquadf_state *state, struct cbox_biquadf_coeffs *coeffs, float *buffer)
{
int i;
float32x2_t c0 = {coeffs->a0, 0};
float32x2_t c1 = {coeffs->a1, -coeffs->b1};
float32x2_t c2 = {coeffs->a2, -coeffs->b2};
float32x2_t s1 = {state->x1, state->y1};
float32x2_t s2 = {state->x2, state->y2};
for (i = 0; i < CBOX_BLOCK_SIZE; i ++)
{
float32x2_t in12 = {buffer[i], 0.f};
float32x2_t out12 = vmla_f32(vmla_f32(vmul_f32(c1, s1), c2, s2), in12, c0); // [a1 * x1 + a2 * x2 + a0 * in, -b1 * y1 - b2 * y2 + 0]
float32x2x2_t trn = vtrn_f32(out12, in12); // [[a1 * x1 + a2 * x2 + a0 * in, in12], [-b1 * y1 - b2 * y2, 0]]
float32x2_t out120 = vadd_f32(trn.val[0], trn.val[1]);
s2 = s1;
s1 = vrev64_f32(out120);
buffer[i] = out120[0];
}
state->x1 = s1[0];
state->y1 = s1[1];
state->x2 = s2[0];
state->y2 = s2[1];
}
#else
static inline void cbox_biquadf_process(struct cbox_biquadf_state *state, struct cbox_biquadf_coeffs *coeffs, float *buffer)
{
int i;
float a0 = coeffs->a0;
float a1 = coeffs->a1;
float a2 = coeffs->a2;
float b1 = coeffs->b1;
float b2 = coeffs->b2;
double y1 = state->y1;
double y2 = state->y2;
for (i = 0; i < CBOX_BLOCK_SIZE; i++)
{
float in = buffer[i];
double out = a0 * in + a1 * state->x1 + a2 * state->x2 - b1 * y1 - b2 * y2;
buffer[i] = out;
state->x2 = state->x1;
state->x1 = in;
y2 = y1;
y1 = out;
}
state->y2 = sanef(y2);
state->y1 = sanef(y1);
}
#endif
static inline void cbox_biquadf_process_stereo(struct cbox_biquadf_state *lstate, struct cbox_biquadf_state *rstate, struct cbox_biquadf_coeffs *coeffs, float *buffer)
{
int i;
float a0 = coeffs->a0;
float a1 = coeffs->a1;
float a2 = coeffs->a2;
float b1 = coeffs->b1;
float b2 = coeffs->b2;
double ly1 = lstate->y1;
double ly2 = lstate->y2;
double ry1 = rstate->y1;
double ry2 = rstate->y2;
for (i = 0; i < 2 * CBOX_BLOCK_SIZE; i += 2)
{
float inl = buffer[i], inr = buffer[i + 1];
float outl = a0 * inl + a1 * lstate->x1 + a2 * lstate->x2 - b1 * ly1 - b2 * ly2;
float outr = a0 * inr + a1 * rstate->x1 + a2 * rstate->x2 - b1 * ry1 - b2 * ry2;
lstate->x2 = lstate->x1;
lstate->x1 = inl;
ly2 = ly1;
ly1 = outl;
buffer[i] = outl;
rstate->x2 = rstate->x1;
rstate->x1 = inr;
ry2 = ry1;
ry1 = outr;
buffer[i + 1] = outr;
}
lstate->y2 = sanef(ly2);
lstate->y1 = sanef(ly1);
rstate->y2 = sanef(ry2);
rstate->y1 = sanef(ry1);
}
static inline double cbox_biquadf_process_sample(struct cbox_biquadf_state *state, struct cbox_biquadf_coeffs *coeffs, double in)
{
double out = sanef(coeffs->a0 * sanef(in) + coeffs->a1 * state->x1 + coeffs->a2 * state->x2 - coeffs->b1 * state->y1 - coeffs->b2 * state->y2);
state->x2 = state->x1;
state->x1 = in;
state->y2 = state->y1;
state->y1 = out;
return out;
}
static inline void cbox_biquadf_process_to(struct cbox_biquadf_state *state, struct cbox_biquadf_coeffs *coeffs, float *buffer_in, float *buffer_out)
{
int i;
float a0 = coeffs->a0;
float a1 = coeffs->a1;
float a2 = coeffs->a2;
float b1 = coeffs->b1;
float b2 = coeffs->b2;
double y1 = state->y1;
double y2 = state->y2;
for (i = 0; i < CBOX_BLOCK_SIZE; i++)
{
float in = buffer_in[i];
double out = a0 * in + a1 * state->x1 + a2 * state->x2 - b1 * y1 - b2 * y2;
buffer_out[i] = out;
state->x2 = state->x1;
state->x1 = in;
y2 = y1;
y1 = out;
}
state->y2 = sanef(y2);
state->y1 = sanef(y1);
}
static inline void cbox_biquadf_process_adding(struct cbox_biquadf_state *state, struct cbox_biquadf_coeffs *coeffs, float *buffer_in, float *buffer_out)
{
int i;
float a0 = coeffs->a0;
float a1 = coeffs->a1;
float a2 = coeffs->a2;
float b1 = coeffs->b1;
float b2 = coeffs->b2;
double y1 = state->y1;
double y2 = state->y2;
for (i = 0; i < CBOX_BLOCK_SIZE; i++)
{
float in = buffer_in[i];
double out = a0 * in + a1 * state->x1 + a2 * state->x2 - b1 * y1 - b2 * y2;
buffer_out[i] += out;
state->x2 = state->x1;
state->x1 = in;
y2 = y1;
y1 = out;
}
state->y2 = sanef(y2);
state->y1 = sanef(y1);
}
#endif

130
template/calfbox/blob.c

@ -1,130 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "blob.h"
#include "tarfile.h"
#include <errno.h>
#include <fcntl.h>
#include <glib.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct cbox_blob *cbox_blob_new(size_t size)
{
struct cbox_blob *p = malloc(sizeof(struct cbox_blob));
if (!p)
return NULL;
p->data = size ? malloc(size) : NULL;
p->size = size;
return p;
}
struct cbox_blob *cbox_blob_new_copy_data(const void *data, size_t size)
{
struct cbox_blob *p = cbox_blob_new(size);
if (!p)
return NULL;
memcpy(p, data, size);
return p;
}
struct cbox_blob *cbox_blob_new_acquire_data(void *data, size_t size)
{
struct cbox_blob *p = malloc(sizeof(struct cbox_blob));
if (!p)
return NULL;
p->data = data;
p->size = size;
return p;
}
static struct cbox_blob *read_from_fd(const char *context_name, const char *pathname, int fd, size_t size, GError **error)
{
struct cbox_blob *blob = cbox_blob_new(size + 1);
if (!blob)
{
g_set_error(error, G_FILE_ERROR, g_file_error_from_errno (errno), "%s: cannot allocate memory for file '%s'", context_name, pathname);
return NULL;
}
uint8_t *data = blob->data;
size_t nread = 0;
do {
size_t chunk = size - nread;
if (chunk > 131072)
chunk = 131072;
size_t nv = read(fd, data + nread, chunk);
if (nv == (size_t)-1)
{
if (errno == EINTR)
continue;
g_set_error(error, G_FILE_ERROR, g_file_error_from_errno (errno), "%s: cannot read '%s': %s", context_name, pathname, strerror(errno));
cbox_blob_destroy(blob);
return NULL;
}
nread += nv;
} while(nread < size);
// Make sure that the content is 0-padded but still has the original size
// (without extra zero byte)
data[nread] = '\0';
blob->size = nread;
return blob;
}
struct cbox_blob *cbox_blob_new_from_file(const char *context_name, struct cbox_tarfile *tarfile, const char *path, const char *name, size_t max_size, GError **error)
{
gchar *fullpath = g_build_filename(path, name, NULL);
struct cbox_blob *blob = NULL;
if (tarfile)
{
struct cbox_taritem *item = cbox_tarfile_get_item_by_name(tarfile, fullpath, TRUE);
if (item)
{
int fd = cbox_tarfile_openitem(tarfile, item);
if (fd >= 0)
{
blob = read_from_fd(context_name, fullpath, fd, item->size, error);
cbox_tarfile_closeitem(tarfile, item, fd);
}
}
}
else
{
int fd = open(fullpath, O_RDONLY | O_LARGEFILE);
if (fd >= 0)
{
uint64_t size = lseek64(fd, 0, SEEK_END);
if (size <= max_size)
blob = read_from_fd(context_name, fullpath, fd, size, error);
else
g_set_error(error, G_FILE_ERROR, g_file_error_from_errno (errno), "%s: file '%s' too large (%llu while max size is %u)", context_name, fullpath, (unsigned long long)size, (unsigned)max_size);
close(fd);
}
else
g_set_error(error, G_FILE_ERROR, g_file_error_from_errno (errno), "%s: cannot open '%s': %s", context_name, fullpath, strerror(errno));
}
g_free(fullpath);
return blob;
}
void cbox_blob_destroy(struct cbox_blob *blob)
{
free(blob->data);
free(blob);
}

39
template/calfbox/blob.h

@ -1,39 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_BLOB_H
#define CBOX_BLOB_H
#include <glib.h>
#include <stddef.h>
struct cbox_blob
{
void *data;
size_t size;
};
struct cbox_tarfile;
extern struct cbox_blob *cbox_blob_new(size_t size);
extern struct cbox_blob *cbox_blob_new_from_file(const char *context_name, struct cbox_tarfile *tarfile, const char *path, const char *name, size_t max_size, GError **error);
extern struct cbox_blob *cbox_blob_new_copy_data(const void *data, size_t size);
extern struct cbox_blob *cbox_blob_new_acquire_data(void *data, size_t size);
extern void cbox_blob_destroy(struct cbox_blob *blob);
#endif

11
template/calfbox/py/cbox.py → template/calfbox/cbox.py

@ -1,9 +1,16 @@
from calfbox._cbox2 import *
from io import BytesIO
import struct
import sys
import traceback
import calfbox.metadata as metadata #local file metadata.py
try:
from _cbox2 import * #local file _cbox2.py
import metadata #local file metadata.py
except ModuleNotFoundError:
from ._cbox2 import *
from . import metadata #local file metadata.py
type_wrapper_debug = False
is_python3 = not sys.version.startswith("2")

574
template/calfbox/cboxrc-example

@ -1,574 +0,0 @@
[io]
inputs=2
in_1=#1
in_2=#2
out_1=#1
out_2=#2
;#midi=alsa_pcm:E-MU-XMidi2X2/midi_capture_2;alsa_pcm:E-MU-Xboard25/midi_capture_1
;midi=alsa_pcm:E-MU-XMidi2X2/midi_capture_2;alsa_pcm:E-MU-XMidi2X2/midi_capture_1
;midi=~alsa_pcm:in-.*-E-MU-XMidi2X2-MIDI-1;~alsa_pcm:in-.*-E-MU-XMidi2X2-MIDI-2;~alsa_pcm:in-.*-padKONTROL-MIDI-2
midi=*.*
[master]
tempo=100
beats_per_bar=4
;effect=cbox_reverb
[fxpreset:cbox_reverb]
engine=reverb
reverb_time=800
wet_gain=-12
dry_gain=0
stereo=-12
[scene:example]
layer1=organ
layer2=piano
[layer:piano]
instrument=progmega
out_channel=1
low_note=C3
[layer:organ]
instrument=default
out_channel=1
high_note=B2
[instrument:default]
engine=tonewheel_organ
percussion=1
percussion_3rd=1
upper_drawbars=888000000
;upper_drawbars=888888888
;upper_drawbars=888000008
;upper_drawbars=800000888
;upper_drawbars=800064000
;upper_drawbars=802244220
lower_drawbars=838000000
pedal_drawbars=80
vibrato_upper=1
vibrato_lower=1
vibrato_mode=c3
[instrument:progmega]
engine=fluidsynth
sf2=ProgMegaBank.sf2
reverb=1
chorus=1
channel1=SP250
channel2=jRhodes3a
channel3=P5 Brass
[instrument:progmega_cheap]
engine=fluidsynth
sf2=ProgMegaBank.sf2
reverb=0
chorus=0
channel1=SP250
channel2=jRhodes3a
channel3=P5 Brass
[instrument:progmega_fx]
engine=fluidsynth
sf2=ProgMegaBank.sf2
reverb=0
chorus=0
insert=chain
channel1=SP250
channel2=jRhodes3a
channel3=P5 Brass
[fxpreset:chain]
engine=fxchain
effect1=stream_phaser
effect2=stream_delay
[fxpreset:stream_phaser]
engine=phaser
center=500
mod_depth=300
lfo_freq=3
[fxpreset:stream_delay]
engine=delay
delay=250
wet_amt=0.25
feedback_gain=-12
[autojack]
soundcard0=Omega
soundcard1=STA
soundcard2=Intel
jack_options=-r -T
alsa_options=-p 128 -n 3 -X raw
jackd=/usr/bin/jackd
[soundcard:Omega]
usbid=1210:0002
[soundcard:STA]
device=DSP24
[soundcard:Intel]
device=Intel
[pattern:walkingminor]
title=Walking-minor
beats=4
resolution=1
track1=bass
bass_channel=2
bass_vel=80
bass_notes=c1,d1,eb1,g1
[track:two]
title=Cm/Ebm
pos1=walkingminor
pos2=walkingminor+3
[drumpattern:pat1]
title=Straight - Verse
beats=4
track1=bd
track2=sd
track3=hh
track4=ho
bd_note=c1
sd_note=d1
hh_note=f#1
ho_note=a#1
bd_trigger=9... .... 9.6. ....
sd_trigger=.... 9..5 .2.. 9...
hh_trigger=9353 7353 7353 73.3
ho_trigger=.... .... .... ..3.
[drumpattern:pat1fill]
title=Straight - Fill
beats=4
track1=bd
track2=sd
track3=hh
track4=ho
bd_note=c1
sd_note=d1
hh_note=f#1
ho_note=a#1
bd_trigger=9... .... 9.6. ....
sd_trigger=..64 9..5 .2.7 99.9
hh_trigger=9353 7353 7353 73.3
ho_trigger=.... .... .... ..3.
[drumpattern:pat2]
title=Enigma - Verse
beats=4
track1=bd
track2=sd
track3=hh
track4=ho
bd_note=c1
sd_note=d1
hh_note=f#1
ho_note=a#1
bd_trigger=9..7 ..7. ..6. ....
sd_trigger=.... 9... .... 9...
hh_trigger=9353 7353 7353 7353
ho_trigger=.... .... ..3. ....
[drumpattern:pat2fill]
title=Enigma - Fill
beats=4
resolution=4
track1=bd
track2=sd
track3=hh
track4=ho
track5=ht
track6=mt
bd_note=c1
sd_note=d1
hh_note=f#1
ho_note=a#1
ht_note=d2
mt_note=b1
bd_trigger=9..7 ..7. ..6. ....
sd_trigger=.... 9... .... 9..9
hh_trigger=9353 7353 7353 7353
ho_trigger=.... .... ..3. ....
ht_trigger=.5.. .... ...7 ....
mt_trigger=.... ...5 .... ..5.
[drumpattern:pat3]
title=Shuffle - Verse
beats=4
swing=6
track1=bd
track2=sd
track3=hh
track4=ho
track5=ht
track6=mt
bd_note=c1
sd_note=d1
hh_note=f#1
ho_note=a#1
ht_note=d2
mt_note=b1
bd_trigger=9.8. ...8 ..6. ....
sd_trigger=.... 94D. .54. 9..D
hh_trigger=9353 7353 7353 7353
ho_trigger=.... .... .... ....
ht_trigger=.... .... .... ....
mt_trigger=.... .... .... ....
[drumpattern:pat3fill]
title=Shuffle - Fill
beats=4
swing=6
track1=bd
track2=sd
track3=hh
track4=ho
track5=ht
track6=mt
bd_note=c1
sd_note=d1
hh_note=f#1
ho_note=a#1
ht_note=d2
mt_note=b1
bd_trigger=9.8. ...8 ..6. ....
sd_trigger=.... 9... F... F..9
hh_trigger=9353 7353 7353 7353
ho_trigger=.... .... .... ....
ht_trigger=.... .... ..9. .5..
mt_trigger=.... .... ...7 ..7.
[drumpattern:pat4]
title=Swing
beats=4
resolution=3
track1=bd
track2=sd
track3=hp
track4=rc
track5=rb
bd_note=c1
sd_note=d1
hp_note=g#1
rc_note=d#2
rb_note=f2
bd_trigger=... ... ... ..3
sd_trigger=... ..3 ..2 .3.
hp_trigger=... 6.. ... 6..
rc_trigger=2.. ..4 4.. ..3
rb_trigger=3.. ... 3.. ...
[drumpattern:pat4fill]
title=Swing
beats=4
resolution=3
track1=bd
track2=sd
track3=hp
track4=rc
track5=rb
bd_note=c1
sd_note=d1
hp_note=g#1
rc_note=d#2
rb_note=f2
bd_trigger=7.. 5.. ... ..5
sd_trigger=..5 ..3 .25 43.
hp_trigger=... 6.. ... 6..
rc_trigger=2.. ..4 4.. ...
rb_trigger=4.. ... 2.. ...
[drumpattern:pat5]
title=6/8 Blues - Verse
beats=4
resolution=3
track1=bd
track2=sd
track3=hh
track4=ho
bd_note=c1
sd_note=d1
hh_note=f#1
ho_note=a#1
bd_trigger=7.. ... 7.. .44
sd_trigger=... 8.. ... 8..
hh_trigger=7.5 6.4 7.5 6..
ho_trigger=... ... ... ..3
[drumpattern:pat5fill]
title=6/8 Blues - Fill
beats=4
resolution=3
track1=bd
track2=sd
track3=hh
track4=ho
track5=ht
track6=mt
bd_note=c1
sd_note=d1
hh_note=f#1
ho_note=a#1
ht_note=d2
mt_note=b1
bd_trigger=7.. ... ... ..4
sd_trigger=... 8.D 75. 85.
hh_trigger=7.5 6.. 7.. ...
ho_trigger=.3. ... ... ...
ht_trigger=... ... ..7 ...
mt_trigger=... ... ... ..5
[drumpattern:pat6]
title=Pompopom - Verse
beats=4
track1=bd
track2=sd
track3=hh
track4=ho
bd_note=c1
sd_note=d1
hh_note=f#1
ho_note=a#1
bd_trigger=9.97 ...9 .996 ....
sd_trigger=.... 9... .... 9...
hh_trigger=9.7. 7.7. 9.7. 7.7.
ho_trigger=.... .3.. .... ....
[drumpattern:pat6fill]
title=Pompopom - Fill
beats=4
track1=bd
track2=sd
track3=hh
track4=ho
bd_note=c1
sd_note=d1
hh_note=f#1
ho_note=a#1
bd_trigger=9..7 ...9 .9.6 ....
sd_trigger=.6.. 9.7. ..7D 97.9
hh_trigger=9.7. 7.7. 9.7. 7.7.
ho_trigger=.... .3.. .... ....
[drumpattern:pat7]
title=Rockish
beats=4
track1=bd
track2=sd
track3=hh
track4=ho
bd_note=c1
sd_note=d1
hh_note=f#1
ho_note=a#1
bd_trigger=98.6 ...7 .95. ....
sd_trigger=.... 9... .... 9..D
hh_trigger=7.5. 7.5. 7.5. 7.5.
ho_trigger=...3 .... .... ....
[drumpattern:pat7fill]
title=Rockish - Fill
beats=4
track1=bd
track2=sd
track3=hh
track4=ho
track5=mt
track6=ht
bd_note=c1
sd_note=d1
hh_note=f#1
ho_note=a#1
mt_note=b1
ht_note=d2
bd_trigger=98.6 ...7 .95. ....
sd_trigger=.... 9..7 ..9. 9..9
hh_trigger=7.5. 7.5. 7.5. 7.5.
ho_trigger=.5.3 .... .... ....
mt_trigger=.... .... .... ..8.
ht_trigger=.... .... ...9 ....
[drumpattern:pat8]
title=80s - Verse
beats=4
track1=bd
track2=sd
track3=hh
track4=ho
bd_note=c1
sd_note=d1
hh_note=f#1
ho_note=a#1
bd_trigger=96.. ..96 ..6. ....
sd_trigger=.... 9... .... 9...
hh_trigger=7.7. 7.7. 7.7. 7.7.
ho_trigger=.... .... .... ....
[drumpattern:pat8fill]
title=80s - Fill
beats=4
track1=bd
track2=sd
track3=hh
track4=ho
track5=mt
track6=ht
bd_note=c1
sd_note=d1
hh_note=f#1
ho_note=a#1
mt_note=b1
ht_note=d2
bd_trigger=96.. ..96 ..6. ....
sd_trigger=..7. 9... 7.7. 9...
hh_trigger=7.7. 7.7. 7.7. 7...
ho_trigger=.... .... .... ....
ht_trigger=.... .... .9.. .97.
mt_trigger=.... .... ...7 ...5
[drumpattern:pat9]
title=Disco - Verse
beats=4
swing=2
track1=bd
track2=sd
track3=hh
track4=ho
track5=rs
bd_note=c1
sd_note=d1
hh_note=f#1
ho_note=a#1
rs_note=c#1
bd_trigger=9... 9... 9... 9...
rs_trigger=..4. .4.. 4..4 ..4.
sd_trigger=.... 8..6 .... 8...
hh_trigger=74.7 74.7 74.7 74.7
ho_trigger=..5. ..5. ..5. ..5.
[drumpattern:pat9fill]
title=Disco - Fill
beats=4
swing=2
track1=bd
track2=sd
track3=hh
track4=ho
bd_note=c1
sd_note=d1
hh_note=f#1
ho_note=a#1
bd_trigger=9... 9... 9... 9...
sd_trigger=.6.. 8.58 .6.5 8688
hh_trigger=74.7 74.7 74.7 74.7
ho_trigger=..5. ..5. ..5. ..5.
[drumpattern:crash]
title=Crash cymbal
beats=4
track1=cc
cc_note=c#2
cc_trigger=9...
[drumpattern:crash2]
title=Kick+crash cymbal
beats=4
track1=cc
track2=bd
cc_note=a#2
bd_note=b0
cc_trigger=5...
bd_trigger=5...
[drumtrack:trk1]
title=Straight
pos1=pat1,crash
pos2=pat1
pos3=pat1
pos4=pat1fill
[drumtrack:trk2]
title=Enigma
pos1=pat2,crash
pos2=pat2
pos3=pat2
pos4=pat2fill
[drumtrack:trk3]
title=Shuffle
pos1=pat3,crash
pos2=pat3
pos3=pat3
pos4=pat3fill
[drumtrack:trk4]
title=Swing
pos1=pat4,crash2
pos2=pat4
pos3=pat4
pos4=pat4fill
[drumtrack:trk5]
title=6/8 Blues
pos1=pat5,crash
pos2=pat5
pos3=pat5
pos4=pat5fill
[drumtrack:trk6]
title=Pompopom
pos1=pat6,crash
pos2=pat6
pos3=pat6
pos4=pat6fill
[drumtrack:trk7]
title=Rockish
pos1=pat7,crash
pos2=pat7
pos3=pat7
pos4=pat7fill
[drumtrack:trk8]
title=80s
pos1=pat8,crash
pos2=pat8
pos3=pat8
pos4=pat8fill
[drumtrack:trk9]
title=Disco
pos1=pat9,crash
pos2=pat9
pos3=pat9
pos4=pat9fill
[layer:samplertest]
instrument=samplertest
[instrument:samplertest]
engine=sampler
program0=prog
[spgm:prog]
layer1=saw1
layer2=saw2
[slayer:saw1]
sample=*saw
tune=-5
pan=-30
volume=-6
[slayer:saw2]
sample=*saw
tune=+5
pan=30
volume=-6

175
template/calfbox/chorus.c

@ -1,175 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "config-api.h"
#include "dspmath.h"
#include "module.h"
#include <glib.h>
#include <malloc.h>
#include <math.h>
#include <memory.h>
#include <sndfile.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_CHORUS_LENGTH 4096
#define MODULE_PARAMS chorus_params
static float sine_table[2049];
struct chorus_params
{
float lfo_freq;
float min_delay;
float mod_depth;
float wet_dry;
float sphase;
};
struct chorus_module
{
struct cbox_module module;
float storage[MAX_CHORUS_LENGTH][2];
struct chorus_params *params;
int pos;
float tp32dsr;
uint32_t phase;
};
MODULE_PROCESSCMD_FUNCTION(chorus)
{
struct chorus_module *m = (struct chorus_module *)ct->user_data;
EFFECT_PARAM("/min_delay", "f", min_delay, double, , 1, 20) else
EFFECT_PARAM("/mod_depth", "f", mod_depth, double, , 1, 20) else
EFFECT_PARAM("/lfo_freq", "f", lfo_freq, double, , 0, 20) else
EFFECT_PARAM("/stereo_phase", "f", sphase, double, , 0, 360) else
EFFECT_PARAM("/wet_dry", "f", wet_dry, double, , 0, 1) else
if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
return cbox_execute_on(fb, NULL, "/min_delay", "f", error, m->params->min_delay) &&
cbox_execute_on(fb, NULL, "/mod_depth", "f", error, m->params->mod_depth) &&
cbox_execute_on(fb, NULL, "/lfo_freq", "f", error, m->params->lfo_freq) &&
cbox_execute_on(fb, NULL, "/stereo_phase", "f", error, m->params->sphase) &&
cbox_execute_on(fb, NULL, "/wet_dry", "f", error, m->params->wet_dry) &&
CBOX_OBJECT_DEFAULT_STATUS(&m->module, fb, error);
}
else
return cbox_object_default_process_cmd(ct, fb, cmd, error);
return TRUE;
}
void chorus_process_event(struct cbox_module *module, const uint8_t *data, uint32_t len)
{
// struct chorus_module *m = (struct chorus_module *)module;
}
void chorus_process_block(struct cbox_module *module, cbox_sample_t **inputs, cbox_sample_t **outputs)
{
struct chorus_module *m = (struct chorus_module *)module;
struct chorus_params *p = m->params;
float min_delay = p->min_delay;
float mod_depth = p->mod_depth;
float wet_dry = p->wet_dry;
int i, c;
int mask = MAX_CHORUS_LENGTH - 1;
uint32_t sphase = (uint32_t)(p->sphase * 65536.0 * 65536.0 / 360);
uint32_t dphase = (uint32_t)(p->lfo_freq * m->tp32dsr);
const int fracbits = 32 - 11;
const int fracscale = 1 << fracbits;
for (c = 0; c < 2; c++)
{
int pos = m->pos;
uint32_t phase = m->phase + c * sphase;
for (i = 0; i < CBOX_BLOCK_SIZE; i++)
{
float dry = inputs[c][i];
float v0 = sine_table[phase >> fracbits];
float v1 = sine_table[1 + (phase >> fracbits)];
float lfo = v0 + (v1 - v0) * ((phase & (fracscale - 1)) * (1.0 / fracscale));
m->storage[pos & mask][c] = dry;
float dva = min_delay + mod_depth * lfo;
int dv = (int)dva;
float frac = dva - dv;
float smp0 = m->storage[(pos - dv) & mask][c];
float smp1 = m->storage[(pos - dv - 1) & mask][c];
float smp = smp0 + (smp1 - smp0) * frac;
outputs[c][i] = sanef(dry + (smp - dry) * wet_dry);
pos++;
phase += dphase;
}
}
m->phase += CBOX_BLOCK_SIZE * dphase;
m->pos += CBOX_BLOCK_SIZE;
}
MODULE_SIMPLE_DESTROY_FUNCTION(chorus)
MODULE_CREATE_FUNCTION(chorus)
{
static int inited = 0;
int i;
if (!inited)
{
inited = 1;
for (i = 0; i < 2049; i++)
sine_table[i] = 1 + sin(i * M_PI / 1024);
}
struct chorus_module *m = malloc(sizeof(struct chorus_module));
CALL_MODULE_INIT(m, 2, 2, chorus);
m->module.process_event = chorus_process_event;
m->module.process_block = chorus_process_block;
m->pos = 0;
m->phase = 0;
m->tp32dsr = 65536.0 * 65536.0 * m->module.srate_inv;
struct chorus_params *p = malloc(sizeof(struct chorus_params));
m->params = p;
p->sphase = cbox_config_get_float(cfg_section, "stereo_phase", 90.f);
p->lfo_freq = cbox_config_get_float(cfg_section, "lfo_freq", 1.f);
p->min_delay = cbox_config_get_float(cfg_section, "min_delay", 20.f);
p->mod_depth = cbox_config_get_float(cfg_section, "mod_depth", 15.f);
p->wet_dry = cbox_config_get_float(cfg_section, "wet_dry", 0.5f);
for (i = 0; i < MAX_CHORUS_LENGTH; i++)
m->storage[i][0] = m->storage[i][1] = 0.f;
return &m->module;
}
struct cbox_module_keyrange_metadata chorus_keyranges[] = {
};
struct cbox_module_livecontroller_metadata chorus_controllers[] = {
};
DEFINE_MODULE(chorus, 2, 2)

11
template/calfbox/cleanpythonbuild.sh

@ -1,11 +0,0 @@
#!/bin/bash
make clean
make distclean
rm build -rf
set -e
sh autogen.sh
./configure --prefix=/usr --without-python
make CFLAGS="-O0 -g"
python3 setup.py build
sudo python3 setup.py install
sudo make install

208
template/calfbox/cmd.c

@ -1,208 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "blob.h"
#include "cmd.h"
#include "dom.h"
#include "errors.h"
#include <assert.h>
#include <glib.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <uuid/uuid.h>
void cbox_command_target_init(struct cbox_command_target *ct, cbox_process_cmd cmd, void *user_data)
{
ct->process_cmd = cmd;
ct->user_data = user_data;
}
gboolean cbox_execute_on(struct cbox_command_target *ct, struct cbox_command_target *fb, const char *cmd_name, const char *args, GError **error, ...)
{
va_list av;
va_start(av, error);
gboolean res = cbox_execute_on_v(ct, fb, cmd_name, args, av, error);
va_end(av);
return res;
}
gboolean cbox_execute_on_v(struct cbox_command_target *ct, struct cbox_command_target *fb, const char *cmd_name, const char *args, va_list av, GError **error)
{
int argcount = 0;
struct cbox_osc_command cmd;
uint8_t *extra_data;
// XXXKF might be not good enough for weird platforms
uint32_t unit_size = sizeof(double);
// this must be a power of 2 to guarantee proper alignment
assert(unit_size >= sizeof(int) && (unit_size == 4 || unit_size == 8));
cmd.command = cmd_name;
cmd.arg_types = args;
for (int i = 0; args[i]; i++)
argcount = i + 1;
// contains pointers to all the values, plus values themselves in case of int/double
// (casting them to pointers is ugly, and va_arg does not return a lvalue)
cmd.arg_values = malloc(sizeof(void *) * argcount + unit_size * argcount);
extra_data = (uint8_t *)&cmd.arg_values[argcount];
for (int i = 0; i < argcount; i++)
{
int iv;
double fv;
void *pv = extra_data + unit_size * i;
switch(args[i])
{
case 's':
cmd.arg_values[i] = va_arg(av, char *);
break;
case 'i':
iv = va_arg(av, int);
memcpy(pv, &iv, sizeof(int));
cmd.arg_values[i] = pv;
break;
case 'f': // double really
fv = (double)va_arg(av, double);
memcpy(pv, &fv, sizeof(double));
cmd.arg_values[i] = pv;
break;
case 'b':
cmd.arg_values[i] = va_arg(av, struct cbox_blob *);
break;
case 'o':
cmd.arg_values[i] = va_arg(av, struct cbox_objhdr *);
break;
case 'u':
cmd.arg_values[i] = va_arg(av, struct cbox_uuid *);
break;
default:
g_error("Invalid format character '%c' for command '%s'", args[i], cmd_name);
assert(0);
}
}
gboolean result = ct->process_cmd(ct, fb, &cmd, error);
free(cmd.arg_values);
return result;
}
gboolean cbox_osc_command_dump(const struct cbox_osc_command *cmd)
{
g_message("Command = %s, args = %s", cmd->command, cmd->arg_types);
for (int i = 0; cmd->arg_types[i]; i++)
{
switch(cmd->arg_types[i])
{
case 's':
g_message("Args[%d] = '%s'", i, (const char *)cmd->arg_values[i]);
break;
case 'o':
{
struct cbox_objhdr *oh = cmd->arg_values[i];
char buf[40];
uuid_unparse(oh->instance_uuid.uuid, buf);
g_message("Args[%d] = uuid:'%s'", i, buf);
break;
}
case 'i':
g_message("Args[%d] = %d", i, *(int *)cmd->arg_values[i]);
break;
case 'f':
g_message("Args[%d] = %f", i, *(double *)cmd->arg_values[i]);
break;
case 'b':
{
struct cbox_blob *b = cmd->arg_values[i];
g_message("Args[%d] = (%p, %d)", i, b->data, (int)b->size);
break;
}
default:
g_error("Invalid format character '%c' for command '%s'", cmd->arg_types[i], cmd->command);
assert(0);
return FALSE;
}
}
return TRUE;
}
gboolean cbox_check_fb_channel(struct cbox_command_target *fb, const char *command, GError **error)
{
if (fb)
return TRUE;
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Feedback channel required for command '%s'", command);
return FALSE;
}
gboolean cbox_execute_sub(struct cbox_command_target *ct, struct cbox_command_target *fb, const struct cbox_osc_command *cmd, const char *new_command, GError **error)
{
struct cbox_osc_command subcmd;
subcmd.command = new_command;
subcmd.arg_types = cmd->arg_types;
subcmd.arg_values = cmd->arg_values;
return ct->process_cmd(ct, fb, &subcmd, error);
}
gboolean cbox_parse_path_part_int(const struct cbox_osc_command *cmd, const char *path, const char **subcommand, int *index, int min_index, int max_index, GError **error)
{
char *numcopy = NULL;
if (!cbox_parse_path_part_str(cmd, path, subcommand, &numcopy, error))
return FALSE;
if (!*subcommand)
return TRUE;
char *endptr = NULL;
*index = strtol(numcopy, &endptr, 10);
if (!*numcopy && *endptr)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Invalid index %s for command %s", numcopy, cmd->command);
g_free(numcopy);
*subcommand = NULL;
return TRUE;
}
if (*index < min_index || *index > max_index)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Index %s out of range [%d, %d] for command %s", numcopy, min_index, max_index, cmd->command);
g_free(numcopy);
*subcommand = NULL;
return TRUE;
}
g_free(numcopy);
return TRUE;
}
gboolean cbox_parse_path_part_str(const struct cbox_osc_command *cmd, const char *path, const char **subcommand, char **path_element, GError **error)
{
*path_element = NULL;
*subcommand = NULL;
int plen = strlen(path);
if (!strncmp(cmd->command, path, plen))
{
const char *num = cmd->command + plen;
const char *slash = strchr(num, '/');
if (!slash)
{
cbox_set_command_error_with_msg(error, cmd, "needs at least one extra path element");
return TRUE;
}
*path_element = g_strndup(num, slash-num);
*subcommand = slash;
return TRUE;
}
return FALSE;
}

64
template/calfbox/cmd.h

@ -1,64 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_CMD_H
#define CBOX_CMD_H
#include <glib.h>
#include <stdarg.h>
#include <stdint.h>
#define CBOX_ARG_I(cmd, idx) (*(int *)(cmd)->arg_values[(idx)])
#define CBOX_ARG_S(cmd, idx) ((const char *)(cmd)->arg_values[(idx)])
#define CBOX_ARG_B(cmd, idx) ((const struct cbox_blob *)(cmd)->arg_values[(idx)])
#define CBOX_ARG_F(cmd, idx) (*(double *)(cmd)->arg_values[(idx)])
#define CBOX_ARG_O(cmd, idx, src, class, error) cbox_document_get_object_by_text_uuid(CBOX_GET_DOCUMENT(src), (const char *)(cmd)->arg_values[(idx)], &CBOX_CLASS(class), (error))
#define CBOX_ARG_S_ISNULL(cmd, idx) (0 == (const char *)(cmd)->arg_values[(idx)])
struct cbox_command_target;
struct cbox_osc_command
{
const char *command;
const char *arg_types;
void **arg_values;
};
typedef gboolean (*cbox_process_cmd)(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error);
struct cbox_command_target
{
void *user_data;
cbox_process_cmd process_cmd;
};
void cbox_command_target_init(struct cbox_command_target *ct, cbox_process_cmd cmd, void *user_data);
extern gboolean cbox_check_fb_channel(struct cbox_command_target *fb, const char *command, GError **error);
extern gboolean cbox_execute_sub(struct cbox_command_target *ct, struct cbox_command_target *fb, const struct cbox_osc_command *cmd, const char *new_command, GError **error);
extern gboolean cbox_execute_on(struct cbox_command_target *ct, struct cbox_command_target *fb, const char *cmd, const char *args, GError **error, ...);
extern gboolean cbox_execute_on_v(struct cbox_command_target *ct, struct cbox_command_target *fb, const char *cmd, const char *args, va_list va, GError **error);
extern gboolean cbox_osc_command_dump(const struct cbox_osc_command *cmd);
// Note: this sets *subcommand to NULL on parse error; requires "/path/" as path
extern gboolean cbox_parse_path_part_int(const struct cbox_osc_command *cmd, const char *path, const char **subcommand, int *index, int min_index, int max_index, GError **error);
extern gboolean cbox_parse_path_part_str(const struct cbox_osc_command *cmd, const char *path, const char **subcommand, char **path_element, GError **error);
#endif

155
template/calfbox/compressor.c

@ -1,155 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "config-api.h"
#include "dspmath.h"
#include "module.h"
#include "onepole-float.h"
#include <glib.h>
#include <malloc.h>
#include <math.h>
#include <memory.h>
#include <sndfile.h>
#include <stdio.h>
#include <stdlib.h>
#define MODULE_PARAMS compressor_params
struct compressor_params
{
float threshold;
float ratio;
float attack;
float release;
float makeup;
};
struct compressor_module
{
struct cbox_module module;
struct compressor_params *params, *old_params;
struct cbox_onepolef_coeffs attack_lp, release_lp, fast_attack_lp;
struct cbox_onepolef_state tracker;
struct cbox_onepolef_state tracker2;
};
MODULE_PROCESSCMD_FUNCTION(compressor)
{
struct compressor_module *m = (struct compressor_module *)ct->user_data;
EFFECT_PARAM("/makeup", "f", makeup, double, dB2gain_simple, -100, 100) else
EFFECT_PARAM("/threshold", "f", threshold, double, dB2gain_simple, -100, 100) else
EFFECT_PARAM("/ratio", "f", ratio, double, , 1, 100) else
EFFECT_PARAM("/attack", "f", attack, double, , 1, 1000) else
EFFECT_PARAM("/release", "f", release, double, , 1, 1000) else
if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
return cbox_execute_on(fb, NULL, "/makeup", "f", error, gain2dB_simple(m->params->makeup))
&& cbox_execute_on(fb, NULL, "/threshold", "f", error, gain2dB_simple(m->params->threshold))
&& cbox_execute_on(fb, NULL, "/ratio", "f", error, m->params->ratio)
&& cbox_execute_on(fb, NULL, "/attack", "f", error, m->params->attack)
&& cbox_execute_on(fb, NULL, "/release", "f", error, m->params->release)
&& CBOX_OBJECT_DEFAULT_STATUS(&m->module, fb, error)
;
}
else
return cbox_object_default_process_cmd(ct, fb, cmd, error);
return TRUE;
}
void compressor_process_event(struct cbox_module *module, const uint8_t *data, uint32_t len)
{
// struct compressor_module *m = module->user_data;
}
void compressor_process_block(struct cbox_module *module, cbox_sample_t **inputs, cbox_sample_t **outputs)
{
struct compressor_module *m = module->user_data;
if (m->params != m->old_params)
{
float scale = M_PI * 1000 / m->module.srate;
cbox_onepolef_set_lowpass(&m->fast_attack_lp, 2 * scale / m->params->attack);
cbox_onepolef_set_lowpass(&m->attack_lp, scale / m->params->attack);
cbox_onepolef_set_lowpass(&m->release_lp, scale / m->params->release);
m->old_params = m->params;
}
float threshold = m->params->threshold, invratio = 1.0 / m->params->ratio;
for (int i = 0; i < CBOX_BLOCK_SIZE; i++)
{
float left = inputs[0][i], right = inputs[1][i];
float sig = 0.5 * (fabs(left) > fabs(right) ? fabs(left) : fabs(right));
int falling = sig < m->tracker.y1 && sig < m->tracker.x1;
int rising_fast = sig > 4 * m->tracker.y1 && sig > 4 * m->tracker.x1;
sig = cbox_onepolef_process_sample(&m->tracker, falling ? &m->release_lp : (rising_fast && m->tracker.y1 ? &m->fast_attack_lp : &m->attack_lp), sig);
sig = cbox_onepolef_process_sample(&m->tracker2, falling ? &m->release_lp : (rising_fast && m->tracker2.y1 ? &m->fast_attack_lp : &m->attack_lp), sig);
float gain = 1.0;
if (sig > threshold)
gain = threshold * powf(sig / threshold, invratio) / sig;
gain *= m->params->makeup;
outputs[0][i] = left * gain;
outputs[1][i] = right * gain;
}
}
MODULE_SIMPLE_DESTROY_FUNCTION(compressor)
MODULE_CREATE_FUNCTION(compressor)
{
static int inited = 0;
if (!inited)
{
inited = 1;
}
struct compressor_module *m = malloc(sizeof(struct compressor_module));
CALL_MODULE_INIT(m, 2, 2, compressor);
m->module.process_event = compressor_process_event;
m->module.process_block = compressor_process_block;
struct compressor_params *p = malloc(sizeof(struct compressor_params));
p->threshold = cbox_config_get_gain_db(cfg_section, "threshold", -12.0);
p->ratio = cbox_config_get_float(cfg_section, "ratio", 2.0);
p->attack = cbox_config_get_float(cfg_section, "attack", 5.0);
p->release = cbox_config_get_float(cfg_section, "release", 100.0);
p->makeup = cbox_config_get_gain_db(cfg_section, "makeup", 6.0);
m->params = p;
m->old_params = NULL;
cbox_onepolef_reset(&m->tracker);
cbox_onepolef_reset(&m->tracker2);
return &m->module;
}
struct cbox_module_keyrange_metadata compressor_keyranges[] = {
};
struct cbox_module_livecontroller_metadata compressor_controllers[] = {
};
DEFINE_MODULE(compressor, 2, 2)

357
template/calfbox/config-api.c

@ -1,357 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config-api.h"
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static GKeyFile *config_keyfile;
static gchar *keyfile_name;
static GStringChunk *cfg_strings = NULL;
static GHashTable *config_sections_hash = NULL;
void cbox_config_init(const char *override_file)
{
const gchar *keyfiledirs[3];
const gchar *keyfilename = ".cboxrc";
GKeyFileFlags flags = G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS;
GError *error = NULL;
if (config_keyfile)
return;
config_sections_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
cfg_strings = g_string_chunk_new(100);
config_keyfile = g_key_file_new();
// Allow virtual (in-memory) config by passing empty string
if (override_file && !*override_file)
{
keyfile_name = g_strdup("");
return;
}
keyfiledirs[0] = getenv("HOME");
keyfiledirs[1] = NULL;
// XXXKF add proper error handling
if (override_file)
{
if (!g_key_file_load_from_file(config_keyfile, override_file, flags, &error))
{
g_warning("Could not read user config: %s", error->message);
g_error_free(error);
}
else
{
keyfile_name = g_strdup(override_file);
g_message("User config pathname is %s", keyfile_name);
return;
}
}
if (!g_key_file_load_from_dirs(config_keyfile, keyfilename, keyfiledirs, &keyfile_name, flags, &error))
{
g_warning("Could not read cboxrc: %s, search dir = %s, filename = %s", error->message, keyfiledirs[0], keyfilename);
g_error_free(error);
}
else
{
g_message("Config pathname is %s", keyfile_name);
}
}
int cbox_config_has_section(const char *section)
{
return section && g_key_file_has_group(config_keyfile, section);
}
char *cbox_config_get_string(const char *section, const char *key)
{
return cbox_config_get_string_with_default(section, key, NULL);
}
void cbox_config_set_string(const char *section, const char *key, const char *value)
{
g_key_file_set_string(config_keyfile, section, key, value);
}
char *cbox_config_permify(const char *temporary)
{
return g_string_chunk_insert(cfg_strings, temporary);
}
char *cbox_config_get_string_with_default(const char *section, const char *key, char *def_value)
{
if (section && key && g_key_file_has_key(config_keyfile, section, key, NULL))
{
gchar *tmp = g_key_file_get_string(config_keyfile, section, key, NULL);
gchar *perm = g_string_chunk_insert(cfg_strings, tmp);
g_free(tmp);
return perm;
}
else
{
return def_value ? g_string_chunk_insert(cfg_strings, def_value) : NULL;
}
}
int cbox_config_get_int(const char *section, const char *key, int def_value)
{
GError *error = NULL;
int result;
if (!section || !key)
return def_value;
result = g_key_file_get_integer(config_keyfile, section, key, &error);
if (error)
{
g_error_free(error);
return def_value;
}
return result;
}
void cbox_config_set_int(const char *section, const char *key, int value)
{
g_key_file_set_integer(config_keyfile, section, key, value);
}
float cbox_config_get_float(const char *section, const char *key, float def_value)
{
GError *error = NULL;
float result;
if (!section || !key)
return def_value;
result = g_key_file_get_double(config_keyfile, section, key, &error);
if (error)
{
g_error_free(error);
return def_value;
}
return result;
}
void cbox_config_set_float(const char *section, const char *key, double value)
{
g_key_file_set_double(config_keyfile, section, key, value);
}
float cbox_config_get_gain(const char *section, const char *key, float def_value)
{
GError *error = NULL;
float result;
if (!section || !key)
return def_value;
result = g_key_file_get_double(config_keyfile, section, key, &error);
if (error)
{
g_error_free(error);
return def_value;
}
return pow(2.0, result / 6.0);
}
float cbox_config_get_gain_db(const char *section, const char *key, float def_value)
{
return cbox_config_get_gain(section, key, pow(2.0, def_value / 6.0));
}
void cbox_config_foreach_section(void (*process)(void *user_data, const char *section), void *user_data)
{
gsize i, length = 0;
gchar **groups = g_key_file_get_groups (config_keyfile, &length);
if (!groups)
return;
for (i = 0; i < length; i++)
{
process(user_data, groups[i]);
}
g_strfreev(groups);
}
void cbox_config_foreach_key(void (*process)(void *user_data, const char *key), const char *section, void *user_data)
{
gsize i, length = 0;
gchar **keys = g_key_file_get_keys (config_keyfile, section, &length, NULL);
if (!keys)
return;
for (i = 0; i < length; i++)
{
process(user_data, keys[i]);
}
g_strfreev(keys);
}
int cbox_config_remove_section(const char *section)
{
return 0 != g_key_file_remove_group(config_keyfile, section, NULL);
}
int cbox_config_remove_key(const char *section, const char *key)
{
return 0 != g_key_file_remove_key(config_keyfile, section, key, NULL);
}
gboolean cbox_config_save(const char *filename, GError **error)
{
gsize len = 0;
gchar *data = g_key_file_to_data(config_keyfile, &len, error);
if (!data)
return FALSE;
if (filename == NULL)
filename = keyfile_name;
gboolean ok = g_file_set_contents(filename, data, len, error);
g_free(data);
return ok;
}
struct cbox_cfgfile
{
gchar *libname;
gchar *filename;
GKeyFile *keyfile;
};
struct cbox_cfgfile *cbox_cfgfile_get_by_libname(const char *name)
{
// XXXKF implement
return NULL;
}
struct cbox_sectref
{
struct cbox_cfgfile *cfgfile;
gchar *section;
};
static struct cbox_sectref *cbox_sectref_lookup(const char *name)
{
struct cbox_sectref *sr = g_hash_table_lookup(config_sections_hash, name);
return sr;
}
static void cbox_sectref_keep(struct cbox_sectref *sect)
{
gchar *tmp = g_strdup_printf("%s@%s", sect->section, sect->cfgfile->libname);
g_hash_table_insert(config_sections_hash, tmp, sect);
g_free(tmp);
}
static void cbox_sectref_set_from_string(struct cbox_sectref *sr, const gchar *refname, struct cbox_cfgfile *default_lib)
{
const gchar *p = strchr(refname, '@');
if (p)
{
sr->section = g_strndup(refname, p - refname);
sr->cfgfile = cbox_cfgfile_get_by_libname(p + 1);
}
else
{
sr->section = g_strndup(refname, p - refname);
sr->cfgfile = default_lib;
}
}
// find the section 'prefix+refname.section' in the config file - either the one referenced by sect, or refname.file
struct cbox_sectref *cbox_config_sectref(struct cbox_sectref *sect, const char *prefix, const char *refname)
{
if (!prefix)
prefix = "";
gchar *tmpsect = NULL;
const char *p = strchr(refname, '@');
if (p)
tmpsect = g_strdup_printf("%s%s", prefix, refname);
else
tmpsect = g_strdup_printf("%s%s@%s", prefix, refname, sect->cfgfile->libname);
struct cbox_sectref *sr = cbox_sectref_lookup(tmpsect);
if (sr)
{
g_free(tmpsect);
return sr;
}
sr = malloc(sizeof(struct cbox_sectref));
cbox_sectref_set_from_string(sr, tmpsect, sect ? sect->cfgfile : NULL);
g_free(tmpsect);
cbox_sectref_keep(sr);
return sr;
}
struct cbox_sectref *cbox_config_get_sectref(struct cbox_sectref *sect, const char *prefix, const char *key)
{
if (!key || !sect)
return NULL;
//const char *sectname = cbox_config_get_string(sect, key);
const char *sectname = cbox_config_get_string(sect->section, key);
if (!sectname)
return NULL;
return cbox_config_sectref(sect, prefix, sectname);
}
struct cbox_sectref *cbox_config_get_sectref_n(struct cbox_sectref *sect, const char *prefix, const char *key, int index)
{
if (!key || !sect)
return NULL;
gchar *tmp = g_strdup_printf("%s%d", key, index);
struct cbox_sectref *sr = cbox_config_get_sectref(sect, prefix, tmp);
g_free(tmp);
return sr;
}
struct cbox_sectref *cbox_config_get_sectref_suffix(struct cbox_sectref *sect, const char *prefix, const char *key, const char *suffix)
{
if (!key || !sect)
return NULL;
gchar *tmp = g_strdup_printf("%s%s", key, suffix ? suffix : "");
struct cbox_sectref *sr = cbox_config_get_sectref(sect, prefix, tmp);
g_free(tmp);
return sr;
}
void cbox_config_close()
{
if (config_sections_hash)
{
g_hash_table_destroy(config_sections_hash);
config_sections_hash = NULL;
}
if (config_keyfile)
{
g_key_file_free(config_keyfile);
config_keyfile = NULL;
}
if (cfg_strings)
{
g_string_chunk_free(cfg_strings);
cfg_strings = NULL;
}
if (keyfile_name)
{
g_free(keyfile_name);
keyfile_name = NULL;
}
}

53
template/calfbox/config-api.h

@ -1,53 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_CONFIG_API_H
#define CBOX_CONFIG_API_H
#include <glib.h>
struct cbox_sectref;
extern void cbox_config_init(const char *override_file);
extern int cbox_config_has_section(const char *section);
extern char *cbox_config_get_string(const char *section, const char *key);
extern char *cbox_config_get_string_with_default(const char *section, const char *key, char *def_value);
extern int cbox_config_get_int(const char *section, const char *key, int def_value);
extern float cbox_config_get_float(const char *section, const char *key, float def_value);
extern float cbox_config_get_gain(const char *section, const char *key, float def_value);
extern float cbox_config_get_gain_db(const char *section, const char *key, float def_value);
extern void cbox_config_foreach_section(void (*process)(void *user_data, const char *section), void *user_data);
extern void cbox_config_foreach_key(void (*process)(void *user_data, const char *key), const char *section, void *user_data);
extern char *cbox_config_permify(const char *temporary);
extern void cbox_config_set_string(const char *section, const char *key, const char *value);
extern void cbox_config_set_int(const char *section, const char *key, int value);
extern void cbox_config_set_float(const char *section, const char *key, double value);
extern int cbox_config_remove_section(const char *section);
extern int cbox_config_remove_key(const char *section, const char *key);
extern gboolean cbox_config_save(const char *filename, GError **error);
extern struct cbox_sectref *cbox_config_sectref(struct cbox_sectref *def_sect, const char *prefix, const char *refname);
extern struct cbox_sectref *cbox_config_get_sectref(struct cbox_sectref *sect, const char *prefix, const char *key);
extern struct cbox_sectref *cbox_config_get_sectref_n(struct cbox_sectref *sect, const char *prefix, const char *key, int index);
extern struct cbox_sectref *cbox_config_get_sectref_suffix(struct cbox_sectref *sect, const char *prefix, const char *key, const char *suffix);
extern void cbox_config_close(void);
#endif

162
template/calfbox/configure.ac

@ -1,162 +0,0 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.71])
AC_INIT([calfbox],[0.0.3],[wdev@foltman.com])
AC_CONFIG_HEADERS([config.h])
LT_INIT([])
LT_LANG([C])
AM_INIT_AUTOMAKE(1.8)
if test "x$prefix" = "xNONE"; then
prefix=$ac_default_prefix
fi
# Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL
PKG_PROG_PKG_CONFIG
# Checks for headers.
AC_CHECK_INCLUDES_DEFAULT
AC_PROG_EGREP
# Set initial parameters
PYTHON_ENABLED="yes"
NCURSES_ENABLED="yes"
JACK_ENABLED="yes"
FLUIDSYNTH_ENABLED="yes"
LIBSMF_ENABLED="yes"
LIBUSB_ENABLED="yes"
SSE_ENABLED="no"
NEON_ENABLED="no"
# Check options
AC_MSG_CHECKING([whether to enable Python embedding])
AC_ARG_WITH(python,
AS_HELP_STRING([--without-python],[disable Python embedding]),
[if test "$withval" = "no"; then PYTHON_ENABLED="no"; fi],[])
AC_MSG_RESULT($PYTHON_ENABLED)
AC_MSG_CHECKING([whether to enable ncurses UI])
AC_ARG_WITH(ncurses,
AS_HELP_STRING([--without-ncurses],[disable ncurses ui]),
[if test "$withval" = "no"; then NCURSES_ENABLED="no"; fi],[])
AC_MSG_RESULT($NCURSES_ENABLED)
AC_MSG_CHECKING([whether to enable JACK I/O])
AC_ARG_WITH(jack,
AS_HELP_STRING([--without-jack],[disable JACK audio and MIDI]),
[if test "$withval" = "no"; then JACK_ENABLED="no"; fi],[])
AC_MSG_RESULT($JACK_ENABLED)
AC_MSG_CHECKING([whether to enable Fluidsynth])
AC_ARG_WITH(fluidsynth,
AS_HELP_STRING([--without-fluidsynth],[disable use of Fluidsynth]),
[if test "$withval" = "no"; then FLUIDSYNTH_ENABLED="no"; fi],[])
AC_MSG_RESULT($FLUIDSYNTH_ENABLED)
AC_MSG_CHECKING([whether to enable libsmf])
AC_ARG_WITH(libsmf,
AS_HELP_STRING([--without-libsmf],[disable use of libsmf]),
[if test "$withval" = "no"; then LIBSMF_ENABLED="no"; fi],[])
AC_MSG_RESULT($LIBSMF_ENABLED)
AC_MSG_CHECKING([whether to enable libusb])
AC_ARG_WITH(libusb,
AS_HELP_STRING([--without-libusb],[disable use of libusb]),
[if test "$withval" = "no"; then LIBUSB_ENABLED="no"; fi],[])
AC_MSG_RESULT($LIBUSB_ENABLED)
AC_MSG_CHECKING([whether to enable SSE (x86 family only)])
AC_ARG_WITH(sse,
AS_HELP_STRING([--with-sse],[enable use of SSE]),
[if test "$withval" = "yes"; then SSE_ENABLED="yes"; fi],[])
AC_MSG_RESULT($SSE_ENABLED)
AC_MSG_CHECKING([whether to enable NEON (ARM family only)])
AC_ARG_WITH(neon,
AS_HELP_STRING([--with-neon],[enable use of NEON]),
[if test "$withval" = "yes"; then NEON_ENABLED="yes"; fi],[])
AC_MSG_RESULT($NEON_ENABLED)
# Check dependencies
AC_CHECK_HEADER(uuid/uuid.h, true, AC_MSG_ERROR([libuuid header (uuid/uuid.h) is required]))
AC_CHECK_LIB(uuid, uuid_unparse, true, AC_MSG_ERROR([libuuid is required]))
PKG_CHECK_MODULES(GLIB_DEPS, glib-2.0 >= 2.6, true, AC_MSG_ERROR([libglib-2.0 is required]))
if test "$LIBUSB_ENABLED" = "yes"; then
PKG_CHECK_MODULES(LIBUSB_DEPS, libusb-1.0 >= 1.0, true, AC_MSG_ERROR([libusb-1.0 is required]))
fi
PKG_CHECK_MODULES(LIBSNDFILE_DEPS, sndfile, true, AC_MSG_ERROR([libsndfile is required]))
if test "$NCURSES_ENABLED" = "yes"; then
PKG_CHECK_MODULES(NCURSES_DEPS, ncurses, true, AC_MSG_ERROR([libncurses is required]))
fi
if test "$FLUIDSYNTH_ENABLED" = "yes"; then
PKG_CHECK_MODULES(FLUIDSYNTH_DEPS, fluidsynth >= 1.0.8, true, AC_MSG_ERROR([fluidsynth 1.0.8 is required]))
fi
if test "$LIBSMF_ENABLED" = "yes"; then
PKG_CHECK_MODULES(LIBSMF_DEPS, smf >= 1.3, true, AC_MSG_ERROR([libsmf 1.3 is required (libsmf.sourceforge.net)]))
fi
if test "$JACK_ENABLED" = "yes"; then
PKG_CHECK_MODULES(JACK_DEPS, jack >= 0.116.0, true, AC_MSG_ERROR([JACK is required (or use --without-jack)]))
AC_CHECK_HEADER(jack/jack.h, true, AC_MSG_ERROR([JACK is required (or use --without-jack)]))
PKG_CHECK_MODULES(JACK_RENAME_PORT, jack >= 0.124.2 jack < 1.9.0, JACK_HAS_RENAME="yes", JACK_HAS_RENAME="no")
PKG_CHECK_MODULES(JACK2_RENAME_PORT, jack >= 1.9.11, JACK_HAS_RENAME="yes", JACK_HAS_RENAME_DUMMY="no")
fi
if test "$PYTHON_ENABLED" = "yes"; then
PKG_CHECK_MODULES(PYTHON_DEPS, python3-embed >= 3.0, true, AC_MSG_ERROR([python 3.0 or newer is required (or use --without-python)]))
fi
# Generate Automake conditionals
AM_CONDITIONAL(USE_PYTHON, test "$PYTHON_ENABLED" = "yes")
AM_CONDITIONAL(USE_NCURSES, test "$NCURSES_ENABLED" = "yes")
AM_CONDITIONAL(USE_JACK, test "$JACK_ENABLED" = "yes")
AM_CONDITIONAL(USE_FLUIDSYNTH, test "$FLUIDSYNTH_ENABLED" = "yes")
AM_CONDITIONAL(USE_LIBSMF, test "$LIBSMF_ENABLED" = "yes")
AM_CONDITIONAL(USE_LIBUSB, test "$LIBUSB_ENABLED" = "yes")
AM_CONDITIONAL(USE_SSE, test "$SSE_ENABLED" = "yes")
AM_CONDITIONAL(USE_NEON, test "$NEON_ENABLED" = "yes")
# Generate config.h conditionals
if test "$PYTHON_ENABLED" = "yes"; then
AC_DEFINE(USE_PYTHON, 1, [Python will be included])
fi
if test "$NCURSES_ENABLED" = "yes"; then
AC_DEFINE(USE_NCURSES, 1, [ncurses will be included])
fi
if test "$JACK_ENABLED" = "yes"; then
AC_DEFINE(USE_JACK, 1, [JACK I/O will be included])
fi
if test "$JACK_HAS_RENAME" = "yes"; then
AC_DEFINE(JACK_HAS_RENAME, 1, [JACK function jack_port_rename should be used instead of jack_port_set_name])
fi
if test "$FLUIDSYNTH_ENABLED" = "yes"; then
AC_DEFINE(USE_FLUIDSYNTH, 1, [Fluidsynth will be included])
fi
if test "$LIBSMF_ENABLED" = "yes"; then
AC_DEFINE(USE_LIBSMF, 1, [libsmf will be used])
fi
if test "$LIBUSB_ENABLED" = "yes"; then
AC_DEFINE(USE_LIBUSB, 1, [libusb will be used])
fi
if test "$LIBUSB_ENABLED" = "no" && test "$JACK_ENABLED" = "no"; then
AC_MSG_ERROR([Neither JACK nor libusb are enabled, at least one is required])
fi
if test "$SSE_ENABLED" = "yes"; then
AC_DEFINE(USE_SSE, 1, [x86 Streaming SIMD Extensions will be used])
fi
if test "$NEON_ENABLED" = "yes"; then
AC_DEFINE(USE_NEON, 1, [ARM NEON SIMD Extensions will be used])
fi
# Generate files
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

139
template/calfbox/delay.c

@ -1,139 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "config-api.h"
#include "dspmath.h"
#include "module.h"
#include <glib.h>
#include <malloc.h>
#include <math.h>
#include <memory.h>
#include <sndfile.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_DELAY_LENGTH 65536
struct delay_params
{
float time;
float wet_dry, fb_amt;
};
struct delay_module
{
struct cbox_module module;
float storage[MAX_DELAY_LENGTH][2];
struct delay_params *params;
int pos;
};
#define MODULE_PARAMS delay_params
MODULE_PROCESSCMD_FUNCTION(delay)
{
struct delay_module *m = (struct delay_module *)ct->user_data;
EFFECT_PARAM("/time", "f", time, double, , 1, 1000) else
EFFECT_PARAM("/fb_amt", "f", fb_amt, double, , 0, 1) else
EFFECT_PARAM("/wet_dry", "f", wet_dry, double, , 0, 1) else
if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
return cbox_execute_on(fb, NULL, "/time", "f", error, m->params->time)
&& cbox_execute_on(fb, NULL, "/fb_amt", "f", error, m->params->fb_amt)
&& cbox_execute_on(fb, NULL, "/wet_dry", "f", error, m->params->wet_dry)
&& CBOX_OBJECT_DEFAULT_STATUS(&m->module, fb, error)
;
}
else
return cbox_object_default_process_cmd(ct, fb, cmd, error);
return TRUE;
}
void delay_process_event(struct cbox_module *module, const uint8_t *data, uint32_t len)
{
// struct delay_module *m = (struct delay_module *)module;
}
void delay_process_block(struct cbox_module *module, cbox_sample_t **inputs, cbox_sample_t **outputs)
{
struct delay_module *m = (struct delay_module *)module;
int pos = m->pos;
int dv = m->params->time * m->module.srate / 1000.0;
float dryamt = 1 - m->params->wet_dry;
float wetamt = m->params->wet_dry;
float fbamt = m->params->fb_amt;
for (int i = 0; i < CBOX_BLOCK_SIZE; i++)
{
float dry[2] = { inputs[0][i], inputs[1][i] };
float *delayed = &m->storage[pos & (MAX_DELAY_LENGTH - 1)][0];
float wet[2] = { dryamt * dry[0] + wetamt * delayed[0], dryamt * dry[1] + wetamt * delayed[1] };
float fb[2] = { dry[0] + fbamt * delayed[0], dry[1] + fbamt * delayed[1] };
outputs[0][i] = sanef(wet[0]);
outputs[1][i] = sanef(wet[1]);
float *wcell = &m->storage[(pos + dv) & (MAX_DELAY_LENGTH - 1)][0];
wcell[0] = sanef(fb[0]);
wcell[1] = sanef(fb[1]);
pos++;
}
m->pos = pos;
}
MODULE_SIMPLE_DESTROY_FUNCTION(delay)
MODULE_CREATE_FUNCTION(delay)
{
static int inited = 0;
int i;
if (!inited)
{
inited = 1;
}
struct delay_module *m = malloc(sizeof(struct delay_module));
CALL_MODULE_INIT(m, 2, 2, delay);
struct delay_params *p = malloc(sizeof(struct delay_params));
m->params = p;
m->module.process_event = delay_process_event;
m->module.process_block = delay_process_block;
m->pos = 0;
p->time = cbox_config_get_float(cfg_section, "delay", 250);
p->wet_dry = cbox_config_get_float(cfg_section, "wet_dry", 0.3);
p->fb_amt = cbox_config_get_gain_db(cfg_section, "feedback_gain", -12.f);
for (i = 0; i < MAX_DELAY_LENGTH; i++)
m->storage[i][0] = m->storage[i][1] = 0.f;
return &m->module;
}
struct cbox_module_keyrange_metadata delay_keyranges[] = {
};
struct cbox_module_livecontroller_metadata delay_controllers[] = {
};
DEFINE_MODULE(delay, 2, 2)

138
template/calfbox/distortion.c

@ -1,138 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "config-api.h"
#include "dspmath.h"
#include "module.h"
#include <glib.h>
#include <malloc.h>
#include <math.h>
#include <memory.h>
#include <sndfile.h>
#include <stdio.h>
#include <stdlib.h>
#define MODULE_PARAMS distortion_params
struct distortion_params
{
float drive;
float shape;
};
struct distortion_module
{
struct cbox_module module;
struct distortion_params *params, *old_params;
};
gboolean distortion_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
struct distortion_module *m = (struct distortion_module *)ct->user_data;
EFFECT_PARAM("/drive", "f", drive, double, dB2gain_simple, -36, 36) else
EFFECT_PARAM("/shape", "f", shape, double, , -1, 2) else
if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
return cbox_execute_on(fb, NULL, "/drive", "f", error, gain2dB_simple(m->params->drive))
&& cbox_execute_on(fb, NULL, "/shape", "f", error, m->params->shape)
&& CBOX_OBJECT_DEFAULT_STATUS(&m->module, fb, error)
;
}
else
return cbox_object_default_process_cmd(ct, fb, cmd, error);
return TRUE;
}
void distortion_process_event(struct cbox_module *module, const uint8_t *data, uint32_t len)
{
// struct distortion_module *m = module->user_data;
}
void distortion_process_block(struct cbox_module *module, cbox_sample_t **inputs, cbox_sample_t **outputs)
{
struct distortion_module *m = module->user_data;
if (m->params != m->old_params)
{
// update calculated values
}
float drive = m->params->drive;
float shape = m->params->shape;
float a0 = shape;
float a1 = -2 * shape - 0.5;
float a2 = 1.5 + shape;
float post = pow(drive, -0.7);
for (int i = 0; i < CBOX_BLOCK_SIZE; i++)
{
for (int c = 0; c < 2; c++)
{
float val = inputs[c][i];
val *= drive;
if (fabs(val) > 1.0)
val = (val > 0) ? 1 : -1;
else
val = a0 * val * val * val * val * val + a1 * val * val * val + a2 * val;
outputs[c][i] = val * post;
}
}
}
MODULE_SIMPLE_DESTROY_FUNCTION(distortion)
MODULE_CREATE_FUNCTION(distortion)
{
static int inited = 0;
if (!inited)
{
inited = 1;
}
struct distortion_module *m = malloc(sizeof(struct distortion_module));
CALL_MODULE_INIT(m, 2, 2, distortion);
m->module.process_event = distortion_process_event;
m->module.process_block = distortion_process_block;
struct distortion_params *p = malloc(sizeof(struct distortion_params));
p->drive = cbox_config_get_gain_db(cfg_section, "drive", 0.f);
p->shape = cbox_config_get_gain_db(cfg_section, "shape", 0.f);
m->params = p;
m->old_params = NULL;
return &m->module;
}
struct cbox_module_keyrange_metadata distortion_keyranges[] = {
};
struct cbox_module_livecontroller_metadata distortion_controllers[] = {
};
DEFINE_MODULE(distortion, 2, 2)

372
template/calfbox/dom.c

@ -1,372 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2012 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "cmd.h"
#include "errors.h"
#include "dom.h"
#include <assert.h>
#include <glib.h>
#include <malloc.h>
#include <string.h>
static GHashTable *class_name_hash = NULL;
struct cbox_class_per_document
{
GList *instances;
};
struct cbox_document
{
GHashTable *classes_per_document;
GHashTable *services_per_document;
GHashTable *uuids_per_document;
struct cbox_command_target cmd_target;
int item_ctr;
uint64_t generation_ctr;
};
////////////////////////////////////////////////////////////////////////////////////////
void cbox_dom_init()
{
class_name_hash = g_hash_table_new(g_str_hash, g_str_equal);
}
void cbox_dom_close()
{
g_hash_table_destroy(class_name_hash);
}
////////////////////////////////////////////////////////////////////////////////////////
struct cbox_class *cbox_class_find_by_name(const char *name)
{
assert(class_name_hash != NULL);
return g_hash_table_lookup(class_name_hash, name);
}
void cbox_class_register(struct cbox_class *class_ptr)
{
assert(class_name_hash != NULL);
g_hash_table_insert(class_name_hash, (gpointer)class_ptr->name, class_ptr);
}
static struct cbox_class_per_document *get_cpd_for_class(struct cbox_document *doc, struct cbox_class *class_ptr)
{
struct cbox_class_per_document *p = g_hash_table_lookup(doc->classes_per_document, class_ptr);
if (p != NULL)
return p;
p = malloc(sizeof(struct cbox_class_per_document));
p->instances = NULL;
g_hash_table_insert(doc->classes_per_document, class_ptr, p);
return p;
}
////////////////////////////////////////////////////////////////////////////////////////
void cbox_uuid_clear(struct cbox_uuid *uuid)
{
uuid_clear(uuid->uuid);
}
guint cbox_uuid_hash(gconstpointer v)
{
char buf[40];
uuid_unparse_lower(((struct cbox_uuid *)v)->uuid, buf);
return g_str_hash(buf);
}
gboolean cbox_uuid_equal(gconstpointer v1, gconstpointer v2)
{
const struct cbox_uuid *p1 = v1;
const struct cbox_uuid *p2 = v2;
return !uuid_compare(p1->uuid, p2->uuid);
}
void cbox_uuid_copy(struct cbox_uuid *vto, const struct cbox_uuid *vfrom)
{
uuid_copy(vto->uuid, vfrom->uuid);
}
gboolean cbox_uuid_report_as(struct cbox_uuid *uuid, const char *cmd, struct cbox_command_target *fb, GError **error)
{
if (!fb)
return TRUE;
return cbox_execute_on(fb, NULL, cmd, "u", error, uuid->uuid);
}
gboolean cbox_uuid_report(struct cbox_uuid *uuid, struct cbox_command_target *fb, GError **error)
{
return cbox_uuid_report_as(uuid, "/uuid", fb, error);
}
gboolean cbox_uuid_fromstring(struct cbox_uuid *uuid, const char *str, GError **error)
{
if (uuid_parse(str, uuid->uuid))
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Malformed UUID: '%s'", str);
return FALSE;
}
return TRUE;
}
void cbox_uuid_tostring(struct cbox_uuid *uuid, char str[40])
{
uuid_unparse(uuid->uuid, str);
}
void cbox_uuid_generate(struct cbox_uuid *uuid)
{
uuid_generate(uuid->uuid);
}
////////////////////////////////////////////////////////////////////////////////////////
void cbox_object_register_instance(struct cbox_document *doc, struct cbox_objhdr *obj)
{
assert(obj != NULL);
struct cbox_class_per_document *cpd = get_cpd_for_class(doc, obj->class_ptr);
cpd->instances = g_list_prepend(cpd->instances, obj);
obj->owner = doc;
obj->link_in_document = cpd->instances;
g_hash_table_insert(obj->owner->uuids_per_document, &obj->instance_uuid, obj);
}
struct cbox_command_target *cbox_object_get_cmd_target(struct cbox_objhdr *hdr_ptr)
{
if (!hdr_ptr->class_ptr->getcmdtargetfunc)
return NULL;
return hdr_ptr->class_ptr->getcmdtargetfunc(hdr_ptr);
}
gboolean cbox_object_try_default_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, const char *subcmd, gboolean *result, GError **error)
{
// XXXKF this assumes objhdr ptr == object ptr - needs to add the header offset in cmd target?
struct cbox_objhdr *obj = ct->user_data;
if (!strcmp(subcmd, "/status") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_object_default_status(obj, fb, error))
{
*result = FALSE;
return TRUE;
}
return FALSE;
}
if (!strcmp(subcmd, "/delete") && !strcmp(cmd->arg_types, ""))
{
cbox_object_destroy(obj);
*result = TRUE;
return TRUE;
}
if (!strcmp(subcmd, "/get_uuid") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
{
*result = FALSE;
return TRUE;
}
*result = cbox_uuid_report(&obj->instance_uuid, fb, error);
return TRUE;
}
if (!strcmp(subcmd, "/get_class_name") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
{
*result = FALSE;
return TRUE;
}
*result = cbox_execute_on(fb, NULL, "/class_name", "s", error, obj->class_ptr->name);
return TRUE;
}
return FALSE;
}
gboolean cbox_object_default_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
gboolean result = FALSE;
if (cbox_object_try_default_process_cmd(ct, fb, cmd, cmd->command, &result, error))
return result;
struct cbox_objhdr *obj = ct->user_data;
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Unknown combination of target path and argument: '%s', '%s' for object class '%s'", cmd->command, cmd->arg_types, obj->class_ptr->name);
return FALSE;
}
gboolean cbox_object_default_status(struct cbox_objhdr *objhdr, struct cbox_command_target *fb, GError **error)
{
char buf[40];
uuid_unparse(objhdr->instance_uuid.uuid, buf);
return cbox_execute_on(fb, NULL, "/uuid", "s", error, buf);
}
void cbox_object_destroy(struct cbox_objhdr *hdr_ptr)
{
struct cbox_class_per_document *cpd = get_cpd_for_class(hdr_ptr->owner, hdr_ptr->class_ptr);
cpd->instances = g_list_delete_link(cpd->instances, hdr_ptr->link_in_document);
hdr_ptr->link_in_document = NULL;
g_hash_table_remove(hdr_ptr->owner->uuids_per_document, &hdr_ptr->instance_uuid);
hdr_ptr->class_ptr->destroyfunc(hdr_ptr);
}
////////////////////////////////////////////////////////////////////////////////////////
static gboolean document_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
char *uuid;
const char *subcommand;
if (!strcmp(cmd->command, "/dump") && !strcmp(cmd->arg_types, ""))
{
struct cbox_document *doc = ct->user_data;
cbox_document_dump(doc);
return TRUE;
}
if (cbox_parse_path_part_str(cmd, "/uuid/", &subcommand, &uuid, error))
{
struct cbox_document *doc = ct->user_data;
if (!subcommand)
return FALSE;
struct cbox_objhdr *obj = cbox_document_get_object_by_text_uuid(doc, uuid, NULL, error);
g_free(uuid);
if (!obj)
return FALSE;
struct cbox_command_target *ct2 = cbox_object_get_cmd_target(obj);
return cbox_execute_sub(ct2, fb, cmd, subcommand, error);
}
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Unknown combination of target path and argument: '%s', '%s'", cmd->command, cmd->arg_types);
return FALSE;
}
struct cbox_document *cbox_document_new()
{
struct cbox_document *res = malloc(sizeof(struct cbox_document));
res->classes_per_document = g_hash_table_new_full(NULL, NULL, NULL, g_free);
res->services_per_document = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
res->uuids_per_document = g_hash_table_new(cbox_uuid_hash, cbox_uuid_equal);
res->cmd_target.process_cmd = document_process_cmd;
res->cmd_target.user_data = res;
res->item_ctr = 0;
res->generation_ctr = 1000; // start with non-zero value just to spot invalid values more easily
return res;
}
struct cbox_command_target *cbox_document_get_cmd_target(struct cbox_document *doc)
{
return &doc->cmd_target;
}
struct cbox_objhdr *cbox_document_get_service(struct cbox_document *document, const char *name)
{
return g_hash_table_lookup(document->services_per_document, name);
}
void cbox_document_set_service(struct cbox_document *document, const char *name, struct cbox_objhdr *obj)
{
g_hash_table_insert(document->services_per_document, g_strdup(name), obj);
}
struct cbox_objhdr *cbox_document_get_object_by_uuid(struct cbox_document *doc, const struct cbox_uuid *uuid)
{
return g_hash_table_lookup(doc->uuids_per_document, uuid);
}
struct cbox_objhdr *cbox_document_get_object_by_text_uuid(struct cbox_document *doc, const char *uuid, const struct cbox_class *class_ptr, GError **error)
{
struct cbox_uuid uuidv;
if (!cbox_uuid_fromstring(&uuidv, uuid, error))
return NULL;
struct cbox_objhdr *obj = cbox_document_get_object_by_uuid(doc, &uuidv);
if (!obj)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "UUID not found: '%s'", uuid);
return NULL;
}
if (class_ptr && !cbox_class_is_a(obj->class_ptr, class_ptr))
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Unexpected object type '%s' for UUID '%s' (expected '%s')", obj->class_ptr->name, uuid, class_ptr->name);
return NULL;
}
return obj;
}
static void iter_func(gpointer key, gpointer value, gpointer doc_)
{
#ifndef NDEBUG
struct cbox_document *doc = (struct cbox_document *)doc_;
#endif
struct cbox_class *class_ptr = key;
struct cbox_class_per_document *cpd = value;
int first = 1;
printf("Class %s: ", class_ptr->name);
GList *l = cpd->instances;
while(l) {
if (!first)
printf(", ");
printf("%p", l->data);
fflush(stdout);
struct cbox_objhdr *hdr = (struct cbox_objhdr *)l->data;
char buf[40];
uuid_unparse(hdr->instance_uuid.uuid, buf);
printf("[%s]", buf);
fflush(stdout);
assert(cbox_document_get_object_by_uuid(doc, &hdr->instance_uuid));
l = l->next;
first = 0;
}
if (first)
printf("<no instances>");
printf("\n");
}
static void iter_func2(gpointer key, gpointer value, gpointer document)
{
struct cbox_objhdr *oh = value;
char buf[40];
uuid_unparse(oh->instance_uuid.uuid, buf);
printf("Service %s: %p", (const char *)key, value);
fflush(stdout);
printf("[%s]", buf);
fflush(stdout);
printf(" (%s)\n", oh->class_ptr->name);
}
void cbox_document_dump(struct cbox_document *document)
{
g_hash_table_foreach(document->classes_per_document, iter_func, document);
g_hash_table_foreach(document->services_per_document, iter_func2, document);
}
uint64_t cbox_document_get_next_stamp(struct cbox_document *document)
{
return document->generation_ctr;
}
void cbox_document_destroy(struct cbox_document *document)
{
g_hash_table_destroy(document->classes_per_document);
g_hash_table_destroy(document->services_per_document);
g_hash_table_destroy(document->uuids_per_document);
free(document);
}

155
template/calfbox/dom.h

@ -1,155 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2012 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_DOM_H
#define CBOX_DOM_H
#include <glib.h>
#include <stdint.h>
#include <uuid/uuid.h>
struct cbox_command_target;
struct cbox_osc_command;
struct cbox_objhdr;
struct cbox_document;
struct GList;
struct cbox_uuid
{
uuid_t uuid;
};
extern void cbox_uuid_clear(struct cbox_uuid *uuid);
extern guint cbox_uuid_hash(gconstpointer v);
extern void cbox_uuid_copy(struct cbox_uuid *vto, const struct cbox_uuid *vfrom);
extern gboolean cbox_uuid_equal(gconstpointer v1, gconstpointer v2);
extern gboolean cbox_uuid_report(struct cbox_uuid *uuid, struct cbox_command_target *fb, GError **error);
extern gboolean cbox_uuid_report_as(struct cbox_uuid *uuid, const char *cmd, struct cbox_command_target *fb, GError **error);
extern gboolean cbox_uuid_fromstring(struct cbox_uuid *uuid, const char *str, GError **error);
extern void cbox_uuid_tostring(struct cbox_uuid *uuid, char str[40]);
extern void cbox_uuid_generate(struct cbox_uuid *uuid);
struct cbox_class
{
struct cbox_class *parent;
const char *name;
int hdr_offset;
void (*destroyfunc)(struct cbox_objhdr *objhdr);
struct cbox_command_target *(*getcmdtargetfunc)(struct cbox_objhdr *objhdr);
};
extern struct cbox_class *cbox_class_find_by_name(const char *name);
extern void cbox_class_register(struct cbox_class *class_ptr);
struct cbox_objhdr
{
struct cbox_class *class_ptr;
struct cbox_document *owner;
void *link_in_document;
struct cbox_uuid instance_uuid;
uint64_t stamp;
};
static inline int cbox_class_is_a(const struct cbox_class *c1, const struct cbox_class *c2)
{
while(c1 != c2 && c1->parent)
c1 = c1->parent;
return c1 == c2;
}
extern void cbox_object_register_instance(struct cbox_document *doc, struct cbox_objhdr *obj);
extern struct cbox_command_target *cbox_object_get_cmd_target(struct cbox_objhdr *hdr_ptr);
extern gboolean cbox_object_try_default_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, const char *subcmd, gboolean *result, GError **error);
extern gboolean cbox_object_default_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error);
extern gboolean cbox_object_default_status(struct cbox_objhdr *objhdr, struct cbox_command_target *fb, GError **error);
extern void cbox_object_destroy(struct cbox_objhdr *hdr_ptr);
extern struct cbox_document *cbox_document_new(void);
extern void cbox_document_dump(struct cbox_document *);
extern struct cbox_command_target *cbox_document_get_cmd_target(struct cbox_document *);
extern struct cbox_objhdr *cbox_document_get_service(struct cbox_document *doc, const char *name);
extern void cbox_document_set_service(struct cbox_document *doc, const char *name, struct cbox_objhdr *hdr_ptr);
extern struct cbox_objhdr *cbox_document_get_object_by_uuid(struct cbox_document *doc, const struct cbox_uuid *uuid);
extern struct cbox_objhdr *cbox_document_get_object_by_text_uuid(struct cbox_document *doc, const char *uuid, const struct cbox_class *class_ptr, GError **error);
extern uint64_t cbox_document_get_next_stamp(struct cbox_document *doc);
extern void cbox_document_destroy(struct cbox_document *);
extern void cbox_dom_init(void);
extern void cbox_dom_close(void);
// must be the first field in the object-compatible struct
#define CBOX_OBJECT_HEADER() \
struct cbox_objhdr _obj_hdr;
#define CBOX_CLASS(class) CBOX_CLASS_##class
#define CBOX_EXTERN_CLASS(class) \
extern struct cbox_class CBOX_CLASS(class);
#define CBOX_GET_DOCUMENT(obj) \
((obj)->_obj_hdr.owner)
#define CBOX_STAMP(obj) \
((obj)->_obj_hdr.stamp = cbox_document_get_next_stamp(CBOX_GET_DOCUMENT(obj)))
#define CBOX_DELETE(obj) \
((obj) && (cbox_object_destroy(&(obj)->_obj_hdr), 1))
#define CBOX_IS_A(obj, class) \
((obj) && cbox_class_is_a((obj)->_obj_hdr.class_ptr, &CBOX_CLASS(class)))
#define CBOX_OBJECT_HEADER_INIT(self, class, document) \
do { \
(self)->_obj_hdr.class_ptr = &CBOX_CLASS_##class; \
(self)->_obj_hdr.owner = (document); \
(self)->_obj_hdr.link_in_document = NULL; \
(self)->_obj_hdr.stamp = cbox_document_get_next_stamp(document); \
uuid_generate((self)->_obj_hdr.instance_uuid.uuid); \
} while(0)
#define CBOX_OBJECT_REGISTER(self) \
(cbox_object_register_instance((self)->_obj_hdr.owner, &(self)->_obj_hdr))
#define CBOX_OBJECT_DEFAULT_STATUS(self, fb, error) \
(cbox_object_default_status(&(self)->_obj_hdr, (fb), (error)))
#define CBOX_CLASS_DEFINITION_ROOT(class) \
static void class##_destroyfunc(struct cbox_objhdr *hdr_ptr); \
static struct cbox_command_target *class##_getcmdtarget(struct cbox_objhdr *hdr) { \
return &(((struct class *)hdr)->cmd_target);\
}; \
struct cbox_class CBOX_CLASS_##class = { \
.parent = NULL, \
.name = #class, \
.hdr_offset = offsetof(struct class, _obj_hdr), \
.destroyfunc = class##_destroyfunc, \
.getcmdtargetfunc = class##_getcmdtarget \
}; \
#define CBOX_RETURN_OBJECT(result) \
return &(result)->_obj_hdr
// Convert header to object, regardless of the relative position of the header.
#define CBOX_H2O(hdr) \
(void *)(((char *)(hdr)) - (hdr)->class_ptr->hdr_offset)
#define CBOX_O2H(obj) \
(&(*(obj))._obj_hdr)
#endif

0
template/calfbox/py/drum_pattern_editor.py → template/calfbox/drum_pattern_editor.py

0
template/calfbox/py/drumkit_editor.py → template/calfbox/drumkit_editor.py

152
template/calfbox/drvjunk/miditest.py

@ -1,152 +0,0 @@
import array
import binascii
import usb.core
import usb.util
import time
class USBMIDIConfiguration:
def __init__(self, cfg, ifno, ifalt):
self.cfg = cfg
self.ifno = ifno
self.ifalt = ifalt
def __str__(self):
return "cfg=%d ifno=%d ifalt=%d" % (self.cfg, self.ifno, self.ifalt)
def __repr__(self):
return "USBMIDIConfiguration(%d,%d,%d)" % (self.cfg, self.ifno, self.ifalt)
class USBMIDIDeviceDescriptor:
def __init__(self, vendorID, productID, interfaces = None):
self.vendorID = vendorID
self.productID = productID
if interfaces is None:
self.interfaces = []
else:
self.interfaces = interfaces
def add_interface(self, config, ifno, ifalt):
self.interfaces.append(USBMIDIConfiguration(config, ifno, ifalt))
def has_interfaces(self):
return len(self.interfaces)
def __str__(self):
return "vid=%04x pid=%04x" % (self.vendorID, self.productID)
def __repr__(self):
return "USBMIDIDeviceDescriptor(0x%04x, 0x%04x, %s)" % (self.vendorID, self.productID, self.interfaces)
class USBMIDI:
cin_sizes = [None, None, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1]
def __init__(self, mididev, midicfg, debug = False):
dev = usb.core.find(idVendor = mididev.vendorID, idProduct = mididev.productID)
self.dev = dev
intf = None
for cfgo in dev:
if cfgo.bConfigurationValue == midicfg.cfg:
cfgo.set()
intf = cfgo[(midicfg.ifno, midicfg.ifalt)]
if not intf:
raise ValueError, "Configuration %d not found" % midicfg.cfg
print intf.bNumEndpoints
self.epIn = None
self.epOut = None
for ep in intf:
if debug:
print "endpoint %x" % ep.bEndpointAddress
if ep.bEndpointAddress > 0x80:
if self.epIn is None:
self.epIn = ep
else:
if self.epOut is None:
self.epOut = ep
def read(self):
try:
data = self.epIn.read(self.epIn.wMaxPacketSize)
if data is None:
return None
return array.array('B', data)
except usb.core.USBError, e:
return None
def encode(self, port, msg):
a = array.array('B')
a.append(16 * port + (msg[0] >> 4))
a.fromlist(msg)
return a
def write(self, data):
self.epOut.write(data)
def parse(self, data):
i = 0
msgs = []
while i < len(data):
if data[i] == 0:
break
cin, cable_id = data[i] & 15, data[i] >> 4
msgs.append(data[i + 1 : i + 1 + KeyRig25.cin_sizes[cin]])
i += 4
return msgs
@staticmethod
def findall(vendorID = None, productID = None, debug = False):
dev_list = []
devices = usb.core.find(find_all = True)
for dev in devices:
if vendorID is not None and dev.idVendor != vendorID:
continue
if productID is not None and dev.idProduct != productID:
continue
thisdev = USBMIDIDeviceDescriptor(dev.idVendor, dev.idProduct)
if debug:
print "Device %04x:%04x, class %d" % (dev.idVendor, dev.idProduct, dev.bDeviceClass)
if dev.bDeviceClass == 0: # device defined at interface level
for cfg in dev:
if debug:
print "Configuration ", cfg.bConfigurationValue
for intf in cfg:
if debug:
print "Interface %d alternate-setting %d" % (intf.bInterfaceNumber, intf.bAlternateSetting)
print "Class %d subclass %d" % (intf.bInterfaceClass, intf.bInterfaceSubClass)
if intf.bInterfaceClass == 1 and intf.bInterfaceSubClass == 3:
if debug:
print "(%d,%d,%d): This is USB MIDI" % (cfg.bConfigurationValue, intf.bInterfaceNumber, intf.bAlternateSetting)
thisdev.add_interface(cfg.bConfigurationValue, intf.bInterfaceNumber, intf.bAlternateSetting)
if thisdev.has_interfaces():
dev_list.append(thisdev)
return dev_list
#print devices
class KnownUSBMIDI(USBMIDI):
def __init__(self, vendorID, productID):
devlist = USBMIDI.findall(vendorID, productID, debug = False)
if not devlist:
raise ValueError
USBMIDI.__init__(self, devlist[0], devlist[0].interfaces[0])
class KeyRig25(KnownUSBMIDI):
def __init__(self):
KnownUSBMIDI.__init__(self, vendorID = 0x763, productID = 0x115)
class XMidi2x2(KnownUSBMIDI):
def __init__(self):
KnownUSBMIDI.__init__(self, vendorID = 0x41e, productID = 0x3f08)
class LexiconOmega(KnownUSBMIDI):
def __init__(self):
KnownUSBMIDI.__init__(self, vendorID = 0x1210, productID = 2)
print USBMIDI.findall()
xmidi = XMidi2x2()
xmidi.write(xmidi.encode(1, [0x90, 36, 100]))
xmidi.write(xmidi.encode(1, [0x80, 36, 100]))
#krig = KeyRig25()
krig = LexiconOmega()
while True:
data = krig.read()
if data is not None:
decoded = krig.parse(data)
reencoded = array.array('B')
for msg in decoded:
reencoded.extend(xmidi.encode(1, list(msg)))
xmidi.write(reencoded)
print decoded

255
template/calfbox/drvjunk/omega.c

@ -1,255 +0,0 @@
#include <libusb-1.0/libusb.h>
#include <assert.h>
#include <errno.h>
#include <math.h>
#include <malloc.h>
#include <memory.h>
#include <sched.h>
#include <stdio.h>
#include <unistd.h>
// interface 1 altsetting 1 endpoint 01 (out) bits 16 channels 2 mps 192
// interface 2 altsetting 1 endpoint 83 (in) bits 16 channels 2 mps 192
int samples_captured = 0;
int samples_played = 0;
static struct libusb_context *usbctx;
static int omega_timeout = 1000;
int epOUT = 0x01, epIN = 0x83;
void init_usb()
{
libusb_init(&usbctx);
libusb_set_debug(usbctx, 3);
}
struct libusb_device_handle *open_omega()
{
struct libusb_device_handle *handle;
handle = libusb_open_device_with_vid_pid(usbctx, 0x1210, 0x0002);
if (!handle)
{
printf("Lexicon Omega not found after reset.\n");
return NULL;
}
if (libusb_set_configuration(handle, 1))
{
libusb_close(handle);
return NULL;
}
if (libusb_claim_interface(handle, 1))
goto error;
if (libusb_claim_interface(handle, 2))
goto error;
if (libusb_claim_interface(handle, 7))
goto error;
if (libusb_set_interface_alt_setting(handle, 1, 1))
goto error;
if (libusb_set_interface_alt_setting(handle, 2, 1))
goto error;
return handle;
error:
libusb_close(handle);
return NULL;
}
#define EP_CONTROL_UNDEFINED 0
#define SAMPLING_FREQ_CONTROL 1
#define PITCH_CONTROL 2
#define SET_CUR 0x01
#define GET_CUR 0x81
#define SET_MIN 0x02
#define GET_MIN 0x82
#define SET_MAX 0x03
#define GET_MAX 0x83
#define SET_RES 0x04
#define GET_RES 0x84
#define SET_MEM 0x05
#define GET_MEM 0x85
#define GET_STAT 0xFF
int configure_omega(struct libusb_device_handle *h, int sample_rate)
{
uint8_t freq_data[3];
freq_data[0] = sample_rate & 0xFF;
freq_data[1] = (sample_rate & 0xFF00) >> 8;
freq_data[2] = (sample_rate & 0xFF0000) >> 16;
if (libusb_control_transfer(h, 0x22, 0x01, 256, epOUT, freq_data, 3, omega_timeout) != 3)
return -1;
if (libusb_control_transfer(h, 0x22, 0x01, 256, epIN, freq_data, 3, omega_timeout) != 3)
return -1;
// libusb_control_transfer(dev, 0x22, 0x01,
return 0;
}
// 192 bytes = 1ms@48000 (48 samples)
#define NUM_PLAY_BUFS 2
#define PLAY_PACKET_COUNT 2
#define PLAY_PACKET_SIZE 192
static float phase = 0;
static int phase2 = 0;
static int desync = 0;
static int samples_sent = 0;
static int srate = 48000;
void play_callback(struct libusb_transfer *transfer)
{
int i;
//printf("Play Callback! %d %p status %d\n", (int)transfer->length, transfer->buffer, (int)transfer->status);
samples_played += transfer->length / 4;
int nsamps = srate / 1000;
if (desync >= 1000 * transfer->num_iso_packets && nsamps < PLAY_PACKET_SIZE/4)
nsamps++;
// printf("desync = %d nsamps = %d!\n", desync, nsamps);
int tlen = 0;
for (i = 0; i < transfer->num_iso_packets; i++)
{
tlen += transfer->iso_packet_desc[i].actual_length;
if (transfer->iso_packet_desc[i].status)
printf("ISO error: index = %d i = %d status = %d\n", (int)transfer->user_data, i, transfer->iso_packet_desc[i].status);
}
// printf("actual length = %d!\n", tlen);
transfer->length = nsamps * transfer->num_iso_packets * 4;
libusb_set_iso_packet_lengths(transfer, nsamps * 4);
desync += transfer->num_iso_packets * srate;
desync -= tlen / 4 * 1000;
int16_t *data = (int16_t*)transfer->buffer;
for (i = 0; i < transfer->length / 4; i ++)
{
float v = 16000 * sin(phase);
//phase += (phase2 & 4096) ? 0.02 : 0.04;
phase += (phase2 & 16384) ? 0.04: 0.02;
//phase += 0.2 * cos(phase2 / 16384.0);
phase2++;
if (phase > 2 * M_PI)
phase -= 2 * M_PI;
int vi = (int)v;
data[i * 2] = vi;
data[i * 2 + 1] = vi;
}
libusb_submit_transfer(transfer);
}
void play_stuff(struct libusb_device_handle *h, int index)
{
struct libusb_transfer *t;
int i;
int packets = PLAY_PACKET_COUNT;
t = libusb_alloc_transfer(packets);
int tsize = srate * 4 / 1000;
uint8_t *buf = (uint8_t *)malloc(PLAY_PACKET_SIZE*packets);
//int ssf = 0;
for (i = 0; i < tsize * packets; i++)
buf[i] = 0;
libusb_fill_iso_transfer(t, h, epOUT, buf, tsize * packets, packets, play_callback, (void *)index, 20000);
libusb_set_iso_packet_lengths(t, tsize);
libusb_submit_transfer(t);
}
#define NUM_RECORD_BUFS 2
#define NUM_REC_PACKETS 2
#define REC_PACKET_SIZE 192
static uint8_t *record_buffers[NUM_RECORD_BUFS];
// struct libusb_transfer *record_transfers[NUM_RECORD_BUFS];
float filt = 0;
void record_callback(struct libusb_transfer *transfer)
{
int i;
// printf("Record callback! %p index %d len %d\n", transfer, (int)transfer->user_data, transfer->length);
samples_captured += transfer->length / 4;
float avg = 0;
int16_t *bufz = (int16_t*)transfer->buffer;
int items = transfer->length / 4;
for (i = 0; i < items; i ++)
{
int16_t *buf = &bufz[i * 2];
if (fabs(buf[0]) > avg)
avg = fabs(buf[0]);
if (fabs(buf[1]) > avg)
avg = fabs(buf[1]);
}
if (avg)
printf("%12.6f dBFS\r", 6 * log(avg / 32767 / items) / log(2.0));
libusb_submit_transfer(transfer);
}
void record_stuff(struct libusb_device_handle *h, int index)
{
// 0x02
struct libusb_transfer *t;
record_buffers[index] = (uint8_t*)malloc(NUM_REC_PACKETS * REC_PACKET_SIZE);
memset(record_buffers[index], 0, NUM_REC_PACKETS * REC_PACKET_SIZE);
t = libusb_alloc_transfer(NUM_REC_PACKETS);
libusb_fill_iso_transfer(t, h, epIN, record_buffers[index], NUM_REC_PACKETS * REC_PACKET_SIZE, NUM_REC_PACKETS, record_callback, (void *)index, 1000);
libusb_set_iso_packet_lengths(t, REC_PACKET_SIZE);
if (libusb_submit_transfer(t))
goto error;
return;
error:
printf("Record setup failed for index=%d\n", index);
}
void usb_main_loop()
{
struct sched_param p;
p.sched_priority = 10;
sched_setscheduler(0, SCHED_FIFO, &p);
while(1) {
struct timeval tv = {
.tv_sec = 0,
.tv_usec = 100
};
libusb_handle_events_timeout(usbctx, &tv);
}
}
int main(int argc, char *argv[])
{
struct libusb_device_handle *h;
int i;
init_usb();
h = open_omega();
if (!h)
{
printf("Lexicon Omega could not be opened.\n");
return 2;
}
// 10: 4 3 3 - 16 bit
// 30: 2 2 1 2 2 2 1 - 24 bit
// 50: 4 3 3
// 70: 2 2 1 2 2 2 1
printf("Error = %d\n", configure_omega(h, srate));
usleep(1);
for (i = 0; i < NUM_PLAY_BUFS; i++)
play_stuff(h, i);
for (i = 0; i < NUM_RECORD_BUFS; i++)
record_stuff(h, i);
usb_main_loop();
return 0;
}

243
template/calfbox/dspmath.h

@ -1,243 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_DSPMATH_H
#define CBOX_DSPMATH_H
#define CBOX_BLOCK_SIZE 16
#include <complex.h>
#include <stdint.h>
#include <stdlib.h>
#include <math.h>
#include <memory.h>
#ifndef M_PI
#include <glib.h>
#define M_PI G_PI
#endif
typedef float cbox_sample_t;
struct cbox_sincos
{
float sine;
float cosine;
float prewarp;
float prewarp2;
};
static inline float hz2w(float hz, float sr)
{
return M_PI * hz / (2 * sr);
}
static inline float cerp_naive(float v0, float v1, float v2, float v3, float f)
{
float x0 = -1;
float x1 = 0;
float x2 = 1;
float x3 = 2;
float l0 = ((f - x1) * (f - x2) * (f - x3)) / ( (x0 - x1) * (x0 - x2) * (x0 - x3));
float l1 = ((f - x0) * (f - x2) * (f - x3)) / ((x1 - x0) * (x1 - x2) * (x1 - x3));
float l2 = ((f - x0) * (f - x1) * (f - x3)) / ((x2 - x0) * (x2 - x1) * (x2 - x3));
float l3 = ((f - x0) * (f - x1) * (f - x2)) / ((x3 - x0) * (x3 - x1) * (x3 - x2) );
return v0 * l0 + v1 * l1 + v2 * l2 + v3 * l3;
}
static inline float cerp(float v0, float v1, float v2, float v3, float f)
{
f += 1;
float d0 = (f - 0);
float d1 = (f - 1);
float d2 = (f - 2);
float d3 = (f - 3);
float d03 = (d0 * d3) * (1.0 / 2.0);
float d12 = (d03 + 1) * (1.0 / 3.0);
float l0 = -d12 * d3;
float l1 = d03 * d2;
float l2 = -d03 * d1;
float l3 = d12 * d0;
float y = v0 * l0 + v1 * l1 + v2 * l2 + v3 * l3;
// printf("%f\n", y - cerp_naive(v0, v1, v2, v3, f - 1));
return y;
}
static inline float sanef(float v)
{
if (fabs(v) < (1.0 / (65536.0 * 65536.0)))
return 0;
return v;
}
static inline void sanebf(float *buf)
{
for (int i = 0; i < CBOX_BLOCK_SIZE; ++i)
buf[i] = sanef(buf[i]);
}
static inline void copybf(float *to, float *from)
{
memcpy(to, from, sizeof(float) * CBOX_BLOCK_SIZE);
}
static inline void zerobf(float *to)
{
for (int i = 0; i < CBOX_BLOCK_SIZE; ++i)
to[i] = 0.f;
}
static inline float cent2factor(float cent)
{
return powf(2.0, cent * (1.f / 1200.f)); // I think this may be optimised using exp()
}
static inline float dB2gain(float dB)
{
return powf(2.f, dB * (1.f / 6.f));
}
static inline float dB2gain_simple(float dB)
{
if (dB <= -96)
return 0;
return powf(2.f, dB * (1.f / 6.f));
}
static inline float gain2dB_simple(float gain)
{
static const float sixoverlog2 = 8.656170245333781; // 6.0 / logf(2.f);
if (gain < (1.f / 65536.f))
return -96.f;
return sixoverlog2 * logf(gain);
}
static inline float deg2rad(float deg)
{
return deg * (float)(M_PI / 180.f);
}
static inline float rad2deg(float rad)
{
return rad * (float)(180.f / M_PI);
}
// Do a butterfly operation:
// dst1 = src1 + e^iw_1*src2
// dst2 = src1 + e^iw_2*src2 (w = phase * 2pi / ANALYSIS_BUFFER_SIZE)
static inline void butterfly(complex float *dst1, complex float *dst2, complex float src1, complex float src2, complex float eiw1, complex float eiw2)
{
*dst1 = src1 + eiw1 * src2;
*dst2 = src1 + eiw2 * src2;
}
struct cbox_gain
{
float db_gain;
float lin_gain;
float old_lin_gain;
float pos;
float delta;
};
static inline void cbox_gain_init(struct cbox_gain *gain)
{
gain->db_gain = 0;
gain->lin_gain = 1;
gain->old_lin_gain = 1;
gain->pos = 1;
gain->delta = 1 / (44100 * 0.1); // XXXKF ballpark
}
static inline void cbox_gain_set_db(struct cbox_gain *gain, float db)
{
if (gain->db_gain == db)
return;
gain->db_gain = db;
gain->old_lin_gain = gain->old_lin_gain + (gain->lin_gain - gain->old_lin_gain) * gain->pos;
gain->lin_gain = dB2gain(db);
gain->pos = 0;
}
#define CBOX_GAIN_APPLY_LOOP(gain, nsamples, code) \
{ \
double pos = (gain)->pos; \
double span = (gain)->lin_gain - (gain)->old_lin_gain; \
double start = (gain)->old_lin_gain; \
double step = (gain)->delta; \
if (pos >= 1) { \
double tgain = gain->lin_gain; \
for (uint32_t i = 0; i < (nsamples); ++i) { \
code(i, tgain) \
} \
} else { \
if (pos + (nsamples) * step < 1.0) { \
for (uint32_t i = 0; i < (nsamples); ++i) { \
double tgain = start + (pos + i * step) * span; \
code(i, tgain) \
} \
gain->pos += (nsamples) * step; \
} \
else { \
for (uint32_t i = 0; i < (nsamples); ++i) { \
code(i, (start + pos * span)) \
pos = (pos + step < 1.0 ? pos + step : 1.0); \
} \
gain->pos = 1.0; \
} \
} \
}
#define CBOX_GAIN_ADD_MONO(i, gain) \
dest1[i] += src1[i] * gain;
static inline void cbox_gain_add_mono(struct cbox_gain *gain, float *dest1, const float *src1, uint32_t nsamples)
{
CBOX_GAIN_APPLY_LOOP(gain, nsamples, CBOX_GAIN_ADD_MONO);
}
#define CBOX_GAIN_ADD_STEREO(i, gain) \
dest1[i] += src1[i] * gain, dest2[i] += src2[i] * gain;
static inline void cbox_gain_add_stereo(struct cbox_gain *gain, float *dest1, const float *src1, float *dest2, const float *src2, uint32_t nsamples)
{
CBOX_GAIN_APPLY_LOOP(gain, nsamples, CBOX_GAIN_ADD_STEREO);
}
#define CBOX_GAIN_COPY_MONO(i, gain) \
dest1[i] = src1[i] * gain;
static inline void cbox_gain_copy_mono(struct cbox_gain *gain, float *dest1, const float *src1, uint32_t nsamples)
{
CBOX_GAIN_APPLY_LOOP(gain, nsamples, CBOX_GAIN_COPY_MONO);
}
#define CBOX_GAIN_COPY_STEREO(i, gain) \
dest1[i] = src1[i] * gain, dest2[i] = src2[i] * gain;
static inline void cbox_gain_copy_stereo(struct cbox_gain *gain, float *dest1, const float *src1, float *dest2, const float *src2, uint32_t nsamples)
{
CBOX_GAIN_APPLY_LOOP(gain, nsamples, CBOX_GAIN_COPY_STEREO);
}
#endif

445
template/calfbox/engine.c

@ -1,445 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2013 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "blob.h"
#include "dom.h"
#include "engine.h"
#include "instr.h"
#include "io.h"
#include "layer.h"
#include "midi.h"
#include "mididest.h"
#include "module.h"
#include "rt.h"
#include "scene.h"
#include "seq.h"
#include "song.h"
#include "stm.h"
#include "track.h"
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
CBOX_CLASS_DEFINITION_ROOT(cbox_engine)
static gboolean cbox_engine_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error);
struct cbox_engine *cbox_engine_new(struct cbox_document *doc, struct cbox_rt *rt)
{
struct cbox_engine *engine = malloc(sizeof(struct cbox_engine));
CBOX_OBJECT_HEADER_INIT(engine, cbox_engine, doc);
engine->rt = rt;
engine->scenes = NULL;
engine->scene_count = 0;
engine->effect = NULL;
engine->master = cbox_master_new(engine);
engine->master->song = cbox_song_new(doc);
engine->spb = NULL;
engine->spb_lock = 0;
engine->spb_retry = 0;
if (rt)
cbox_io_env_copy(&engine->io_env, &rt->io_env);
else
{
engine->io_env.srate = 0; // must be overridden
engine->io_env.buffer_size = 256;
engine->io_env.input_count = 0;
engine->io_env.output_count = 2;
}
cbox_midi_buffer_init(&engine->midibuf_aux);
cbox_midi_buffer_init(&engine->midibuf_jack);
cbox_midi_buffer_init(&engine->midibuf_song);
engine->stmap = malloc(sizeof(struct cbox_song_time_mapper));
cbox_song_time_mapper_init(engine->stmap, engine);
cbox_midi_appsink_init(&engine->appsink, rt, &engine->stmap->tmap);
cbox_command_target_init(&engine->cmd_target, cbox_engine_process_cmd, engine);
CBOX_OBJECT_REGISTER(engine);
return engine;
}
struct cbox_objhdr *cbox_engine_newfunc(struct cbox_class *class_ptr, struct cbox_document *doc)
{
return NULL;
}
void cbox_engine_destroyfunc(struct cbox_objhdr *obj_ptr)
{
struct cbox_engine *engine = (struct cbox_engine *)obj_ptr;
while(engine->scene_count)
CBOX_DELETE(engine->scenes[0]);
if (engine->master->song)
{
CBOX_DELETE(engine->master->song);
engine->master->song = NULL;
}
cbox_master_destroy(engine->master);
engine->master = NULL;
free(engine->stmap);
engine->stmap = NULL;
free(engine);
}
static gboolean cbox_engine_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
struct cbox_engine *engine = ct->user_data;
if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
{
for (uint32_t i = 0; i < engine->scene_count; i++)
{
if (!cbox_execute_on(fb, NULL, "/scene", "o", error, engine->scenes[i]))
return FALSE;
}
return CBOX_OBJECT_DEFAULT_STATUS(engine, fb, error);
}
else if (!strcmp(cmd->command, "/render_stereo") && !strcmp(cmd->arg_types, "i"))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
if (engine->rt && engine->rt->io)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot use render function in real-time mode.");
return FALSE;
}
struct cbox_midi_buffer midibuf_song;
cbox_midi_buffer_init(&midibuf_song);
int nframes = CBOX_ARG_I(cmd, 0);
float *data = malloc(2 * nframes * sizeof(float));
float *data_i = malloc(2 * nframes * sizeof(float));
float *buffers[2] = { data, data + nframes };
for (int i = 0; i < nframes; i++)
{
buffers[0][i] = 0.f;
buffers[1][i] = 0.f;
}
cbox_engine_process(engine, NULL, nframes, buffers, 2);
for (int i = 0; i < nframes; i++)
{
data_i[i * 2] = buffers[0][i];
data_i[i * 2 + 1] = buffers[1][i];
}
free(data);
if (!cbox_execute_on(fb, NULL, "/data", "b", error, cbox_blob_new_acquire_data(data_i, nframes * 2 * sizeof(float))))
return FALSE;
return TRUE;
}
else if (!strncmp(cmd->command, "/master_effect/",15))
{
return cbox_module_slot_process_cmd(&engine->effect, fb, cmd, cmd->command + 14, CBOX_GET_DOCUMENT(engine), engine->rt, engine, error);
}
else if (!strcmp(cmd->command, "/new_scene") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
struct cbox_scene *s = cbox_scene_new(CBOX_GET_DOCUMENT(engine), engine);
return s ? cbox_execute_on(fb, NULL, "/uuid", "o", error, s) : FALSE;
}
else if (!strcmp(cmd->command, "/new_recorder") && !strcmp(cmd->arg_types, "s"))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
struct cbox_recorder *rec = cbox_recorder_new_stream(engine, engine->rt, CBOX_ARG_S(cmd, 0));
return rec ? cbox_execute_on(fb, NULL, "/uuid", "o", error, rec) : FALSE;
}
else
return cbox_object_default_process_cmd(ct, fb, cmd, error);
}
void cbox_engine_process(struct cbox_engine *engine, struct cbox_io *io, uint32_t nframes, float **output_buffers, uint32_t output_channels)
{
struct cbox_module *effect = engine->effect;
uint32_t i, j;
cbox_midi_buffer_clear(&engine->midibuf_aux);
cbox_midi_buffer_clear(&engine->midibuf_song);
if (io)
cbox_io_get_midi_data(io, &engine->midibuf_jack);
else
cbox_midi_buffer_clear(&engine->midibuf_jack);
// Copy MIDI input to the app-sink
cbox_midi_appsink_supply(&engine->appsink, &engine->midibuf_jack, io->free_running_frame_counter);
// Clear external track outputs
if (engine->spb)
cbox_song_playback_prepare_render(engine->spb);
if (engine->rt)
cbox_rt_handle_rt_commands(engine->rt);
// Combine various sources of events (song, non-RT thread, JACK input)
if (engine->spb)
{
engine->frame_start_song_pos = engine->spb->song_pos_samples;
cbox_song_playback_render(engine->spb, &engine->midibuf_song, nframes);
}
for (uint32_t i = 0; i < engine->scene_count; i++)
cbox_scene_render(engine->scenes[i], nframes, output_buffers, output_channels);
// Process "master" effect
if (effect)
{
for (i = 0; i < nframes; i += CBOX_BLOCK_SIZE)
{
cbox_sample_t left[CBOX_BLOCK_SIZE], right[CBOX_BLOCK_SIZE];
cbox_sample_t *in_bufs[2] = {output_buffers[0] + i, output_buffers[1] + i};
cbox_sample_t *out_bufs[2] = {left, right};
(*effect->process_block)(effect, in_bufs, out_bufs);
for (j = 0; j < CBOX_BLOCK_SIZE; j++)
{
output_buffers[0][i + j] = left[j];
output_buffers[1][i + j] = right[j];
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////////
void cbox_engine_add_scene(struct cbox_engine *engine, struct cbox_scene *scene)
{
assert(scene->engine == engine);
cbox_rt_array_insert(engine->rt, (void ***)&engine->scenes, &engine->scene_count, -1, scene);
}
void cbox_engine_remove_scene(struct cbox_engine *engine, struct cbox_scene *scene)
{
assert(scene->engine == engine);
cbox_rt_array_remove_by_value(engine->rt, (void ***)&engine->scenes, &engine->scene_count, scene);
}
////////////////////////////////////////////////////////////////////////////////////////
#define cbox_engine_set_song_playback_args(ARG) ARG(struct cbox_song_playback *, old_song) ARG(struct cbox_song_playback *, new_song) ARG(uint32_t, new_time_ppqn)
DEFINE_ASYNC_RT_FUNC(cbox_engine, engine, cbox_engine_set_song_playback)
{
// If there's no new song, silence all ongoing notes. Otherwise, copy the
// ongoing notes to the new playback structure so that the notes get released
// when playback is stopped (or possibly earlier).
if (engine->spb)
{
if (new_song)
cbox_song_playback_apply_old_state(new_song);
if (cbox_song_playback_active_notes_release(engine->spb, new_song, new_time_ppqn == (uint32_t)-1 ? old_song->song_pos_ppqn : new_time_ppqn, &engine->midibuf_aux) < 0)
{
RT_CALL_AGAIN_LATER();
return;
}
}
engine->spb = new_song;
engine->master->spb = new_song;
if (new_song)
{
if (new_time_ppqn == (uint32_t)-1)
{
int old_time_ppqn = old_song ? old_song->song_pos_ppqn : 0;
cbox_song_playback_seek_samples(engine->master->spb, old_song ? old_song->song_pos_samples : 0);
// If tempo change occurred anywhere before playback point, then
// sample-based position corresponds to a completely different location.
// So, if new sample-based position corresponds to different PPQN
// position, seek again using PPQN position.
if (old_song && abs(new_song->song_pos_ppqn - old_time_ppqn) > 1)
cbox_song_playback_seek_ppqn(engine->master->spb, old_time_ppqn, FALSE);
}
else
cbox_song_playback_seek_ppqn(engine->master->spb, new_time_ppqn, FALSE);
}
}
ASYNC_PREPARE_FUNC(cbox_engine, engine, cbox_engine_set_song_playback)
{
// If update is already in progress, reschedule another at the end of it
if (engine->spb_lock)
{
engine->spb_retry = 1;
return 1;
}
++engine->spb_lock;
args->old_song = engine->spb;
args->new_song = cbox_song_playback_new(engine->master->song, engine->master, engine, args->old_song);
return 0;
}
ASYNC_CLEANUP_FUNC(cbox_engine, engine, cbox_engine_set_song_playback)
{
--engine->spb_lock;
assert(!engine->spb_lock);
if (args->old_song)
cbox_song_playback_destroy(args->old_song);
// If another update was requested while this one was in progress, repeat
// the operation
if (engine->spb_retry) {
engine->spb_retry = 0;
cbox_engine_set_song_playback(engine, NULL, NULL, args->new_time_ppqn);
}
}
void cbox_engine_update_song(struct cbox_engine *engine, int new_pos_ppqn)
{
cbox_engine_set_song_playback(engine, NULL, NULL, new_pos_ppqn);
}
////////////////////////////////////////////////////////////////////////////////////////
void cbox_engine_update_song_playback(struct cbox_engine *engine)
{
cbox_engine_update_song(engine, -1);
}
////////////////////////////////////////////////////////////////////////////////////////
uint32_t cbox_engine_current_pos_samples(struct cbox_engine *engine)
{
uint32_t pos = engine->frame_start_song_pos + engine->song_pos_offset;
if (engine->spb && engine->spb->loop_start_ppqn < engine->spb->loop_end_ppqn)
pos = cbox_song_playback_correct_for_looping(engine->spb, pos);
return pos;
}
////////////////////////////////////////////////////////////////////////////////////////
void cbox_engine_update_input_connections(struct cbox_engine *engine)
{
for (uint32_t i = 0; i < engine->scene_count; i++)
cbox_scene_update_connected_inputs(engine->scenes[i]);
}
void cbox_engine_update_output_connections(struct cbox_engine *engine)
{
for (uint32_t i = 0; i < engine->scene_count; i++)
cbox_scene_update_connected_outputs(engine->scenes[i]);
}
////////////////////////////////////////////////////////////////////////////////////////
void cbox_engine_send_events_to(struct cbox_engine *engine, struct cbox_midi_merger *merger, struct cbox_midi_buffer *buffer)
{
if (!engine || !buffer)
return;
if (merger)
cbox_midi_merger_push(merger, buffer, engine->rt);
else
{
for (uint32_t i = 0; i < engine->scene_count; i++)
cbox_midi_merger_push(&engine->scenes[i]->scene_input_merger, buffer, engine->rt);
if (!engine->rt || !engine->rt->io)
return;
for (GSList *p = engine->rt->io->midi_outputs; p; p = p->next)
{
struct cbox_midi_output *midiout = p->data;
cbox_midi_merger_push(&midiout->merger, buffer, engine->rt);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////
void cbox_engine_on_tempo_sync(struct cbox_engine *engine, double beats_per_minute)
{
if (!engine->master)
return;
if (beats_per_minute && beats_per_minute != engine->master->tempo && beats_per_minute != engine->master->new_tempo) {
engine->master->new_tempo = beats_per_minute;
}
}
////////////////////////////////////////////////////////////////////////////////////////
gboolean cbox_engine_on_transport_sync(struct cbox_engine *engine, enum cbox_transport_state state, uint32_t frame)
{
if (state == ts_stopping)
{
if (engine->master->state == CMTS_ROLLING)
engine->master->state = engine->spb ? CMTS_STOPPING : CMTS_STOP;
return engine->master->state == CMTS_STOP;
}
if (state == ts_starting)
{
if (engine->master->state == CMTS_STOPPING)
return FALSE;
if (engine->master->state == CMTS_ROLLING)
{
if (engine->spb->song_pos_samples == frame)
return TRUE;
engine->master->state = CMTS_STOPPING;
return FALSE;
}
if (engine->spb && engine->spb->song_pos_samples != frame)
{
cbox_song_playback_seek_samples(engine->spb, frame);
}
engine->frame_start_song_pos = frame;
return TRUE;
}
if (state == ts_rolling)
{
// When starting with JACK transport rolling, there is no
// ts_starting message in first place (because there can't be without
// interfering with other applications). Seek immediately.
if (engine->spb && engine->spb->song_pos_samples != frame)
{
cbox_song_playback_seek_samples(engine->spb, frame);
}
else
engine->frame_start_song_pos = frame;
engine->master->state = CMTS_ROLLING;
return TRUE;
}
if (state == ts_stopped)
{
if (engine->master->state == CMTS_ROLLING)
engine->master->state = CMTS_STOPPING;
if (engine->master->state == CMTS_STOP && engine->spb && engine->spb->song_pos_samples != frame)
{
cbox_song_playback_seek_samples(engine->spb, frame);
}
return engine->master->state == CMTS_STOP;
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////////////
struct cbox_midi_merger *cbox_engine_get_midi_output(struct cbox_engine *engine, struct cbox_uuid *uuid)
{
struct cbox_objhdr *objhdr = cbox_document_get_object_by_uuid(CBOX_GET_DOCUMENT(engine), uuid);
if (!objhdr)
return NULL;
struct cbox_scene *scene = (struct cbox_scene *)objhdr;
if (!CBOX_IS_A(scene, cbox_scene))
return NULL;
return &scene->scene_input_merger;
}

72
template/calfbox/engine.h

@ -1,72 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2013 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_ENGINE_H
#define CBOX_ENGINE_H
#include "cmd.h"
#include "dom.h"
#include "io.h"
#include "midi.h"
#include "rt.h"
CBOX_EXTERN_CLASS(cbox_engine)
#define GET_RT_FROM_cbox_engine(ptr) ((ptr)->rt)
struct cbox_engine
{
CBOX_OBJECT_HEADER()
struct cbox_command_target cmd_target;
struct cbox_io_env io_env;
struct cbox_rt *rt;
struct cbox_scene **scenes;
uint32_t scene_count;
struct cbox_song_playback *spb;
struct cbox_module *effect;
struct cbox_master *master;
struct cbox_midi_buffer midibuf_aux, midibuf_jack, midibuf_song;
struct cbox_song_time_mapper *stmap;
struct cbox_midi_appsink appsink;
int spb_lock, spb_retry;
uint32_t frame_start_song_pos, song_pos_offset; // samples
};
// These use an RT command internally
extern struct cbox_engine *cbox_engine_new(struct cbox_document *doc, struct cbox_rt *rt);
extern void cbox_engine_update_song_playback(struct cbox_engine *engine);
extern void cbox_engine_update_input_connections(struct cbox_engine *engine);
extern void cbox_engine_update_output_connections(struct cbox_engine *engine);
extern void cbox_engine_add_scene(struct cbox_engine *engine, struct cbox_scene *scene);
void cbox_engine_remove_scene(struct cbox_engine *engine, struct cbox_scene *scene);
extern struct cbox_song *cbox_engine_set_song(struct cbox_engine *engine, struct cbox_song *song, int new_pos);
extern struct cbox_song *cbox_engine_set_pattern(struct cbox_engine *engine, struct cbox_midi_pattern *pattern, int new_pos);
extern void cbox_engine_set_pattern_and_destroy(struct cbox_engine *engine, struct cbox_midi_pattern *pattern);
extern void cbox_engine_send_events_to(struct cbox_engine *engine, struct cbox_midi_merger *merger, struct cbox_midi_buffer *buffer);
extern void cbox_engine_process(struct cbox_engine *engine, struct cbox_io *io, uint32_t nframes, float **output_buffers, uint32_t output_channels);
extern gboolean cbox_engine_on_transport_sync(struct cbox_engine *engine, enum cbox_transport_state state, uint32_t frame);
extern void cbox_engine_on_tempo_sync(struct cbox_engine *engine, double beats_per_minute);
extern struct cbox_midi_merger *cbox_engine_get_midi_output(struct cbox_engine *engine, struct cbox_uuid *uuid);
extern uint32_t cbox_engine_current_pos_samples(struct cbox_engine *engine);
extern int cbox_engine_get_sample_rate(struct cbox_engine *engine);
extern int cbox_engine_get_buffer_size(struct cbox_engine *engine);
#endif

324
template/calfbox/envelope.h

@ -1,324 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_ENVELOPE_H
#define CBOX_ENVELOPE_H
#include <glib.h>
#include <config-api.h>
struct cbox_envstage
{
double end_value;
int time;
int next_if_pressed, next_if_released, keep_last_value, break_on_release, is_exp;
};
#define MAX_ENV_STAGES 16
#define EXP_NOISE_FLOOR (100.0 / 16384.0)
struct cbox_envelope_shape
{
double start_value;
struct cbox_envstage stages[MAX_ENV_STAGES];
};
struct cbox_envelope
{
struct cbox_envelope_shape *shape;
double stage_start_value, cur_value, exp_factor, inv_time, cur_time, orig_time, orig_target;
int cur_stage;
};
static inline void cbox_envelope_init_stage(struct cbox_envelope *env)
{
struct cbox_envstage *es = &env->shape->stages[env->cur_stage];
env->orig_time = es->time;
env->orig_target = es->end_value;
env->inv_time = es->time > 0 ? 1.0 / es->time : 1e6;
if (es->is_exp)
{
if (env->stage_start_value < EXP_NOISE_FLOOR)
env->stage_start_value = EXP_NOISE_FLOOR;
double ev = es->end_value;
if (ev < EXP_NOISE_FLOOR)
ev = EXP_NOISE_FLOOR;
env->exp_factor = log(ev / env->stage_start_value);
}
}
static inline void cbox_envelope_go_to(struct cbox_envelope *env, int stage)
{
env->stage_start_value = env->cur_value;
env->cur_stage = stage;
env->cur_time = 0;
cbox_envelope_init_stage(env);
}
static inline void cbox_envelope_reset(struct cbox_envelope *env)
{
env->cur_value = 0;
env->cur_stage = 0;
env->cur_time = 0;
cbox_envelope_init_stage(env);
}
static inline void cbox_envelope_update_shape(struct cbox_envelope *env, struct cbox_envelope_shape *shape)
{
struct cbox_envelope_shape *old_shape = env->shape;
env->shape = shape;
if (env->cur_stage < 0)
return;
struct cbox_envstage *ns = &env->shape->stages[env->cur_stage];
struct cbox_envstage *os = &old_shape->stages[env->cur_stage];
if (os->time > 0)
env->cur_time = env->cur_time * ns->time / os->time;
if (env->cur_time > ns->time)
env->cur_time = ns->time;
}
static inline float cbox_envelope_get_value(struct cbox_envelope *env, const struct cbox_envelope_shape *shape)
{
if (env->cur_stage < 0)
return env->cur_value;
const struct cbox_envstage *es = &shape->stages[env->cur_stage];
double pos = es->time > 0 ? env->cur_time * env->inv_time : 0;
if (pos > 1)
pos = 1;
if (es->is_exp)
{
// instead of exp, may use 2**x which can be factored
// into a shift and a table lookup
env->cur_value = env->stage_start_value * expf(pos * env->exp_factor);
if (env->cur_value <= EXP_NOISE_FLOOR)
env->cur_value = 0;
}
else
env->cur_value = env->stage_start_value + (es->end_value - env->stage_start_value) * pos;
return env->cur_value;
}
#define DEBUG_UPDATE_SHAPE(...)
static inline void cbox_envelope_update_shape_after_modify(struct cbox_envelope *env, struct cbox_envelope_shape *shape, double sr)
{
if (env->cur_stage < 0)
return;
struct cbox_envstage *es = &shape->stages[env->cur_stage];
if (es->time != env->orig_time)
{
// Scale cur_time to reflect the same relative position within the stage
env->cur_time = env->cur_time * es->time / (env->orig_time > 0 ? env->orig_time : 1);
env->orig_time = es->time;
env->inv_time = es->time > 0 ? 1.0 / es->time : 1e6;
}
if (es->end_value != env->orig_target)
{
// Adjust the start value to keep the current value intact given the change in the slope
double pos = es->time > 0 ? env->cur_time * env->inv_time : 1;
if (pos < 1)
{
if (es->is_exp)
env->stage_start_value /= pow(es->end_value / (env->orig_target >= EXP_NOISE_FLOOR ? env->orig_target : EXP_NOISE_FLOOR), pos / (1 - pos)); // untested, likely never used
else
env->stage_start_value -= (es->end_value - env->orig_target) * pos / (1 - pos);
}
env->orig_target = es->end_value;
}
}
static inline void cbox_envelope_advance(struct cbox_envelope *env, int released, const struct cbox_envelope_shape *shape)
{
if (env->cur_stage < 0)
return;
const struct cbox_envstage *es = &shape->stages[env->cur_stage];
double pos = es->time > 0 ? env->cur_time * env->inv_time : 1;
env->cur_time++;
if (pos >= 1 || (es->break_on_release && released))
{
int next_stage = released ? es->next_if_released : es->next_if_pressed;
if (!es->keep_last_value || pos >= 1 || (es->keep_last_value == 2 && !released) || next_stage == env->cur_stage)
env->stage_start_value = es->end_value;
else
env->stage_start_value = env->cur_value;
env->cur_stage = next_stage;
env->cur_time = 0;
cbox_envelope_init_stage(env);
}
}
struct cbox_adsr
{
float attack;
float decay;
float sustain;
float release;
};
static inline void cbox_envelope_init_adsr(struct cbox_envelope_shape *env, const struct cbox_adsr *adsr, int sr)
{
env->start_value = 0;
env->stages[0].end_value = 1;
env->stages[0].time = adsr->attack * sr;
env->stages[0].next_if_pressed = 1;
env->stages[0].next_if_released = 3;
env->stages[0].keep_last_value = 1;
env->stages[0].break_on_release = 0;
env->stages[0].is_exp = 0;
env->stages[1].end_value = adsr->sustain;
env->stages[1].time = adsr->decay * sr;
env->stages[1].next_if_pressed = 2;
env->stages[1].next_if_released = 3;
env->stages[1].keep_last_value = 1;
env->stages[1].break_on_release = 0;
env->stages[1].is_exp = 0;
env->stages[2].end_value = adsr->sustain;
env->stages[2].time = 1 * sr;
env->stages[2].next_if_pressed = 2;
env->stages[2].next_if_released = 3;
env->stages[2].keep_last_value = 0;
env->stages[2].break_on_release = 1;
env->stages[2].is_exp = 0;
env->stages[3].end_value = 0;
env->stages[3].time = adsr->release * sr;
env->stages[3].next_if_pressed = -1;
env->stages[3].next_if_released = -1;
env->stages[3].keep_last_value = 0;
env->stages[3].break_on_release = 0;
env->stages[3].is_exp = 1;
env->stages[15].end_value = 0;
env->stages[15].time = 0.01 * sr;
env->stages[15].next_if_pressed = -1;
env->stages[15].next_if_released = -1;
env->stages[15].keep_last_value = 0;
env->stages[15].break_on_release = 0;
env->stages[15].is_exp = 0;
}
struct cbox_dahdsr
{
float start;
float delay;
float attack;
float hold;
float decay;
float sustain;
float release;
};
static inline void cbox_dahdsr_init(struct cbox_dahdsr *dahdsr, float top_value)
{
dahdsr->start = 0.f;
dahdsr->delay = 0.f;
dahdsr->attack = 0.f;
dahdsr->hold = 0.f;
dahdsr->decay = 0.f;
dahdsr->sustain = top_value;
dahdsr->release = 0.05f;
}
static inline void cbox_envelope_init_dahdsr(struct cbox_envelope_shape *env, const struct cbox_dahdsr *dahdsr, int sr, float top_value, gboolean is_release_exp)
{
env->start_value = dahdsr->start;
env->stages[0].end_value = dahdsr->start;
env->stages[0].time = dahdsr->delay * sr;
env->stages[0].next_if_pressed = 1;
env->stages[0].next_if_released = 5;
env->stages[0].keep_last_value = 1;
env->stages[0].break_on_release = 0;
env->stages[0].is_exp = 0;
env->stages[1].end_value = top_value;
env->stages[1].time = dahdsr->attack * sr;
env->stages[1].next_if_pressed = 2;
env->stages[1].next_if_released = 5;
env->stages[1].keep_last_value = 2;
env->stages[1].break_on_release = 1;
env->stages[1].is_exp = 0;
env->stages[2].end_value = top_value;
env->stages[2].time = dahdsr->hold * sr;
env->stages[2].next_if_pressed = 3;
env->stages[2].next_if_released = 5;
env->stages[2].keep_last_value = 2;
env->stages[2].break_on_release = 1;
env->stages[2].is_exp = 0;
env->stages[3].end_value = dahdsr->sustain;
env->stages[3].time = dahdsr->decay * sr;
env->stages[3].next_if_pressed = 4;
env->stages[3].next_if_released = 5;
env->stages[3].keep_last_value = 1;
env->stages[3].break_on_release = 1;
env->stages[3].is_exp = 0;
env->stages[4].end_value = dahdsr->sustain;
env->stages[4].time = 1 * sr;
env->stages[4].next_if_pressed = 4;
env->stages[4].next_if_released = 5;
env->stages[4].keep_last_value = 1;
env->stages[4].break_on_release = 1;
env->stages[4].is_exp = 0;
env->stages[5].end_value = 0;
env->stages[5].time = dahdsr->release * sr;
env->stages[5].next_if_pressed = -1;
env->stages[5].next_if_released = -1;
env->stages[5].keep_last_value = 0;
env->stages[5].break_on_release = 0;
env->stages[5].is_exp = is_release_exp;
env->stages[15].end_value = 0;
env->stages[15].time = 0.01 * sr;
env->stages[15].next_if_pressed = -1;
env->stages[15].next_if_released = -1;
env->stages[15].keep_last_value = 0;
env->stages[15].break_on_release = 0;
env->stages[15].is_exp = 0;
}
static inline void cbox_envelope_modify_dahdsr(struct cbox_envelope_shape *env, int part, float value, int sr)
{
switch(part)
{
case 0: // delay
case 1: // attack
case 2: // hold
case 3: // decay
case 5: // release
env->stages[part].time += value * sr;
// Allow negative times (deal with them in get_next) to make multiple signed modulations work correctly
break;
case 4: // sustain
env->stages[3].end_value += value;
env->stages[4].end_value += value;
env->stages[4].time = 0.02 * sr; // more rapid transition
break;
case 6: // start
env->stages[0].end_value += value;
env->start_value += value;
break;
}
}
#endif

194
template/calfbox/eq.c

@ -1,194 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "biquad-float.h"
#include "config.h"
#include "config-api.h"
#include "dspmath.h"
#include "eq.h"
#include "module.h"
#include <glib.h>
#include <malloc.h>
#include <math.h>
#include <memory.h>
#include <sndfile.h>
#include <stdio.h>
#include <stdlib.h>
#define MODULE_PARAMS parametric_eq_params
#define MAX_EQ_BANDS 4
struct parametric_eq_params
{
struct eq_band bands[MAX_EQ_BANDS];
};
struct parametric_eq_module
{
struct cbox_module module;
struct parametric_eq_params *params, *old_params;
struct cbox_biquadf_state state[MAX_EQ_BANDS][2];
struct cbox_biquadf_coeffs coeffs[MAX_EQ_BANDS];
};
static void redo_filters(struct parametric_eq_module *m)
{
for (int i = 0; i < MAX_EQ_BANDS; i++)
{
struct eq_band *band = &m->params->bands[i];
if (band->active)
{
cbox_biquadf_set_peakeq_rbj(&m->coeffs[i], band->center, band->q, band->gain, m->module.srate);
}
}
m->old_params = m->params;
}
gboolean parametric_eq_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
struct parametric_eq_module *m = (struct parametric_eq_module *)ct->user_data;
EFFECT_PARAM_ARRAY("/active", "i", bands, active, int, , 0, 1) else
EFFECT_PARAM_ARRAY("/center", "f", bands, center, double, , 10, 20000) else
EFFECT_PARAM_ARRAY("/q", "f", bands, q, double, , 0.01, 100) else
EFFECT_PARAM_ARRAY("/gain", "f", bands, gain, double, dB2gain_simple, -100, 100) else
if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
for (int i = 0; i < MAX_EQ_BANDS; i++)
{
if (!cbox_execute_on(fb, NULL, "/active", "ii", error, i, (int)m->params->bands[i].active))
return FALSE;
if (!cbox_execute_on(fb, NULL, "/center", "if", error, i, m->params->bands[i].center))
return FALSE;
if (!cbox_execute_on(fb, NULL, "/q", "if", error, i, m->params->bands[i].q))
return FALSE;
if (!cbox_execute_on(fb, NULL, "/gain", "if", error, i, gain2dB_simple(m->params->bands[i].gain)))
return FALSE;
}
// return cbox_execute_on(fb, NULL, "/wet_dry", "f", error, m->params->wet_dry);
return CBOX_OBJECT_DEFAULT_STATUS(&m->module, fb, error);
}
else
return cbox_object_default_process_cmd(ct, fb, cmd, error);
return TRUE;
}
void parametric_eq_process_event(struct cbox_module *module, const uint8_t *data, uint32_t len)
{
// struct parametric_eq_module *m = (struct parametric_eq_module *)module;
}
void parametric_eq_process_block(struct cbox_module *module, cbox_sample_t **inputs, cbox_sample_t **outputs)
{
struct parametric_eq_module *m = (struct parametric_eq_module *)module;
if (m->params != m->old_params)
redo_filters(m);
for (int c = 0; c < 2; c++)
{
gboolean first = TRUE;
for (int i = 0; i < MAX_EQ_BANDS; i++)
{
if (!m->params->bands[i].active)
continue;
if (first)
{
cbox_biquadf_process_to(&m->state[i][c], &m->coeffs[i], inputs[c], outputs[c]);
first = FALSE;
}
else
{
cbox_biquadf_process(&m->state[i][c], &m->coeffs[i], outputs[c]);
}
}
if (first)
memcpy(outputs[c], inputs[c], sizeof(float) * CBOX_BLOCK_SIZE);
}
}
float cbox_eq_get_band_param(const char *cfg_section, int band, const char *param, float defvalue)
{
gchar *s = g_strdup_printf("band%d_%s", band + 1, param);
float v = cbox_config_get_float(cfg_section, s, defvalue);
g_free(s);
return v;
}
float cbox_eq_get_band_param_db(const char *cfg_section, int band, const char *param, float defvalue)
{
gchar *s = g_strdup_printf("band%d_%s", band + 1, param);
float v = cbox_config_get_gain_db(cfg_section, s, defvalue);
g_free(s);
return v;
}
void cbox_eq_reset_bands(struct cbox_biquadf_state state[1][2], int bands)
{
for (int b = 0; b < MAX_EQ_BANDS; b++)
for (int c = 0; c < 2; c++)
cbox_biquadf_reset(&state[b][c]);
}
MODULE_SIMPLE_DESTROY_FUNCTION(parametric_eq)
MODULE_CREATE_FUNCTION(parametric_eq)
{
static int inited = 0;
if (!inited)
{
inited = 1;
}
struct parametric_eq_module *m = malloc(sizeof(struct parametric_eq_module));
CALL_MODULE_INIT(m, 2, 2, parametric_eq);
m->module.process_event = parametric_eq_process_event;
m->module.process_block = parametric_eq_process_block;
struct parametric_eq_params *p = malloc(sizeof(struct parametric_eq_params));
m->params = p;
m->old_params = NULL;
for (int b = 0; b < MAX_EQ_BANDS; b++)
{
p->bands[b].active = cbox_eq_get_band_param(cfg_section, b, "active", 0) > 0;
p->bands[b].center = cbox_eq_get_band_param(cfg_section, b, "center", 50 * pow(4.0, b));
p->bands[b].q = cbox_eq_get_band_param(cfg_section, b, "q", 0.707);
p->bands[b].gain = cbox_eq_get_band_param_db(cfg_section, b, "gain", 0);
}
cbox_eq_reset_bands(m->state, MAX_EQ_BANDS);
return &m->module;
}
struct cbox_module_keyrange_metadata parametric_eq_keyranges[] = {
};
struct cbox_module_livecontroller_metadata parametric_eq_controllers[] = {
};
DEFINE_MODULE(parametric_eq, 2, 2)

31
template/calfbox/eq.h

@ -1,31 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <glib.h>
struct eq_band
{
gboolean active;
float center;
float q;
float gain;
};
extern float cbox_eq_get_band_param(const char *cfg_section, int band, const char *param, float defvalue);
extern float cbox_eq_get_band_param_db(const char *cfg_section, int band, const char *param, float defvalue);
extern void cbox_eq_reset_bands(struct cbox_biquadf_state state[1][2], int bands);

70
template/calfbox/errors.c

@ -1,70 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "errors.h"
GQuark cbox_module_error_quark()
{
return g_quark_from_string("cbox-module-error-quark");
}
void cbox_force_error(GError **error)
{
if (error && !*error)
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "unknown error");
}
void cbox_print_error(GError *error)
{
if (!error)
{
g_warning("Unspecified error");
return;
}
g_warning("%s", error->message);
g_error_free(error);
}
void cbox_print_error_if(GError *error)
{
if (!error)
return;
g_warning("%s", error->message);
g_error_free(error);
}
gboolean cbox_set_command_error(GError **error, const struct cbox_osc_command *cmd)
{
if (error && !*error)
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_OUT_OF_RANGE, "Invalid command '%s' with args '%s'", cmd->command, cmd->arg_types);
return FALSE;
}
gboolean cbox_set_command_error_with_msg(GError **error, const struct cbox_osc_command *cmd, const char *extra_msg)
{
if (error && !*error)
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_OUT_OF_RANGE, "Invalid command '%s' with args '%s': %s", cmd->command, cmd->arg_types, extra_msg);
return FALSE;
}
gboolean cbox_set_range_error(GError **error, const char *param, double minv, double maxv)
{
if (error && !*error)
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_OUT_OF_RANGE, "Parameter %s not within a valid range of [%f, %f]", param, minv, maxv);
return FALSE;
}

44
template/calfbox/errors.h

@ -1,44 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_ERRORS_H
#define CBOX_ERRORS_H
#include <glib.h>
#include "cmd.h"
#define CBOX_MODULE_ERROR cbox_module_error_quark()
enum CboxModuleError
{
CBOX_MODULE_ERROR_FAILED,
CBOX_MODULE_ERROR_INVALID_COMMAND,
CBOX_MODULE_ERROR_OUT_OF_RANGE,
};
struct cbox_osc_command;
extern GQuark cbox_module_error_quark(void);
extern void cbox_force_error(GError **error);
extern void cbox_print_error(GError *error);
extern void cbox_print_error_if(GError *error);
extern gboolean cbox_set_command_error(GError **error, const struct cbox_osc_command *cmd);
extern gboolean cbox_set_command_error_with_msg(GError **error, const struct cbox_osc_command *cmd, const char *extra_msg);
extern gboolean cbox_set_range_error(GError **error, const char *param, double minv, double maxv);
#endif

554
template/calfbox/example.py

@ -1,554 +0,0 @@
import sys
sys.argv = []
import gi
gi.require_version('Gdk', '3.0')
gi.require_version('Gtk', '3.0')
from gi.repository import GObject, Gdk, Gtk
import math
sys.path = ["./py"] + sys.path
import cbox
from gui_tools import *
import fx_gui
import instr_gui
import drumkit_editor
#import drum_pattern_editor
class SceneDialog(SelectObjectDialog):
title = "Select a scene"
def __init__(self, parent):
SelectObjectDialog.__init__(self, parent=parent)
def update_model(self, model):
for s in cbox.Config.sections("scene:"):
title = s["title"]
model.append((s.name[6:], "Scene", s.name, title))
for s in cbox.Config.sections("instrument:"):
title = s["title"]
model.append((s.name[11:], "Instrument", s.name, title))
for s in cbox.Config.sections("layer:"):
title = s["title"]
model.append((s.name[6:], "Layer", s.name, title))
class NewLayerDialog(SelectObjectDialog):
title = "Create a layer"
def __init__(self, parent):
SelectObjectDialog.__init__(self, parent=parent)
def update_model(self, model):
for engine_name, wclass in instr_gui.instrument_window_map.items():
model.append((engine_name, "Engine", engine_name, ""))
class LoadLayerDialog(SelectObjectDialog):
title = "Load a layer"
def __init__(self, parent):
SelectObjectDialog.__init__(self, parent=parent)
def update_model(self, model):
for s in cbox.Config.sections("instrument:"):
title = s["title"]
model.append((s.name[11:], "Instrument", s.name, title))
for s in cbox.Config.sections("layer:"):
title = s["title"]
model.append((s.name[6:], "Layer", s.name, title))
class PlayPatternDialog(SelectObjectDialog):
title = "Play a drum pattern"
def __init__(self, parent):
SelectObjectDialog.__init__(self, parent)
def update_model(self, model):
model.append((None, "Stop", "", ""))
for s in cbox.Config.sections("drumpattern:"):
title = s["title"]
model.append((s.name[12:], "Pattern", s.name, title))
for s in cbox.Config.sections("drumtrack:"):
title = s["title"]
model.append((s.name[10:], "Track", s.name, title))
in_channels_ls = Gtk.ListStore(GObject.TYPE_INT, GObject.TYPE_STRING)
in_channels_ls.append((0, "All"))
out_channels_ls = Gtk.ListStore(GObject.TYPE_INT, GObject.TYPE_STRING)
out_channels_ls.append((0, "Same"))
for i in range(1, 17):
in_channels_ls.append((i, str(i)))
out_channels_ls.append((i, str(i)))
notes_ls = Gtk.ListStore(GObject.TYPE_INT, GObject.TYPE_STRING)
opt_notes_ls = Gtk.ListStore(GObject.TYPE_INT, GObject.TYPE_STRING)
opt_notes_ls.append((-1, "N/A"))
for i in range(0, 128):
notes_ls.append((i, note_to_name(i)))
opt_notes_ls.append((i, note_to_name(i)))
transpose_ls = Gtk.ListStore(GObject.TYPE_INT, GObject.TYPE_STRING)
for i in range(-60, 61):
transpose_ls.append((i, str(i)))
class SceneLayersModel(Gtk.ListStore):
def __init__(self):
Gtk.ListStore.__init__(self, GObject.TYPE_STRING, GObject.TYPE_BOOLEAN,
GObject.TYPE_INT, GObject.TYPE_INT, GObject.TYPE_BOOLEAN,
GObject.TYPE_INT, GObject.TYPE_INT, GObject.TYPE_INT, GObject.TYPE_INT, GObject.TYPE_STRING)
#def make_row_item(self, opath, tree_path):
# return opath % self[(1 + int(tree_path))]
def make_row_item(self, opath, tree_path):
return cbox.Document.uuid_cmd(self[int(tree_path)][-1], opath)
def refresh(self, scene_status):
self.clear()
for layer in scene_status.layers:
ls = layer.status()
self.append((ls.instrument_name, ls.enable != 0, ls.in_channel, ls.out_channel, ls.consume != 0, ls.low_note, ls.high_note, ls.fixed_note, ls.transpose, layer.uuid))
class SceneLayersView(Gtk.TreeView):
def __init__(self, model):
Gtk.TreeView.__init__(self, model=model)
self.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, [("text/plain", 0, 1)], Gdk.DragAction.MOVE)
self.enable_model_drag_dest([("text/plain", Gtk.TargetFlags.SAME_APP | Gtk.TargetFlags.SAME_WIDGET, 1)], Gdk.DragAction.MOVE)
self.connect('drag_data_get', self.drag_data_get)
self.connect('drag_data_received', self.drag_data_received)
self.insert_column_with_attributes(0, "On?", standard_toggle_renderer(model, "/enable", 1), active=1)
self.insert_column_with_attributes(1, "Name", Gtk.CellRendererText(), text=0)
self.insert_column_with_data_func(2, "In Ch#", standard_combo_renderer(model, in_channels_ls, "/in_channel", 2), lambda column, cell, model, iter, data: cell.set_property('text', "%s" % model[iter][2] if model[iter][2] != 0 else 'All'), None)
self.insert_column_with_data_func(3, "Out Ch#", standard_combo_renderer(model, out_channels_ls, "/out_channel", 3), lambda column, cell, model, iter, data: cell.set_property('text', "%s" % model[iter][3] if model[iter][3] != 0 else 'Same'), None)
self.insert_column_with_attributes(4, "Eat?", standard_toggle_renderer(model, "/consume", 4), active=4)
self.insert_column_with_data_func(5, "Lo N#", standard_combo_renderer(model, notes_ls, "/low_note", 5), lambda column, cell, model, iter, data: cell.set_property('text', note_to_name(model[iter][5])), None)
self.insert_column_with_data_func(6, "Hi N#", standard_combo_renderer(model, notes_ls, "/high_note", 6), lambda column, cell, model, iter, data: cell.set_property('text', note_to_name(model[iter][6])), None)
self.insert_column_with_data_func(7, "Fix N#", standard_combo_renderer(model, opt_notes_ls, "/fixed_note", 7), lambda column, cell, model, iter, data: cell.set_property('text', note_to_name(model[iter][7])), None)
self.insert_column_with_attributes(8, "Transpose", standard_combo_renderer(model, transpose_ls, "/transpose", 8), text=8)
def drag_data_get(self, treeview, context, selection, target_id, etime):
cursor = treeview.get_cursor()
if cursor is not None:
selection.set('text/plain', 8, str(cursor[0][0]))
def drag_data_received(self, treeview, context, x, y, selection, info, etime):
src_row = int(selection.data)
dest_row_info = treeview.get_dest_row_at_pos(x, y)
if dest_row_info is not None:
dest_row = dest_row_info[0][0]
#print src_row, dest_row, dest_row_info[1]
scene = cbox.Document.get_scene()
scene.move_layer(src_row, dest_row)
self.get_model().refresh(scene.status())
class SceneAuxBusesModel(Gtk.ListStore):
def __init__(self):
Gtk.ListStore.__init__(self, GObject.TYPE_STRING, GObject.TYPE_STRING)
def refresh(self, scene_status):
self.clear()
for aux_name, aux_obj in scene_status.auxes.items():
slot = aux_obj.slot.status()
self.append((slot.insert_preset, slot.insert_engine))
class SceneAuxBusesView(Gtk.TreeView):
def __init__(self, model):
Gtk.TreeView.__init__(self, model=model)
self.insert_column_with_attributes(0, "Name", Gtk.CellRendererText(), text=0)
self.insert_column_with_attributes(1, "Engine", Gtk.CellRendererText(), text=1)
def get_current_row(self):
if self.get_cursor()[0] is None:
return None, None
row = self.get_cursor()[0][0]
return row + 1, self.get_model()[row]
class StatusBar(Gtk.Statusbar):
def __init__(self):
Gtk.Statusbar.__init__(self)
self.sample_rate_label = Gtk.Label(label="")
self.pack_start(self.sample_rate_label, False, False, 2)
self.status = self.get_context_id("Status")
self.sample_rate = self.get_context_id("Sample rate")
self.push(self.status, "")
self.push(self.sample_rate, "-")
def update(self, status, sample_rate):
self.pop(self.status)
self.push(self.status, status)
self.sample_rate_label.set_text("%s Hz" % sample_rate)
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, type = Gtk.WindowType.TOPLEVEL)
self.vbox = Gtk.VBox(spacing = 5)
self.add(self.vbox)
self.create()
set_timer(self, 30, self.update)
#self.drum_pattern_editor = None
self.drumkit_editor = None
def create(self):
self.menu_bar = Gtk.MenuBar()
self.menu_bar.append(create_menu("_Scene", [
("_Load", self.load_scene),
("_Quit", self.quit),
]))
self.menu_bar.append(create_menu("_Layer", [
("_New", self.layer_new),
("_Load", self.layer_load),
("_Remove", self.layer_remove),
]))
self.menu_bar.append(create_menu("_AuxBus", [
("_Add", self.aux_bus_add),
("_Edit", self.aux_bus_edit),
("_Remove", self.aux_bus_remove),
]))
self.menu_bar.append(create_menu("_Tools", [
("_Drum Kit Editor", self.tools_drumkit_editor),
("_Play Drum Pattern", self.tools_play_drum_pattern),
#("_Edit Drum Pattern", self.tools_drum_pattern_editor),
("_Un-zombify", self.tools_unzombify),
("_Object list", self.tools_object_list),
("_Wave bank dump", self.tools_wave_bank_dump),
]))
self.vbox.pack_start(self.menu_bar, False, False, 0)
rt_status = cbox.Document.get_rt().status()
scene = cbox.Document.get_scene()
self.nb = Gtk.Notebook()
self.vbox.add(self.nb)
self.nb.append_page(self.create_master(scene), Gtk.Label(label="Master"))
self.status_bar = StatusBar()
self.vbox.pack_start(self.status_bar, False, False, 0)
self.create_instrument_pages(scene.status(), rt_status)
def create_master(self, scene):
scene_status = scene.status()
self.master_info = left_label("")
self.timesig_info = left_label("")
t = Gtk.Grid()
t.set_column_spacing(5)
t.set_row_spacing(5)
t.attach(bold_label("Scene"), 0, 0, 1, 1)
self.scene_label = left_label(scene_status.name)
t.attach(self.scene_label, 1, 0, 2, 1)
self.title_label = left_label(scene_status.title)
t.attach(bold_label("Title"), 0, 1, 1, 1)
t.attach(self.title_label, 1, 1, 2, 1)
t.attach(bold_label("Play pos"), 0, 2, 1, 1)
t.attach(self.master_info, 1, 2, 2, 1)
t.attach(bold_label("Time sig"), 0, 3, 1, 1)
t.attach(self.timesig_info, 1, 3, 2, 1)
hb = Gtk.HButtonBox()
b = Gtk.Button(label="Play")
b.connect('clicked', lambda w: cbox.Transport.play())
hb.pack_start(b, False, False, 5)
b = Gtk.Button(label="Stop")
b.connect('clicked', lambda w: cbox.Transport.stop())
hb.pack_start(b, False, False, 5)
b = Gtk.Button(label="Rewind")
b.connect('clicked', lambda w: cbox.Transport.seek_ppqn(0))
hb.pack_start(b, False, False, 5)
b = Gtk.Button(label="Panic")
b.connect('clicked', lambda w: cbox.Transport.panic())
hb.pack_start(b, False, False, 5)
t.attach(hb, 2, 3, 1, 1)
t.attach(bold_label("Tempo"), 0, 4, 1, 1)
self.tempo_adj = Gtk.Adjustment(value=40, lower=40, upper=300, step_increment=1, page_increment=5, page_size=0)
self.tempo_adj.connect('value_changed', adjustment_changed_float, cbox.VarPath("/master/set_tempo"))
t.attach(standard_hslider(self.tempo_adj), 1, 4, 2, 1)
t.attach(bold_label("Transpose"), 0, 5, 1, 1)
self.transpose_adj = Gtk.Adjustment(value=scene_status.transpose, lower=-24, upper=24, step_increment=1, page_increment=5, page_size=0)
self.transpose_adj.connect('value_changed', adjustment_changed_int, cbox.VarPath('/scene/transpose'))
t.attach(standard_align(Gtk.SpinButton(adjustment = self.transpose_adj), 0, 0, 0, 0), 1, 5, 2, 1)
self.layers_model = SceneLayersModel()
self.layers_view = SceneLayersView(self.layers_model)
t.attach(standard_vscroll_window(-1, 160, self.layers_view), 0, 7, 3, 1)
self.auxes_model = SceneAuxBusesModel()
self.auxes_view = SceneAuxBusesView(self.auxes_model)
t.attach(standard_vscroll_window(-1, 120, self.auxes_view), 0, 8, 3, 1)
me = cbox.Document.get_engine().master_effect
me_status = me.status()
hb = Gtk.HBox(spacing = 5)
self.master_chooser = fx_gui.InsertEffectChooser(me.path, "slot", me_status.insert_engine, me_status.insert_preset, me_status.bypass, self)
hb.pack_start(self.master_chooser.fx_engine, True, True, 0)
hb.pack_start(self.master_chooser.fx_preset, True, True, 5)
hb.pack_start(self.master_chooser.fx_edit, False, False, 5)
hb.pack_start(self.master_chooser.fx_bypass, False, False, 5)
t.attach(bold_label("Master effect"), 0, 6, 1, 1)
t.attach(standard_align(hb, 0, 0, 0, 0), 1, 6, 3, 1)
self.layers_model.refresh(scene_status)
self.auxes_model.refresh(scene_status)
return t
def quit(self, w):
self.destroy()
def load_scene(self, w):
d = SceneDialog(self)
response = d.run()
try:
if response == Gtk.ResponseType.OK:
scene = cbox.Document.get_scene()
item_name, item_type, item_key, item_label = d.get_selected_object()
if item_type == 'Scene':
scene.load(item_name)
elif item_type == 'Layer':
scene.clear()
scene.add_layer(item_name)
elif item_type == 'Instrument':
scene.clear()
scene.add_instrument_layer(item_name)
scene_status = scene.status()
self.scene_label.set_text(scene_status.name)
self.title_label.set_text(scene_status.title)
self.refresh_instrument_pages(scene_status)
finally:
d.destroy()
def layer_load(self, w):
d = LoadLayerDialog(self)
response = d.run()
try:
if response == Gtk.ResponseType.OK:
scene = cbox.Document.get_scene()
item_name, item_type, item_key, item_label = d.get_selected_object()
if item_type == 'Layer':
scene.add_layer(item_name)
elif item_type == 'Instrument':
scene.add_instrument_layer(item_name)
self.refresh_instrument_pages()
finally:
d.destroy()
def layer_new(self, w):
d = NewLayerDialog(self)
response = d.run()
try:
if response == Gtk.ResponseType.OK:
scene = cbox.Document.get_scene()
keys = scene.status().instruments.keys()
engine_name = d.get_selected_object()[0]
for i in range(1, 1001):
name = "%s%s" % (engine_name, i)
if name not in keys:
break
scene.add_new_instrument_layer(name, engine_name)
self.refresh_instrument_pages()
finally:
d.destroy()
def layer_remove(self, w):
if self.layers_view.get_cursor()[0] is not None:
pos = self.layers_view.get_cursor()[0][0]
cbox.Document.get_scene().delete_layer(pos)
self.refresh_instrument_pages()
def aux_bus_add(self, w):
d = fx_gui.LoadEffectDialog(self)
response = d.run()
try:
cbox.do_cmd("/scene/load_aux", None, [d.get_selected_object()[0]])
self.refresh_instrument_pages()
finally:
d.destroy()
def aux_bus_remove(self, w):
rowid, row = self.auxes_view.get_current_row()
if rowid is None:
return
cbox.do_cmd("/scene/delete_aux", None, [row[0]])
self.refresh_instrument_pages()
def aux_bus_edit(self, w):
rowid, row = self.auxes_view.get_current_row()
if rowid is None:
return
wclass = fx_gui.effect_window_map[row[1]]
popup = wclass("Aux: %s" % row[0], self, "/scene/aux/%s/slot/engine" % row[0])
popup.show_all()
popup.present()
def tools_unzombify(self, w):
cbox.do_cmd("/rt/cycle", None, [])
def tools_drumkit_editor(self, w):
if self.drumkit_editor is None:
self.drumkit_editor = drumkit_editor.EditorDialog(self)
self.refresh_instrument_pages()
self.drumkit_editor.connect('destroy', self.on_drumkit_editor_destroy)
self.drumkit_editor.show_all()
self.drumkit_editor.present()
def on_drumkit_editor_destroy(self, w):
self.drumkit_editor = None
def tools_object_list(self, w):
cbox.Document.dump()
def tools_wave_bank_dump(self, w):
for w in cbox.get_thing('/waves/list', '/waveform', [str]):
info = cbox.GetThings("/waves/info", ["filename", "name", "bytes", "loop"], [w])
print("%s: %d bytes, loop = %s" % (info.filename, info.bytes, info.loop))
def tools_play_drum_pattern(self, w):
d = PlayPatternDialog(self)
response = d.run()
try:
if response == Gtk.ResponseType.OK:
row = d.get_selected_object()
if row[1] == 'Pattern':
song = cbox.Document().get_song()
song.loop_single_pattern(lambda: song.load_drum_pattern(row[0]))
elif row[1] == 'Track':
song = cbox.Document().get_song()
song.loop_single_pattern(lambda: song.load_drum_track(row[0]))
elif row[1] == 'Stop':
song = cbox.Document().get_song()
song.clear()
song.update_playback()
tracks = song.status().tracks
if len(tracks):
for track_item in tracks:
track_item.track.set_external_output(cbox.Document.get_scene().uuid)
song.update_playback()
finally:
d.destroy()
def tools_drum_pattern_editor(self, w):
if self.drum_pattern_editor is None:
length = drum_pattern_editor.PPQN * 4
pat_data = cbox.Pattern.get_pattern()
if pat_data is not None:
pat_data, length = pat_data
self.drum_pattern_editor = drum_pattern_editor.DrumSeqWindow(length, pat_data)
self.drum_pattern_editor.set_title("Drum pattern editor")
self.drum_pattern_editor.show_all()
self.drum_pattern_editor.connect('destroy', self.on_drum_pattern_editor_destroy)
self.drum_pattern_editor.pattern.connect('changed', self.on_drum_pattern_changed)
self.drum_pattern_editor.pattern.changed()
self.drum_pattern_editor.present()
def on_drum_pattern_changed(self, pattern):
data = bytearray()
for i in pattern.items():
ch = i.channel - 1
data += cbox.Pattern.serialize_event(int(i.pos), 0x90 + ch, int(i.row), int(i.vel))
if i.len > 1:
data += cbox.Pattern.serialize_event(int(i.pos + i.len - 1), 0x80 + ch, int(i.row), int(i.vel))
else:
data += cbox.Pattern.serialize_event(int(i.pos + 1), 0x80 + ch, int(i.row), int(i.vel))
length = pattern.get_length()
song = cbox.Document().get_song()
song.loop_single_pattern(lambda: song.pattern_from_blob(data, length))
def on_drum_pattern_editor_destroy(self, w):
self.drum_pattern_editor = None
def refresh_instrument_pages(self, scene_status = None):
self.delete_instrument_pages()
rt_status = cbox.Document.get_rt().status()
if scene_status is None:
scene_status = cbox.Document.get_scene().status()
self.layers_model.refresh(scene_status)
self.auxes_model.refresh(scene_status)
self.create_instrument_pages(scene_status, rt_status)
self.nb.show_all()
self.title_label.set_text(scene_status.title)
def create_instrument_pages(self, scene_status, rt_status):
self.path_widgets = {}
self.path_popups = {}
self.fx_choosers = {}
outputs_ls = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_INT)
for out in range(0, rt_status.audio_channels[1]//2):
outputs_ls.append(("Out %s/%s" % (out * 2 + 1, out * 2 + 2), out))
auxbus_ls = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_STRING)
auxbus_ls.append(("", ""))
for bus_name in scene_status.auxes.keys():
auxbus_ls.append(("Aux: %s" % bus_name, bus_name))
for iname, (iengine, iobj) in scene_status.instruments.items():
ipath = "/scene/instr/%s" % iname
idata = iobj.status()
#attribs = cbox.GetThings("/scene/instr_info", ['engine', 'name'], [i])
#markup += '<b>Instrument %d:</b> engine %s, name %s\n' % (i, attribs.engine, attribs.name)
b = Gtk.VBox(spacing = 5)
b.set_border_width(5)
b.pack_start(Gtk.Label(label="Engine: %s" % iengine), False, False, 5)
b.pack_start(Gtk.HSeparator(), False, False, 5)
t = Gtk.Table(n_rows=1 + idata.outputs, n_columns=7)
t.attach(bold_label("Instr. output", 0.5), 0, 1, 0, 1, Gtk.AttachOptions.SHRINK, Gtk.AttachOptions.SHRINK)
t.attach(bold_label("Send to", 0.5), 1, 2, 0, 1, Gtk.AttachOptions.SHRINK, Gtk.AttachOptions.SHRINK)
t.attach(bold_label("Gain [dB]", 0.5), 2, 3, 0, 1, 0, Gtk.AttachOptions.SHRINK)
t.attach(bold_label("Effect", 0.5), 3, 4, 0, 1, 0, Gtk.AttachOptions.SHRINK)
t.attach(bold_label("Preset", 0.5), 4, 7, 0, 1, 0, Gtk.AttachOptions.SHRINK)
b.pack_start(t, False, False, 5)
y = 1
for o in range(1, idata.outputs + 1):
is_aux = o >= idata.aux_offset
if not is_aux:
opath = "%s/output/%s" % (ipath, o)
output_name = "Out %s" % o
else:
opath = "%s/aux/%s" % (ipath, o - idata.aux_offset + 1)
output_name = "Aux %s" % (o - idata.aux_offset + 1)
odata = cbox.GetThings(opath + "/status", ['gain', 'output', 'bus', 'insert_engine', 'insert_preset', 'bypass'], [])
engine = odata.insert_engine
preset = odata.insert_preset
bypass = odata.bypass
t.attach(Gtk.Label(label=output_name), 0, 1, y, y + 1, Gtk.AttachOptions.SHRINK, Gtk.AttachOptions.SHRINK)
if not is_aux:
cb = standard_combo(outputs_ls, odata.output - 1)
cb.connect('changed', combo_value_changed, cbox.VarPath(opath + '/output'), 1)
else:
cb = standard_combo(auxbus_ls, ls_index(auxbus_ls, odata.bus, 1))
cb.connect('changed', combo_value_changed_use_column, cbox.VarPath(opath + '/bus'), 1)
t.attach(cb, 1, 2, y, y + 1, Gtk.AttachOptions.SHRINK, Gtk.AttachOptions.SHRINK)
adj = Gtk.Adjustment(value=odata.gain, lower=-96, upper=24, step_increment=1, page_increment=6, page_size=0)
adj.connect('value_changed', adjustment_changed_float, cbox.VarPath(opath + '/gain'))
t.attach(standard_hslider(adj), 2, 3, y, y + 1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK)
chooser = fx_gui.InsertEffectChooser(opath, "%s: %s" % (iname, output_name), engine, preset, bypass, self)
self.fx_choosers[opath] = chooser
t.attach(chooser.fx_engine, 3, 4, y, y + 1, 0, Gtk.AttachOptions.SHRINK)
t.attach(chooser.fx_preset, 4, 5, y, y + 1, 0, Gtk.AttachOptions.SHRINK)
t.attach(chooser.fx_edit, 5, 6, y, y + 1, 0, Gtk.AttachOptions.SHRINK)
t.attach(chooser.fx_bypass, 6, 7, y, y + 1, 0, Gtk.AttachOptions.SHRINK)
y += 1
if iengine in instr_gui.instrument_window_map:
b.pack_start(Gtk.HSeparator(), False, False, 5)
b.pack_start(instr_gui.instrument_window_map[iengine](iname, iobj), True, True, 5)
self.nb.append_page(b, Gtk.Label(label=iname))
self.update()
def delete_instrument_pages(self):
while self.nb.get_n_pages() > 1:
self.nb.remove_page(self.nb.get_n_pages() - 1)
def update(self):
cbox.call_on_idle()
master = cbox.Transport.status()
if master.tempo is not None:
self.master_info.set_markup('%s (%s)' % (master.pos, master.pos_ppqn))
self.timesig_info.set_markup("%s/%s" % tuple(master.timesig))
self.tempo_adj.set_value(master.tempo)
state = cbox.Document.get_rt().status().state
self.status_bar.update(state[1], master.sample_rate)
return True
def do_quit(window):
Gtk.main_quit()
w = MainWindow()
w.set_title("My UI")
w.show_all()
w.connect('destroy', do_quit)
Gtk.main()

57
template/calfbox/experiments/interactive.py

@ -1,57 +0,0 @@
#! /usr/bin/env -S python3 -i
# -*- coding: utf-8 -*-
"""
This is a minimal calfbox python example. It is meant as a starting
point to find bugs and test performance.
Copyright, Nils Hilbricht, Germany ( https://www.hilbricht.net )
This code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import atexit
from pprint import pprint
from calfbox import cbox
cbox.init_engine("")
cbox.Config.set("io", "outputs", 8)
NAME = "Cbox Interactive"
cbox.Config.set("io", "client_name", NAME)
cbox.start_audio()
scene = cbox.Document.get_engine().new_scene()
scene.clear()
trackName = "trackOne"
cboxMidiOutUuid = cbox.JackIO.create_midi_output(trackName)
calfboxTrack = cbox.Document.get_song().add_track()
pblob = bytes()
pblob += cbox.Pattern.serialize_event(0, 0x90, 60, 100) # note on
pblob += cbox.Pattern.serialize_event(383, 0x80, 60, 100) # note off
pattern = cbox.Document.get_song().pattern_from_blob(pblob, 384)
calfboxTrack.add_clip(0, 0, 384, pattern) #pos, offset, length(and not end-position, but is the same for the complete track), pattern
cbox.Document.get_song().set_loop(384, 384) #set playback length for the entire score. Why is the first value not zero? That would create an actual loop from the start to end. We want the song to play only once. The cbox way of doing that is to set the loop range to zero at the end of the track. Zero length is stop.
cbox.Document.get_song().update_playback()
print()
def exit_handler():
#Restore initial state and stop the engine
cbox.Transport.stop()
cbox.stop_audio()
cbox.shutdown_engine()
atexit.register(exit_handler)

602
template/calfbox/experiments/meta.py

@ -1,602 +0,0 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright, Nils Hilbricht, Germany ( https://www.hilbricht.net )
This code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import re
from calfbox import cbox #use the globally installed calfbox
from asyncio import get_event_loop
from sys import stdout, maxsize
import os, signal
D1024 =210 * 2**0 # = 210. The lcm of 2, 3, 5, 7 . according to www.informatics.indiana.edu/donbyrd/CMNExtremes.htm this is the real world limit.
D512 = 210 * 2**1
D256 = 210 * 2**2
D128 = 210 * 2**3
D64 = 210 * 2**4
D32 = 210 * 2**5
D16 = 210 * 2**6 #16th 13440 ticks
D8 = 210 * 2**7 #eigth 26880 ticks
D4 = 210 * 2**8 #quarter 53760 ticks
D2 = 210 * 2**9 #half 107520 ticks
D1 = 210 * 2**10 #whole 215040 ticks
DB = 210 * 2**11 #brevis 430080 ticks
DL = 210 * 2**12 #longa
DM = 210 * 2**13 #maxima
#MAXIMUM = 0x7FFFFFFF # 31bit. maximum number of calfbox ticks allowed for its timeline, for example for the song duration
MAXIMUM = 100 * D1
#max_pulses = min(2**31, 2**31 * ppqn * bpm / (60 * sample_rate))
ly2pitch = {
"ceses,,," : 00,
"ces,,," : 10,
"c,,," : 20,
"cis,,," : 30,
"cisis,,," : 40,
"deses,,," : 50,
"des,,," : 60,
"d,,," : 70,
"dis,,," : 80,
"disis,,," : 90,
"eeses,,," : 100,
"ees,,," : 110,
"e,,," : 120,
"eis,,," : 130,
"eisis,,," : 140,
"feses,,," : 150,
"fes,,," : 160,
"f,,," : 170,
"fis,,," : 180,
"fisis,,," : 190,
"geses,,," : 200,
"ges,,," : 210,
"g,,," : 220,
"gis,,," : 230,
"gisis,,," : 240,
"aeses,,," : 250,
"aes,,," : 260,
"a,,," : 270,
"ais,,," : 280,
"aisis,,," : 290,
"beses,,," : 300,
"bes,,," : 310,
"b,,," : 320,
"bis,,," : 330,
"bisis,,," : 340,
"ceses,," : 350,
"ces,," : 360,
"c,," : 370,
"cis,," : 380,
"cisis,," : 390,
"deses,," : 400,
"des,," : 410,
"d,," : 420,
"dis,," : 430,
"disis,," : 440,
"eeses,," : 450,
"ees,," : 460,
"e,," : 470,
"eis,," : 480,
"eisis,," : 490,
"feses,," : 500,
"fes,," : 510,
"f,," : 520,
"fis,," : 530,
"fisis,," : 540,
"geses,," : 550,
"ges,," : 560,
"g,," : 570,
"gis,," : 580,
"gisis,," : 590,
"aeses,," : 600,
"aes,," : 610,
"a,," : 620,
"ais,," : 630,
"aisis,," : 640,
"beses,," : 650,
"bes,," : 660,
"b,," : 670,
"bis,," : 680,
"bisis,," : 690,
"ceses," : 700,
"ces," : 710,
"c," : 720,
"cis," : 730,
"cisis," : 740,
"deses," : 750,
"des," : 760,
"d," : 770,
"dis," : 780,
"disis," : 790,
"eeses," : 800,
"ees," : 810,
"e," : 820,
"eis," : 830,
"eisis," : 840,
"feses," : 850,
"fes," : 860,
"f," : 870,
"fis," : 880,
"fisis," : 890,
"geses," : 900,
"ges," : 910,
"g," : 920,
"gis," : 930,
"gisis," : 940,
"aeses," : 950,
"aes," : 960,
"a," : 970,
"ais," : 980,
"aisis," : 990,
"beses," : 1000,
"bes," : 1010,
"b," : 1020,
"bis," : 1030,
"bisis," : 1040,
"ceses" : 1050,
"ces" : 1060,
"c" : 1070,
"cis" : 1080,
"cisis" : 1090,
"deses" : 1100,
"des" : 1110,
"d" : 1120,
"dis" : 1130,
"disis" : 1140,
"eeses" : 1150,
"ees" : 1160,
"e" : 1170,
"eis" : 1180,
"eisis" : 1190,
"feses" : 1200,
"fes" : 1210,
"f" : 1220,
"fis" : 1230,
"fisis" : 1240,
"geses" : 1250,
"ges" : 1260,
"g" : 1270,
"gis" : 1280,
"gisis" : 1290,
"aeses" : 1300,
"aes" : 1310,
"a" : 1320,
"ais" : 1330,
"aisis" : 1340,
"beses" : 1350,
"bes" : 1360,
"b" : 1370,
"bis" : 1380,
"bisis" : 1390,
"ceses'" : 1400,
"ces'" : 1410,
"c'" : 1420,
"cis'" : 1430,
"cisis'" : 1440,
"deses'" : 1450,
"des'" : 1460,
"d'" : 1470,
"dis'" : 1480,
"disis'" : 1490,
"eeses'" : 1500,
"ees'" : 1510,
"e'" : 1520,
"eis'" : 1530,
"eisis'" : 1540,
"feses'" : 1550,
"fes'" : 1560,
"f'" : 1570,
"fis'" : 1580,
"fisis'" : 1590,
"geses'" : 1600,
"ges'" : 1610,
"g'" : 1620,
"gis'" : 1630,
"gisis'" : 1640,
"aeses'" : 1650,
"aes'" : 1660,
"a'" : 1670,
"ais'" : 1680,
"aisis'" : 1690,
"beses'" : 1700,
"bes'" : 1710,
"b'" : 1720,
"bis'" : 1730,
"bisis'" : 1740,
"ceses''" : 1750,
"ces''" : 1760,
"c''" : 1770,
"cis''" : 1780,
"cisis''" : 1790,
"deses''" : 1800,
"des''" : 1810,
"d''" : 1820,
"dis''" : 1830,
"disis''" : 1840,
"eeses''" : 1850,
"ees''" : 1860,
"e''" : 1870,
"eis''" : 1880,
"eisis''" : 1890,
"feses''" : 1900,
"fes''" : 1910,
"f''" : 1920,
"fis''" : 1930,
"fisis''" : 1940,
"geses''" : 1950,
"ges''" : 1960,
"g''" : 1970,
"gis''" : 1980,
"gisis''" : 1990,
"aeses''" : 2000,
"aes''" : 2010,
"a''" : 2020,
"ais''" : 2030,
"aisis''" : 2040,
"beses''" : 2050,
"bes''" : 2060,
"b''" : 2070,
"bis''" : 2080,
"bisis''" : 2090,
"ceses'''" : 2100,
"ces'''" : 2110,
"c'''" : 2120,
"cis'''" : 2130,
"cisis'''" : 2140,
"deses'''" : 2150,
"des'''" : 2160,
"d'''" : 2170,
"dis'''" : 2180,
"disis'''" : 2190,
"eeses'''" : 2200,
"ees'''" : 2210,
"e'''" : 2220,
"eis'''" : 2230,
"eisis'''" : 2240,
"feses'''" : 2250,
"fes'''" : 2260,
"f'''" : 2270,
"fis'''" : 2280,
"fisis'''" : 2290,
"geses'''" : 2300,
"ges'''" : 2310,
"g'''" : 2320,
"gis'''" : 2330,
"gisis'''" : 2340,
"aeses'''" : 2350,
"aes'''" : 2360,
"a'''" : 2370,
"ais'''" : 2380,
"aisis'''" : 2390,
"beses'''" : 2400,
"bes'''" : 2410,
"b'''" : 2420,
"bis'''" : 2430,
"bisis'''" : 2440,
"ceses''''" : 2450,
"ces''''" : 2460,
"c''''" : 2470,
"cis''''" : 2480,
"cisis''''" : 2490,
"deses''''" : 2500,
"des''''" : 2510,
"d''''" : 2520,
"dis''''" : 2530,
"disis''''" : 2540,
"eeses''''" : 2550,
"ees''''" : 2560,
"e''''" : 2570,
"eis''''" : 2580,
"eisis''''" : 2590,
"feses''''" : 2600,
"fes''''" : 2610,
"f''''" : 2620,
"fis''''" : 2630,
"fisis''''" : 2640,
"geses''''" : 2650,
"ges''''" : 2660,
"g''''" : 2670,
"gis''''" : 2680,
"gisis''''" : 2690,
"aeses''''" : 2700,
"aes''''" : 2710,
"a''''" : 2720,
"ais''''" : 2730,
"aisis''''" : 2740,
"beses''''" : 2750,
"bes''''" : 2760,
"b''''" : 2770,
"bis''''" : 2780,
"bisis''''" : 2790,
"ceses'''''" : 2800,
"ces'''''" : 2810,
"c'''''" : 2820,
"cis'''''" : 2830,
"cisis'''''" : 2840,
"deses'''''" : 2850,
"des'''''" : 2860,
"d'''''" : 2870,
"dis'''''" : 2880,
"disis'''''" : 2890,
"eeses'''''" : 2900,
"ees'''''" : 2910,
"e'''''" : 2920,
"eis'''''" : 2930,
"eisis'''''" : 2940,
"feses'''''" : 2950,
"fes'''''" : 2960,
"f'''''" : 2970,
"fis'''''" : 2980,
"fisis'''''" : 2990,
"geses'''''" : 3000,
"ges'''''" : 3010,
"g'''''" : 3020,
"gis'''''" : 3030,
"gisis'''''" : 3040,
"aeses'''''" : 3050,
"aes'''''" : 3060,
"a'''''" : 3070,
"ais'''''" : 3080,
"aisis'''''" : 3090,
"beses'''''" : 3100,
"bes'''''" : 3110,
"b'''''" : 3120,
"bis'''''" : 3130,
"bisis'''''" : 3140,
#"r" : float('inf'), a rest is not a pitch
}
def plain(pitch):
""" Extract the note from a note-number, without any octave but with the tailing zero.
This means we double-use the lowest octave as abstract version."""
#Dividing through the octave, 350, results in the number of the octave and the note as remainder.
return divmod(pitch, 350)[1]
def octave(pitch):
"""Return the octave of given note. Lowest 0 is X,,,"""
return divmod(pitch, 350)[0]
def halfToneDistanceFromC(pitch):
"""Return the half-tone step distance from C. The "sounding" interval"""
return {
#00 : 10, # ceses,,, -> bes
#10 : 11, # ces,,, -> b
00 : -2, # ceses,,, -> bes
10 : -1, # ces,,, -> b
20 : 0, # c,,,
30 : 1, # cis,,,
40 : 2, # cisis,,, -> d ...
50 : 0, # deses,,,
60 : 1, # des,,,
70 : 2, # d,,,
80 : 3, # dis,,,
90 : 4, # disis,,,
100 : 2, # eeses,,,
110 : 3, # ees,,,
120 : 4, # e,,,
130 : 5, # eis,,,
140 : 6, # eisis,,,
150 : 3, # feses,,,
160 : 4, # fes,,,
170 : 5, # f,,,
180 : 6, # fis,,,
190 : 7, # fisis,,,
200 : 5, # geses,,,
210 : 6, # ges,,,
220 : 7, # g,,,
230 : 8, # gis,,,
240 : 9, # gisis,,,
250 : 7, # aeses,,,
260 : 8, # aes,,,
270 : 9, # a,,,
280 : 10, # ais,,,
290 : 11, # aisis,,,
300 : 9, # beses,,,
310 : 10, # bes,,,
320 : 11, # b,,,
330 : 12, # bis,,,
340 : 13, # bisis,,,
#330 : 0, # bis,,,
#340 : 1, # bisis,,,
}[plain(pitch)]
lyToMidi = {} #filled for all pitches on startup, below
for ly, pitch in ly2pitch.items():
octOffset = (octave(pitch) +1) * 12 #twelve tones per midi octave
lyToMidi[ly] = octOffset + halfToneDistanceFromC(pitch)
lyToTicks = {
"16" : D16,
"8" : D8,
"4" : D4,
"2" : D2,
"1" : D1,
}
def ly(lilypondString):
"""Take string of simple lilypond notes, return midi pitches as generator of (pitch, ticks)"""
lastDur = "4"
for lyNote in lilypondString.split(" "):
try:
lyPitch, lyDur = re.split(r'(\d+)', lyNote)[0:2]
lastDur = lyDur
except ValueError:
lyPitch = re.split(r'(\d+)', lyNote)[0]
lyDur = lastDur
yield (lyToMidi[lyPitch], lyToTicks[lyDur])
def ly2cbox(lilypondString):
"""Return (pbytes, durationInTicks)
a python byte data type with midi data for cbox"""
#cbox.Pattern.serialize_event(position, midibyte1 (noteon), midibyte2(pitch), midibyte3(velocity))
pblob = bytes()
startTick = 0
for midiPitch, durationInTicks in ly(lilypondString):
endTick = startTick + durationInTicks - 1 #-1 ticks to create a small logical gap. This is nothing compared to our tick value dimensions, but it is enough for the midi protocol to treat two notes as separate ones. Imporant to say that this does NOT affect the next note on. This will be mathematically correct anyway.
pblob += cbox.Pattern.serialize_event(startTick, 0x90, midiPitch, 100) # note on
pblob += cbox.Pattern.serialize_event(endTick , 0x80, midiPitch, 100) # note off
startTick = startTick + durationInTicks #no -1 for the next note
return pblob, startTick
cboxTracks = {} #trackName:(cboxTrack,cboxMidiOutUuid)
def cboxSetTrack(trackName, durationInTicks, pattern):
"""Creates or resets calfbox tracks including jack connections
Keeps jack connections alive.
pattern is most likely a single pattern created through cbox.Document.get_song().pattern_from_blob
But it can also be a list of such patterns. In this case all patterns must be the same duration
and the parameter durationInTicks is the length of ONE pattern.
"""
if not trackName in cboxTracks:
cboxMidiOutUuid = cbox.JackIO.create_midi_output(trackName)
calfboxTrack = cbox.Document.get_song().add_track()
cboxTracks[trackName] = (calfboxTrack, cboxMidiOutUuid)
else:
calfboxTrack, cboxMidiOutUuid = cboxTracks[trackName]
calfboxTrack.delete()
calfboxTrack = cbox.Document.get_song().add_track()
calfboxTrack.set_external_output(cboxMidiOutUuid)
cbox.JackIO.rename_midi_output(cboxMidiOutUuid, trackName)
calfboxTrack.set_name(trackName)
if type(pattern) is cbox.DocPattern:
calfboxTrack.add_clip(0, 0, durationInTicks, pattern) #pos, offset, length(and not end-position, but is the same for the complete track), pattern
else: #iterable
assert iter(pattern)
#durationInTicks is the length of ONE pattern.
for i, pat in enumerate(pattern):
calfboxTrack.add_clip(i*durationInTicks, 0, durationInTicks, pat) #pos, offset, length, pattern.
calfboxTrack.add_clip(i*durationInTicks, 0, durationInTicks, pat) #pos, offset, length, pattern.
return calfboxTrack
def ly2Track(trackName, lyString):
"""Convert a simple string of lilypond notes to a cbox track and add that to the score"""
music = lyString
cboxBlob, durationInTicks = ly2cbox(music)
pattern = cbox.Document.get_song().pattern_from_blob(cboxBlob, durationInTicks)
cboxSetTrack(trackName, durationInTicks, pattern)
def getLongestTrackDuationInTicks():
return max( max(clip.pos + clip.length for clip in cboxTrack.track.status().clips) for cboxTrack in cbox.Document.get_song().status().tracks if cboxTrack.track.status().clips)
#for cboxTrack in cbox.Document.get_song().status().tracks:
# print (cboxTrack.track)
#TODO: These are different than the one above. It is more. Why?
#for cboxTrack, cboxMidiOutUuid in cboxTracks.values():
# print (cboxTrack.status())
def cboxLoop(eventLoop):
cbox.call_on_idle()
assert eventLoop.is_running()
#it is not that simple. status = "[Running]" if cbox.Transport.status().playing else "[Stopped]"
if cbox.Transport.status().playing == 1:
status = "[Running]"
elif cbox.Transport.status().playing == 0:
status = "[Stopped]"
elif cbox.Transport.status().playing == 2:
status = "[Stopping]"
elif cbox.Transport.status().playing is None:
status = "[Uninitialized]"
else:
raise ValueError("Unknown playback status: {}".format(cbox.Transport.status().playing))
stdout.write(" \r") #it is a hack but it cleans the line from old artefacts
stdout.write('{}: {}\r'.format(status, cbox.Transport.status().pos_ppqn))
stdout.flush()
eventLoop.call_later(0.1, cboxLoop, eventLoop) #100ms delay
eventLoop = get_event_loop()
def initCbox(clientName, internalEventProcessor=True, commonMidiInput=True):
cbox.init_engine("")
cbox.Config.set("io", "client_name", clientName)
cbox.Config.set("io", "enable_common_midi_input", commonMidiInput) #the default "catch all" midi input
cbox.start_audio()
scene = cbox.Document.get_engine().new_scene()
scene.clear()
cbox.do_cmd("/master/set_ppqn_factor", None, [D4]) #quarter note has how many ticks?
cbox.Transport.stop()
cbox.Transport.seek_ppqn(0)
cbox.Transport.set_tempo(120.0) #must be float
if internalEventProcessor:
eventLoop.call_soon(cboxLoop, eventLoop)
return scene, cbox, eventLoop
def connectPhysicalKeyboards(port="midi"):
midiKeyboards = cbox.JackIO.get_ports(".*", cbox.JackIO.MIDI_TYPE, cbox.JackIO.PORT_IS_SOURCE | cbox.JackIO.PORT_IS_PHYSICAL)
ourMidiInPort = cbox.Config.get("io", "client_name",) + ":" + port
for keyboard in midiKeyboards:
cbox.JackIO.port_connect(keyboard, ourMidiInPort)
def start(autoplay = False, userfunction = None, tempo = 120):
def ask_exit():
print()
eventLoop.stop()
shutdownCbox()
try:
dur = getLongestTrackDuationInTicks()
print("Starting with supplied music data. Setting sond duration to longest track")
assert dur > 0
cbox.Document.get_song().set_loop(dur, dur) #set playback length for the entire score.
except ValueError:
print ("Starting without a track. Setting song duration to a high value to generate recording space")
cbox.Document.get_song().set_loop(MAXIMUM, MAXIMUM) #set playback length for the entire score.
cbox.Transport.set_tempo(float(tempo))
cbox.Document.get_song().update_playback()
for signame in ('SIGINT', 'SIGTERM'):
eventLoop.add_signal_handler(getattr(signal, signame), ask_exit)
if userfunction:
print ("Send SIGUSR1 with following command to trigger user function")
print ("kill -10 {}".format(os.getpid()))
print ()
eventLoop.add_signal_handler(getattr(signal, "SIGUSR1"), userfunction)
print ("Use jack transport to control playback")
print ("Press Ctrl+C to abort")
print("pid %s: send SIGINT or SIGTERM to exit." % os.getpid())
try:
eventLoop.run_forever()
finally:
eventLoop.close()
def shutdownCbox():
cbox.Transport.stop()
cbox.Transport.seek_ppqn(0)
cbox.stop_audio()
cbox.shutdown_engine()

51
template/calfbox/experiments/playPatternsAsMeasures.py

@ -1,51 +0,0 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright, Nils Hilbricht, Germany ( https://www.hilbricht.net )
This code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from meta import ly2cbox, cboxSetTrack, initCbox, start, D4
scene, cbox, eventLoop = initCbox("test02")
#Generate Music
music = "c'4 d' e' f'"
cboxBlob, durationInTicks = ly2cbox(music)
#cboxSetTrack("someInstrument", durationInTicks, pattern)
oneMeasureInTicks = D4 * 4
patternList = [
cbox.Document.get_song().pattern_from_blob(cboxBlob, durationInTicks),
cbox.Document.get_song().pattern_from_blob(cboxBlob, durationInTicks),
cbox.Document.get_song().pattern_from_blob(cboxBlob, durationInTicks),
cbox.Document.get_song().pattern_from_blob(cboxBlob, durationInTicks),
cbox.Document.get_song().pattern_from_blob(cboxBlob, durationInTicks),
cbox.Document.get_song().pattern_from_blob(cboxBlob, durationInTicks),
cbox.Document.get_song().pattern_from_blob(cboxBlob, durationInTicks),
cbox.Document.get_song().pattern_from_blob(cboxBlob, durationInTicks),
]
cboxSetTrack("metronome", oneMeasureInTicks, patternList)
def userfunction():
D4 = 210 * 2**8
MEASURE = 4 * D4
cbox.Transport.stop()
cbox.Document.get_song().update_playback()
cbox.Transport.seek_ppqn(4 * MEASURE + 2 * D4 ) #4th measure in the middle
cbox.Transport.play()
start(userfunction=userfunction)

32
template/calfbox/experiments/printAllMidiEvents.py

@ -1,32 +0,0 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright, Nils Hilbricht, Germany ( https://www.hilbricht.net )
This code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from meta import initCbox, start, connectPhysicalKeyboards
def processMidiIn(eventLoop):
eventList = cbox.get_new_events()
if eventList:
for (address, uninterestingStuff, event) in eventList: #we are only interested in the event, which is a list again.
print (address, "event:", event, "playback:", cbox.Transport.status().playing)
eventLoop.call_later(0.1, processMidiIn, eventLoop)
scene, cbox, eventLoop = initCbox("test01", internalEventProcessor=False)
eventLoop.call_later(0.1, processMidiIn, eventLoop) #100ms
connectPhysicalKeyboards()
start()

35
template/calfbox/experiments/printAllMidiEventsSpecificPort.py

@ -1,35 +0,0 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright, Nils Hilbricht, Germany ( https://www.hilbricht.net )
This code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from meta import initCbox, start, connectPhysicalKeyboards
def processMidiIn(eventLoop):
eventList = cbox.JackIO.get_new_events(cboxMidiPortUid)
if eventList:
for (address, uninterestingStuff, event) in eventList: #we are only interested in the event, which is a list again.
print (address, "event:", event, "playback:", cbox.Transport.status().playing)
eventLoop.call_later(0.1, processMidiIn, eventLoop)
scene, cbox, eventLoop = initCbox("test01", internalEventProcessor=False, commonMidiInput=False)
cboxMidiPortUid = cbox.JackIO.create_midi_input("customInput")
cbox.JackIO.set_appsink_for_midi_input(cboxMidiPortUid, True) #This sounds like a program wide sink, but it is needed for every port.
cbox.JackIO.route_midi_input(cboxMidiPortUid, scene.uuid)
eventLoop.call_later(0.1, processMidiIn, eventLoop) #100ms
connectPhysicalKeyboards(port="customInput")
start()

79
template/calfbox/experiments/printNotesOnlyDuringPlayback.py

@ -1,79 +0,0 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
from meta import ly2Track, initCbox, start, connectPhysicalKeyboards
def processMidiIn(eventLoop):
"""cbox event: ("event address", None, [firstByte, pitch, velocit])
Cbox event come in pairs
first is the normal midi-event + channel
channel = first & 0x0F
mode = first & 0xF0
Of course it doesn't need to be pitch and velocity.
But this is easier to document than "data2, data3"
Either call cbox.call_on_idle or cbox.get_new_events.
Both will clean the event queue but only the latter will give us
the results as python data.
"""
eventList = cbox.get_new_events()
lenList = len(eventList)
if lenList >= 2 and lenList % 2 == 0:
for (address, uninterestingStuff, event) in eventList: #we are only interested in the event, which is a list again.
#print (address, "event:", event, "playback:", cbox.Transport.status().playing)
if address in ("/io/midi/event_time_samples", "/io/midi/event_time_ppqn", ):
assert len(event) == 1
#We are very strict at the moment. A timestamp is only allowed if there wasn't another timestamp waiting. It is strict because only simple_event with len==3 eat up the timestamp. Any other event will trigger an error.
if processMidiIn.lastTimestamp:
raise NotImplementedError("the previous event didn't eat up the timestamp")
else:
if address == "/io/midi/event_time_ppqn":
assert cbox.Transport.status().playing == 1
during_recording = True
else:
assert not cbox.Transport.status().playing == 1
during_recording = False
processMidiIn.lastTimestamp = event[0]
elif address == "/io/midi/simple_event" and len(event) == 3: #we can only unpack the event after knowing its length.
assert processMidiIn.lastTimestamp # Midi events are always preceded by timestamps
first, second, third = event
channel = first & 0x0F
mode = first & 0xF0 #0x90 note on, 0x80 note off and so on.
if mode == 0x90: #Note On. 144 in decimal
midipitch = second
velocity = third
if during_recording:
print("ON: {}, Channel: {}, Pitch: {}, Velocity: {}".format(processMidiIn.lastTimestamp, channel, midipitch, velocity))
#else:
# print("ON Time-Samples: {}, Channel: {}, Pitch: {}, Velocity: {}".format(processMidiIn.lastTimestamp, channel, midipitch, velocity))
elif mode == 0x80: #Note Off. 128 in decimal
midipitch = second
velocity = third
if during_recording:
print("OFF: {}, Channel: {}, Pitch: {}, Velocity: {}".format(processMidiIn.lastTimestamp, channel, midipitch, velocity))
#elif mode == 0xB0: #CC
# ccNumber = second
# ccValue = third
#else:
#discard the events
processMidiIn.lastTimestamp = None
else:
raise NotImplementedError("Address type {} unknown".format(address))
eventLoop.call_later(0.1, processMidiIn, eventLoop)
processMidiIn.lastTimestamp = None
scene, cbox, eventLoop = initCbox("test01", internalEventProcessor=False)
#ly2Track(trackName="doWeNeedThis", lyString="c8")
eventLoop.call_later(0.1, processMidiIn, eventLoop) #100ms
connectPhysicalKeyboards()
start()

30
template/calfbox/experiments/simplePlayback.py

@ -1,30 +0,0 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright, Nils Hilbricht, Germany ( https://www.hilbricht.net )
This code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from meta import ly2cbox, cboxSetTrack, initCbox, start
scene, cbox, eventLoop = initCbox("test01")
#Generate Music
music = "c'4 d' e' f'2 g' c''"
cboxBlob, durationInTicks = ly2cbox(music)
pattern = cbox.Document.get_song().pattern_from_blob(cboxBlob, durationInTicks)
cboxSetTrack("someInstrument", durationInTicks, pattern)
start()

25
template/calfbox/experiments/simplerPlayback.py

@ -1,25 +0,0 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright, Nils Hilbricht, Germany ( https://www.hilbricht.net )
This code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from meta import ly2Track, initCbox, start
scene, cbox, eventLoop = initCbox("test01")
ly2Track(trackName="someInstrument", lyString="c'4 d' e' f'2 g' c''")
start()

82
template/calfbox/experiments/testmetadata.py

@ -1,82 +0,0 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
This is a minimal calfbox python example. It is meant as a starting
point to find bugs and test performance.
Copyright, Nils Hilbricht, Germany ( https://www.hilbricht.net )
This code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import atexit
from pprint import pprint
from calfbox import cbox
cbox.init_engine("")
cbox.Config.set("io", "outputs", 8)
NAME = "Cbox Interactive"
cbox.Config.set("io", "client_name", NAME)
cbox.start_audio()
scene = cbox.Document.get_engine().new_scene()
scene.clear()
print("Setting nonsense meta data to our first two ports and midi port")
cbox.JackIO.Metadata.set_property("Cbox Interactive:out_1", "foo", "bar")
cbox.JackIO.Metadata.set_property("Cbox Interactive:out_1", "faz", "baz")
cbox.JackIO.Metadata.set_property("Cbox Interactive:out_2", "rolf", "hello")
cbox.JackIO.Metadata.set_property("Cbox Interactive:out_2", "rolf", "hello")
cbox.JackIO.Metadata.set_property("Cbox Interactive:midi", "wolf", "world", "stryng")
cbox.JackIO.Metadata.set_property("Cbox Interactive:midi", "asd", "qwe", "")
print ("Setting port order for all 8 ports")
portOrderDict = {
"Cbox Interactive:out_1": 50,
"Cbox Interactive:out_2": 40,
"Cbox Interactive:out_3": 3,
"Cbox Interactive:out_4": 5,
"Cbox Interactive:out_5": 7,
"Cbox Interactive:out_6": 999,
"Cbox Interactive:out_7": 4,
"Cbox Interactive:out_8": 4,
}
try:
cbox.JackIO.Metadata.set_all_port_order(portOrderDict)
print ("Test to catch non-unique indices failed!. Quitting")
quit()
except ValueError as e:
print ("Caught expected ValueError for double index entry.\nAdjusting value and try again to set all ports.")
portOrderDict["Cbox Interactive:out_8"] = 0
cbox.JackIO.Metadata.set_all_port_order(portOrderDict)
print("List of all metadata follows")
pprint (cbox.JackIO.Metadata.get_all_properties())
print()
print ("Now check your port order in QJackCtl or similar. Press [Return] to quit")
input() #wait for key to confirm order visually in qjackctl
quit()
def exit_handler():
#Restore initial state and stop the engine
cbox.Transport.stop()
cbox.stop_audio()
cbox.shutdown_engine()
atexit.register(exit_handler)

373
template/calfbox/fbr.c

@ -1,373 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "biquad-float.h"
#include "config.h"
#include "config-api.h"
#include "dspmath.h"
#include "eq.h"
#include "module.h"
#include "rt.h"
#include <complex.h>
#include <glib.h>
#include <malloc.h>
#include <math.h>
#include <memory.h>
#include <sndfile.h>
#include <stdio.h>
#include <stdlib.h>
#define MODULE_PARAMS feedback_reducer_params
#define MAX_FBR_BANDS 16
#define ANALYSIS_BUFFER_SIZE 8192
#define ANALYSIS_BUFFER_BITS 13
// Sine table
static complex float euler_table[ANALYSIS_BUFFER_SIZE];
// Bit reversal table
static int map_table[ANALYSIS_BUFFER_SIZE];
// Bit-reversed von Hann window
static float von_hann_window_transposed[ANALYSIS_BUFFER_SIZE];
struct feedback_reducer_params
{
struct eq_band bands[MAX_FBR_BANDS];
};
struct feedback_reducer_module
{
struct cbox_module module;
struct feedback_reducer_params *params, *old_params;
struct cbox_biquadf_coeffs coeffs[MAX_FBR_BANDS];
struct cbox_biquadf_state state[MAX_FBR_BANDS][2];
float analysis_buffer[ANALYSIS_BUFFER_SIZE];
float *wrptr;
int analysed;
complex float fft_buffers[2][ANALYSIS_BUFFER_SIZE];
};
// Trivial implementation of Cooley-Tukey (+ my own mistakes) + von Hann window
static int do_fft(struct feedback_reducer_module *m)
{
// Copy + bit reversal addressing
for (int i = 0; i < ANALYSIS_BUFFER_SIZE; i++)
{
m->fft_buffers[0][i] = von_hann_window_transposed[i] * m->analysis_buffer[map_table[i]] * (2.0 / ANALYSIS_BUFFER_SIZE);
}
for (int i = 0; i < ANALYSIS_BUFFER_BITS; i++)
{
complex float *src = m->fft_buffers[i & 1];
complex float *dst = m->fft_buffers[(~i) & 1];
int invi = ANALYSIS_BUFFER_BITS - i - 1;
int disp = 1 << i;
int mask = disp - 1;
for (int j = 0; j < ANALYSIS_BUFFER_SIZE / 2; j++)
{
int jj1 = (j & mask) + ((j & ~mask) << 1); // insert 0 at i'th bit to get the left arm of the butterfly
int jj2 = jj1 + disp; // insert 1 at i'th bit to get the right arm
// e^iw
complex float eiw1 = euler_table[(jj1 << invi) & (ANALYSIS_BUFFER_SIZE - 1)];
complex float eiw2 = euler_table[(jj2 << invi) & (ANALYSIS_BUFFER_SIZE - 1)];
// printf("%d -> %d, %d\n", j, jj, jj + disp);
butterfly(&dst[jj1], &dst[jj2], src[jj1], src[jj2], eiw1, eiw2);
}
}
return ANALYSIS_BUFFER_BITS & 1;
}
#define PEAK_REGION_RADIUS 3
struct potential_peak_info
{
int bin;
float avg;
float centre;
float peak;
float dist;
float points;
};
static int peak_compare(const void *peak1, const void *peak2)
{
const struct potential_peak_info *pi1 = peak1;
const struct potential_peak_info *pi2 = peak2;
if (pi1->points < pi2->points)
return +1;
if (pi1->points > pi2->points)
return -1;
return 0;
}
static int find_peaks(complex float *spectrum, float srate, float peak_freqs[16])
{
struct potential_peak_info pki[ANALYSIS_BUFFER_SIZE / 2 + 1];
for (int i = 0; i <= ANALYSIS_BUFFER_SIZE / 2; i++)
{
pki[i].bin = i;
pki[i].points = 0.f;
}
float gmax = 0;
for (int i = PEAK_REGION_RADIUS; i <= ANALYSIS_BUFFER_SIZE / 2 - PEAK_REGION_RADIUS; i++)
{
struct potential_peak_info *pi = &pki[i];
float sum = 0;
float sumf = 0;
float peak = 0;
for (int j = -PEAK_REGION_RADIUS; j <= PEAK_REGION_RADIUS; j++)
{
float f = (i + j);
float bin = cabs(spectrum[i + j]);
if (bin > peak)
peak = bin;
sum += bin;
sumf += f * bin;
}
pi->avg = sum / (2 * PEAK_REGION_RADIUS + 1);
pi->peak = peak;
pi->centre = sumf / sum;
pi->dist = (sumf / sum - i);
if (peak > gmax)
gmax = peak;
// printf("Bin %d sumf/sum %f avg %f peak %f p/a %f dist %f val %f\n", i, sumf / sum, pki[i].avg, peak, peak / pki[i].avg, sumf/sum - i, cabs(spectrum[i]));
}
for (int i = PEAK_REGION_RADIUS; i <= ANALYSIS_BUFFER_SIZE / 2 - PEAK_REGION_RADIUS; i++)
{
struct potential_peak_info *tpi = &pki[i];
// ignore peaks below -40dB of the max bin
if (pki[(int)tpi->centre].peak < gmax * 0.01)
continue;
pki[(int)tpi->centre].points += 1;
}
#if 0
for (int i = 0; i <= ANALYSIS_BUFFER_SIZE / 2; i++)
{
float freq = i * srate / ANALYSIS_BUFFER_SIZE;
printf("Bin %d freq %f points %f\n", i, freq, pki[i].points);
}
#endif
qsort(pki, ANALYSIS_BUFFER_SIZE / 2 + 1, sizeof(struct potential_peak_info), peak_compare);
float peaks[16];
int peak_count = 0;
for (int i = 0; i <= ANALYSIS_BUFFER_SIZE / 2; i++)
{
if (pki[i].points <= 1)
break;
if (pki[i].peak <= 0.0001)
break;
gboolean dupe = FALSE;
for (int j = 0; j < peak_count; j++)
{
if (fabs(peaks[j] - pki[i].centre) < PEAK_REGION_RADIUS)
{
dupe = TRUE;
break;
}
}
if (dupe)
continue;
peak_freqs[peak_count] = pki[i].centre * srate / ANALYSIS_BUFFER_SIZE;
peaks[peak_count++] = pki[i].centre;
printf("Mul %f freq %f points %f peak %f\n", pki[i].centre, pki[i].centre * srate / ANALYSIS_BUFFER_SIZE, pki[i].points, pki[i].peak);
if (peak_count == 4)
break;
}
return peak_count;
}
static void redo_filters(struct feedback_reducer_module *m)
{
for (int i = 0; i < MAX_FBR_BANDS; i++)
{
struct eq_band *band = &m->params->bands[i];
if (band->active)
{
cbox_biquadf_set_peakeq_rbj(&m->coeffs[i], band->center, band->q, band->gain, m->module.srate);
}
}
m->old_params = m->params;
}
gboolean feedback_reducer_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
struct feedback_reducer_module *m = (struct feedback_reducer_module *)ct->user_data;
EFFECT_PARAM_ARRAY("/active", "i", bands, active, int, , 0, 1) else
EFFECT_PARAM_ARRAY("/center", "f", bands, center, double, , 10, 20000) else
EFFECT_PARAM_ARRAY("/q", "f", bands, q, double, , 0.01, 100) else
EFFECT_PARAM_ARRAY("/gain", "f", bands, gain, double, dB2gain_simple, -100, 100) else
if (!strcmp(cmd->command, "/start") && !strcmp(cmd->arg_types, ""))
{
m->analysed = 0;
cbox_rt_swap_pointers(m->module.rt, (void **)&m->wrptr, m->analysis_buffer);
}
else if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
if (m->wrptr == m->analysis_buffer + ANALYSIS_BUFFER_SIZE && m->analysed == 0)
{
float freqs[16];
int count = find_peaks(m->fft_buffers[do_fft(m)], m->module.srate, freqs);
struct feedback_reducer_params *p = malloc(sizeof(struct feedback_reducer_params));
memcpy(p->bands + count, &m->params->bands[0], sizeof(struct eq_band) * (MAX_FBR_BANDS - count));
for (int i = 0; i < count; i++)
{
p->bands[i].active = TRUE;
p->bands[i].center = freqs[i];
p->bands[i].q = freqs[i] / 50; // each band ~100 Hz (not really sure about filter Q vs bandwidth)
p->bands[i].gain = 0.125;
}
free(cbox_rt_swap_pointers(m->module.rt, (void **)&m->params, p)); \
m->analysed = 1;
if (!cbox_execute_on(fb, NULL, "/refresh", "i", error, 1))
return FALSE;
}
if (!cbox_execute_on(fb, NULL, "/finished", "i", error, m->analysed))
return FALSE;
for (int i = 0; i < MAX_FBR_BANDS; i++)
{
if (!cbox_execute_on(fb, NULL, "/active", "ii", error, i, (int)m->params->bands[i].active))
return FALSE;
if (!cbox_execute_on(fb, NULL, "/center", "if", error, i, m->params->bands[i].center))
return FALSE;
if (!cbox_execute_on(fb, NULL, "/q", "if", error, i, m->params->bands[i].q))
return FALSE;
if (!cbox_execute_on(fb, NULL, "/gain", "if", error, i, gain2dB_simple(m->params->bands[i].gain)))
return FALSE;
}
// return cbox_execute_on(fb, NULL, "/wet_dry", "f", error, m->params->wet_dry);
return CBOX_OBJECT_DEFAULT_STATUS(&m->module, fb, error);
}
else
return cbox_object_default_process_cmd(ct, fb, cmd, error);
return TRUE;
}
void feedback_reducer_process_event(struct cbox_module *module, const uint8_t *data, uint32_t len)
{
// struct feedback_reducer_module *m = module->user_data;
}
void feedback_reducer_process_block(struct cbox_module *module, cbox_sample_t **inputs, cbox_sample_t **outputs)
{
struct feedback_reducer_module *m = module->user_data;
if (m->params != m->old_params)
redo_filters(m);
if (m->wrptr && m->wrptr != m->analysis_buffer + ANALYSIS_BUFFER_SIZE)
{
for (int i = 0; i < CBOX_BLOCK_SIZE; i++)
{
if (m->wrptr == m->analysis_buffer + ANALYSIS_BUFFER_SIZE)
break;
*m->wrptr++ = inputs[0][i] + inputs[1][i];
}
}
for (int c = 0; c < 2; c++)
{
gboolean first = TRUE;
for (int i = 0; i < MAX_FBR_BANDS; i++)
{
if (!m->params->bands[i].active)
continue;
if (first)
{
cbox_biquadf_process_to(&m->state[i][c], &m->coeffs[i], inputs[c], outputs[c]);
first = FALSE;
}
else
{
cbox_biquadf_process(&m->state[i][c], &m->coeffs[i], outputs[c]);
}
}
if (first)
memcpy(outputs[c], inputs[c], sizeof(float) * CBOX_BLOCK_SIZE);
}
}
MODULE_SIMPLE_DESTROY_FUNCTION(feedback_reducer)
MODULE_CREATE_FUNCTION(feedback_reducer)
{
static int inited = 0;
if (!inited)
{
for (int i = 0; i < ANALYSIS_BUFFER_SIZE; i++)
{
euler_table[i] = cos(i * 2 * M_PI / ANALYSIS_BUFFER_SIZE) + I * sin(i * 2 * M_PI / ANALYSIS_BUFFER_SIZE);
int ni = 0;
for (int j = 0; j < ANALYSIS_BUFFER_BITS; j++)
{
if (i & (1 << (ANALYSIS_BUFFER_BITS - 1 - j)))
ni = ni | (1 << j);
}
map_table[i] = ni;
von_hann_window_transposed[i] = 0.5 * (1 - cos (ni * 2 * M_PI / (ANALYSIS_BUFFER_SIZE - 1)));
}
inited = 1;
}
struct feedback_reducer_module *m = malloc(sizeof(struct feedback_reducer_module));
CALL_MODULE_INIT(m, 2, 2, feedback_reducer);
m->module.process_event = feedback_reducer_process_event;
m->module.process_block = feedback_reducer_process_block;
struct feedback_reducer_params *p = malloc(sizeof(struct feedback_reducer_params));
m->params = p;
m->old_params = NULL;
m->analysed = 0;
m->wrptr = NULL;
for (int b = 0; b < MAX_FBR_BANDS; b++)
{
p->bands[b].active = cbox_eq_get_band_param(cfg_section, b, "active", 0) > 0;
p->bands[b].center = cbox_eq_get_band_param(cfg_section, b, "center", 50 * pow(2.0, b / 2.0));
p->bands[b].q = cbox_eq_get_band_param(cfg_section, b, "q", 0.707 * 2);
p->bands[b].gain = cbox_eq_get_band_param_db(cfg_section, b, "gain", 0);
}
redo_filters(m);
cbox_eq_reset_bands(m->state, MAX_FBR_BANDS);
return &m->module;
}
struct cbox_module_keyrange_metadata feedback_reducer_keyranges[] = {
};
struct cbox_module_livecontroller_metadata feedback_reducer_controllers[] = {
};
DEFINE_MODULE(feedback_reducer, 2, 2)

22
template/calfbox/fifo.c

@ -1,22 +0,0 @@
#include "fifo.h"
#include <malloc.h>
struct cbox_fifo *cbox_fifo_new(uint32_t size)
{
struct cbox_fifo *fifo = calloc(1, sizeof(struct cbox_fifo) + size);
if (!fifo)
return NULL;
fifo->data = (uint8_t *)(fifo + 1);
fifo->size = size;
fifo->write_count = 0;
fifo->write_offset= 0;
fifo->read_count = 0;
fifo->read_offset = 0;
return fifo;
}
void cbox_fifo_destroy(struct cbox_fifo *fifo)
{
free(fifo);
}

136
template/calfbox/fifo.h

@ -1,136 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2013 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_FIFO_H
#define CBOX_FIFO_H
#include <assert.h>
#include <stdint.h>
#include <glib.h>
#include <string.h>
struct cbox_fifo
{
uint8_t *data;
uint32_t size;
uint64_t pad; // ensure the write-related and read-related structs are on 64 bit boundary
uint32_t write_count;
uint32_t write_offset;
uint32_t read_count;
uint32_t read_offset;
};
extern struct cbox_fifo *cbox_fifo_new(uint32_t size);
static inline uint32_t cbox_fifo_readsize(struct cbox_fifo *fifo);
static inline uint32_t cbox_fifo_writespace(struct cbox_fifo *fifo);
static inline gboolean cbox_fifo_read_atomic(struct cbox_fifo *fifo, void *dest, uint32_t bytes);
static inline gboolean cbox_fifo_write_atomic(struct cbox_fifo *fifo, const void *src, uint32_t bytes);
static inline gboolean cbox_fifo_peek(struct cbox_fifo *fifo, void *dest, uint32_t bytes);
static inline gboolean cbox_fifo_consume(struct cbox_fifo *fifo, uint32_t bytes);
extern void cbox_fifo_destroy(struct cbox_fifo *fifo);
static inline uint32_t cbox_fifo_readsize(struct cbox_fifo *fifo)
{
return fifo->write_count - fifo->read_count;
}
static inline uint32_t cbox_fifo_writespace(struct cbox_fifo *fifo)
{
return fifo->size - (fifo->write_count - fifo->read_count);
}
static inline gboolean cbox_fifo_read_impl(struct cbox_fifo *fifo, void *dest, uint32_t bytes, gboolean advance)
{
__sync_synchronize();
if (fifo->write_count - fifo->read_count < bytes)
return FALSE;
if (dest)
{
uint32_t ofs = fifo->read_count - fifo->read_offset;
assert(ofs >= 0 && ofs < fifo->size);
if (ofs + bytes > fifo->size)
{
uint8_t *dstb = dest;
uint32_t firstpart = fifo->size - ofs;
memcpy(dstb, fifo->data + ofs, firstpart);
memcpy(dstb + firstpart, fifo->data, bytes - firstpart);
}
else
memcpy(dest, fifo->data + ofs, bytes);
}
if (advance)
{
__sync_synchronize();
// Make sure data are copied before signalling that they can be overwritten
fifo->read_count += bytes;
if (fifo->read_count - fifo->read_offset >= fifo->size)
fifo->read_offset += fifo->size;
}
__sync_synchronize();
return TRUE;
}
static inline gboolean cbox_fifo_read_atomic(struct cbox_fifo *fifo, void *dest, uint32_t bytes)
{
return cbox_fifo_read_impl(fifo, dest, bytes, TRUE);
}
static inline gboolean cbox_fifo_peek(struct cbox_fifo *fifo, void *dest, uint32_t bytes)
{
return cbox_fifo_read_impl(fifo, dest, bytes, FALSE);
}
static inline gboolean cbox_fifo_consume(struct cbox_fifo *fifo, uint32_t bytes)
{
return cbox_fifo_read_impl(fifo, NULL, bytes, TRUE);
}
static inline gboolean cbox_fifo_write_atomic(struct cbox_fifo *fifo, const void *src, uint32_t bytes)
{
if (fifo->size - (fifo->write_count - fifo->read_count) < bytes)
return FALSE;
uint32_t ofs = fifo->write_count - fifo->write_offset;
assert(ofs >= 0 && ofs < fifo->size);
if (ofs + bytes > fifo->size)
{
const uint8_t *srcb = src;
uint32_t firstpart = fifo->size - ofs;
memcpy(fifo->data + ofs, srcb, firstpart);
memcpy(fifo->data, srcb + firstpart, bytes - firstpart);
}
else
memcpy(fifo->data + ofs, src, bytes);
// Make sure data are in the buffer before announcing the availability
__sync_synchronize();
fifo->write_count += bytes;
if (fifo->write_count - fifo->write_offset >= fifo->size)
fifo->write_offset += fifo->size;
return TRUE;
}
#endif

444
template/calfbox/fluid.c

@ -1,444 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#if USE_FLUIDSYNTH
#include "config-api.h"
#include "dspmath.h"
#include "module.h"
#include <glib.h>
#include <math.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <fluidsynth.h>
#include <fluidsynth/sfont.h>
#include <fluidsynth/synth.h>
#include <fluidsynth/types.h>
#if FLUIDSYNTH_VERSION_MAJOR < 2
typedef unsigned int cbox_fluidsynth_id_t;
#define fluid_sfont_iteration_setup() fluid_preset_t sfont_iterator;
#define fluid_sfont_iteration_start(sfont) (sfont)->iteration_start(sfont)
#define fluid_sfont_iteration_next(sfont) (sfont)->iteration_next(sfont, &sfont_iterator) ? &sfont_iterator : NULL
#define fluid_preset_get_num(preset) (preset)->get_num(preset)
#define fluid_preset_get_banknum(preset) (preset)->get_banknum(preset)
#define fluid_preset_get_name(preset) (preset)->get_name(preset)
#else
typedef int cbox_fluidsynth_id_t;
#define fluid_sfont_iteration_setup()
#endif
#define CBOX_FLUIDSYNTH_ERROR cbox_fluidsynth_error_quark()
enum CboxFluidsynthError
{
CBOX_FLUIDSYNTH_ERROR_FAILED,
};
GQuark cbox_fluidsynth_error_quark(void)
{
return g_quark_from_string("cbox-fluidsynth-error-quark");
}
static void fluidsynth_process_block(struct cbox_module *module, cbox_sample_t **inputs, cbox_sample_t **outputs);
static void fluidsynth_process_event(struct cbox_module *module, const uint8_t *data, uint32_t len);
static gboolean fluidsynth_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error);
static void fluidsynth_destroyfunc(struct cbox_module *module);
struct fluidsynth_module
{
struct cbox_module module;
fluid_settings_t *settings;
fluid_synth_t *synth;
char *bank_name;
int sfid;
int output_pairs;
int is_multi;
#if OLD_FLUIDSYNTH
float **left_outputs, **right_outputs;
#endif
GString *error_log;
};
static gboolean select_patch_by_name(struct fluidsynth_module *m, int channel, const gchar *preset, GError **error)
{
fluid_sfont_t* sfont = fluid_synth_get_sfont(m->synth, 0);
fluid_preset_t* tmp;
fluid_sfont_iteration_setup();
fluid_sfont_iteration_start(sfont);
while((tmp = fluid_sfont_iteration_next(sfont)) != NULL)
{
// trailing spaces are common in some SF2s
const char *pname = fluid_preset_get_name(tmp);
int len = strlen(pname);
while (len > 0 && pname[len - 1] == ' ')
len--;
if (!strncmp(pname, preset, len) && preset[len] == '\0')
{
fluid_synth_program_select(m->synth, channel, m->sfid, fluid_preset_get_banknum(tmp), fluid_preset_get_num(tmp));
return TRUE;
}
}
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Preset not found: %s", preset);
return FALSE;
}
static void cbox_fluidsynth_log_write(int level, const char *message, void *data)
{
struct fluidsynth_module *m = data;
if (!m->error_log)
m->error_log = g_string_new(message);
else
g_string_append(m->error_log, message);
g_string_append_c(m->error_log, '\n');
}
static gboolean load_soundfont(struct fluidsynth_module *m, const char *bank_name, GError **error)
{
g_message("Loading soundfont %s", bank_name);
int result = fluid_synth_sfload(m->synth, bank_name, 1);
if (result == FLUID_FAILED)
{
char *error_msg = g_string_free(m->error_log, FALSE);
m->error_log = NULL;
g_set_error(error, CBOX_FLUIDSYNTH_ERROR, CBOX_FLUIDSYNTH_ERROR_FAILED, "Failed to load the SF2 bank %s: %s", bank_name, error_msg);
g_free(error_msg);
return FALSE;
}
m->bank_name = g_strdup(bank_name);
m->sfid = result;
return TRUE;
}
MODULE_CREATE_FUNCTION(fluidsynth)
{
int i;
const char *bankname = cbox_config_get_string(cfg_section, "sf2");
static int inited = 0;
if (!inited)
{
inited = 1;
}
struct fluidsynth_module *m = malloc(sizeof(struct fluidsynth_module));
int pairs = cbox_config_get_int(cfg_section, "output_pairs", 0);
m->output_pairs = pairs ? pairs : 1;
m->is_multi = pairs > 0;
if (m->output_pairs < 1 || m->output_pairs > 16)
{
free(m);
g_set_error(error, CBOX_FLUIDSYNTH_ERROR, CBOX_FLUIDSYNTH_ERROR_FAILED, "Invalid number of output pairs (found %d, supported range 1-16)", m->output_pairs);
return NULL;
}
if (pairs == 0)
{
CALL_MODULE_INIT(m, 0, 2 * m->output_pairs, fluidsynth);
#if OLD_FLUIDSYNTH
m->left_outputs = NULL;
m->right_outputs = NULL;
#endif
}
else
{
g_message("Multichannel mode enabled, %d output pairs, 2 effects", m->output_pairs);
CALL_MODULE_INIT(m, 0, 2 * m->output_pairs + 4, fluidsynth);
#if OLD_FLUIDSYNTH
m->left_outputs = malloc(sizeof(float *) * (m->output_pairs + 2));
m->right_outputs = malloc(sizeof(float *) * (m->output_pairs + 2));
#endif
}
m->module.process_event = fluidsynth_process_event;
m->module.process_block = fluidsynth_process_block;
m->module.aux_offset = 2 * m->output_pairs;
const char *audio_drivers[] = { NULL };
fluid_audio_driver_register(audio_drivers);
m->settings = new_fluid_settings();
fluid_settings_setnum(m->settings, "synth.sample-rate", m->module.srate);
fluid_settings_setint(m->settings, "synth.audio-channels", m->output_pairs);
fluid_settings_setint(m->settings, "synth.audio-groups", m->output_pairs);
fluid_settings_setint(m->settings, "synth.reverb.active", cbox_config_get_int(cfg_section, "reverb", 1));
fluid_settings_setint(m->settings, "synth.chorus.active", cbox_config_get_int(cfg_section, "chorus", 1));
m->synth = new_fluid_synth(m->settings);
fluid_set_log_function(FLUID_PANIC, cbox_fluidsynth_log_write, m);
fluid_set_log_function(FLUID_ERR, cbox_fluidsynth_log_write, m);
fluid_set_log_function(FLUID_WARN, cbox_fluidsynth_log_write, m);
//fluid_synth_add_sfloader(m->synth, new_fluid_defsfloader(m->settings));
m->error_log = NULL;
m->bank_name = NULL;
m->sfid = -1;
if (bankname)
{
if (!load_soundfont(m, bankname, error))
{
CBOX_DELETE(&m->module);
return NULL;
}
g_message("Soundfont %s loaded", bankname);
}
if (bankname)
{
for (i = 0; i < 16; i++)
{
gchar *key = g_strdup_printf("channel%d", i + 1);
gchar *preset = cbox_config_get_string(cfg_section, key);
fluid_synth_sfont_select(m->synth, i, m->sfid);
if (preset)
{
if (!select_patch_by_name(m, i, preset, error))
{
CBOX_DELETE(&m->module);
return NULL;
}
}
g_free(key);
}
}
return &m->module;
}
void fluidsynth_process_block(struct cbox_module *module, cbox_sample_t **inputs, cbox_sample_t **outputs)
{
struct fluidsynth_module *m = (struct fluidsynth_module *)module;
if (!m->is_multi)
fluid_synth_write_float(m->synth, CBOX_BLOCK_SIZE, outputs[0], 0, 1, outputs[1], 0, 1);
else
{
#if OLD_FLUIDSYNTH
for (int i = 0; i < 2 + m->output_pairs; i++)
{
m->left_outputs[i] = outputs[2 * i];
m->right_outputs[i] = outputs[2 * i + 1];
}
fluid_synth_nwrite_float(m->synth, CBOX_BLOCK_SIZE, m->left_outputs, m->right_outputs, m->left_outputs + m->output_pairs, m->right_outputs + m->output_pairs);
#else
float *fx_outputs[4];
for (int i = 0; i < 4; i++)
fx_outputs[i] = outputs[2 * m->output_pairs + i];
for (int i = 0; i < 2 * (2 + m->output_pairs); i++)
zerobf(outputs[i]);
fluid_synth_process(m->synth, CBOX_BLOCK_SIZE, 4, fx_outputs, 2 * m->output_pairs, outputs);
#endif
}
}
void fluidsynth_process_event(struct cbox_module *module, const uint8_t *data, uint32_t len)
{
struct fluidsynth_module *m = (struct fluidsynth_module *)module;
if (len > 0)
{
int cmd = data[0] >> 4;
int chn = data[0] & 15;
switch(cmd)
{
case 8:
fluid_synth_noteoff(m->synth, chn, data[1]);
break;
case 9:
fluid_synth_noteon(m->synth, chn, data[1], data[2]);
break;
case 10:
// polyphonic pressure not handled
break;
case 11:
fluid_synth_cc(m->synth, chn, data[1], data[2]);
break;
case 12:
fluid_synth_program_change(m->synth, chn, data[1]);
break;
case 13:
fluid_synth_channel_pressure(m->synth, chn, data[1]);
break;
case 14:
fluid_synth_pitch_bend(m->synth, chn, data[1] + 128 * data[2]);
break;
}
}
}
gboolean fluidsynth_process_load_patch(struct fluidsynth_module *m, const char *bank_name, GError **error)
{
if (bank_name && !*bank_name)
bank_name = NULL;
int old_sfid = m->sfid;
char *old_bank_name = m->bank_name;
if (bank_name)
{
if (!load_soundfont(m, bank_name, error))
return FALSE;
g_message("Soundfont %s loaded at ID %d", bank_name, m->sfid);
}
else
m->sfid = -1;
if (old_sfid != -1)
{
g_free(old_bank_name);
fluid_synth_sfunload(m->synth, old_sfid, 1);
}
if (m->sfid != -1)
{
for (int i = 0; i < 16; i++)
fluid_synth_sfont_select(m->synth, i, m->sfid);
}
m->bank_name = bank_name ? g_strdup(bank_name) : NULL;
return TRUE;
}
gboolean fluidsynth_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
struct fluidsynth_module *m = (struct fluidsynth_module *)ct->user_data;
if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
if (!cbox_execute_on(fb, NULL, "/polyphony", "i", error, fluid_synth_get_polyphony(m->synth)))
return FALSE;
if (!cbox_execute_on(fb, NULL, "/soundfont", "s", error, m->bank_name ? m->bank_name : ""))
return FALSE;
for (int i = 0; i < 16; i++)
{
cbox_fluidsynth_id_t sfont_id, bank_num, preset_num;
fluid_synth_get_program(m->synth, i, &sfont_id, &bank_num, &preset_num);
fluid_preset_t *preset = fluid_synth_get_channel_preset(m->synth, i);
if (!cbox_execute_on(fb, NULL, "/patch", "iis", error, 1 + i, preset_num + 128 * bank_num, preset ? fluid_preset_get_name(preset) : "(unknown)"))
return FALSE;
}
return CBOX_OBJECT_DEFAULT_STATUS(&m->module, fb, error);
}
else if (!strcmp(cmd->command, "/patches") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
if (m->sfid == -1)
return TRUE;
fluid_sfont_t* sfont = fluid_synth_get_sfont(m->synth, 0);
fluid_preset_t *tmp;
fluid_sfont_iteration_setup();
fluid_sfont_iteration_start(sfont);
while((tmp = fluid_sfont_iteration_next(sfont)) != NULL)
{
const char *pname = fluid_preset_get_name(tmp);
if (!cbox_execute_on(fb, NULL, "/patch", "is", error, (int)(fluid_preset_get_num(tmp) + 128 * fluid_preset_get_banknum(tmp)), pname))
return FALSE;
}
return TRUE;
}
else if (!strcmp(cmd->command, "/set_patch") && !strcmp(cmd->arg_types, "ii"))
{
if (m->sfid == -1)
{
g_set_error(error, CBOX_FLUIDSYNTH_ERROR, CBOX_FLUIDSYNTH_ERROR_FAILED, "No soundfont loaded");
return FALSE;
}
int channel = CBOX_ARG_I(cmd, 0);
if (channel < 1 || channel > 16)
{
g_set_error(error, CBOX_FLUIDSYNTH_ERROR, CBOX_FLUIDSYNTH_ERROR_FAILED, "Invalid channel %d", channel);
return FALSE;
}
int value = CBOX_ARG_I(cmd, 1);
return fluid_synth_program_select(m->synth, channel - 1, m->sfid, value >> 7, value & 127) == FLUID_OK;
}
else if (!strcmp(cmd->command, "/polyphony") && !strcmp(cmd->arg_types, "i"))
{
int polyphony = CBOX_ARG_I(cmd, 0);
if (polyphony < 2 || polyphony > 256)
{
g_set_error(error, CBOX_FLUIDSYNTH_ERROR, CBOX_FLUIDSYNTH_ERROR_FAILED, "Invalid polyphony %d (must be between 2 and 256)", polyphony);
return FALSE;
}
return fluid_synth_set_polyphony(m->synth, polyphony) == FLUID_OK;
}
else if (!strcmp(cmd->command, "/load_soundfont") && !strcmp(cmd->arg_types, "s"))
{
return fluidsynth_process_load_patch(m, CBOX_ARG_S(cmd, 0), error);
}
else
return cbox_object_default_process_cmd(ct, fb, cmd, error);
return TRUE;
}
void fluidsynth_destroyfunc(struct cbox_module *module)
{
struct fluidsynth_module *m = (struct fluidsynth_module *)module;
#if OLD_FLUIDSYNTH
if (m->output_pairs)
{
free(m->left_outputs);
free(m->right_outputs);
}
#endif
free(m->bank_name);
delete_fluid_synth(m->synth);
delete_fluid_settings(m->settings);
}
struct cbox_module_livecontroller_metadata fluidsynth_controllers[] = {
{ -1, cmlc_continuouscc, 1, "Modulation", NULL},
{ -1, cmlc_continuouscc, 7, "Volume", NULL},
{ -1, cmlc_continuouscc, 10, "Pan", NULL},
{ -1, cmlc_continuouscc, 91, "Reverb", NULL},
{ -1, cmlc_continuouscc, 93, "Chorus", NULL},
{ -1, cmlc_onoffcc, 64, "Hold", NULL},
{ -1, cmlc_onoffcc, 66, "Sostenuto", NULL},
};
struct cbox_module_keyrange_metadata fluidsynth_keyranges[] = {
{ 1, 0, 127, "Channel 1" },
{ 2, 0, 127, "Channel 2" },
{ 3, 0, 127, "Channel 3" },
{ 4, 0, 127, "Channel 4" },
{ 5, 0, 127, "Channel 5" },
{ 6, 0, 127, "Channel 6" },
{ 7, 0, 127, "Channel 7" },
{ 8, 0, 127, "Channel 8" },
{ 9, 0, 127, "Channel 9" },
{ 10, 0, 127, "Channel 10" },
{ 11, 0, 127, "Channel 11" },
{ 12, 0, 127, "Channel 12" },
{ 13, 0, 127, "Channel 13" },
{ 14, 0, 127, "Channel 14" },
{ 15, 0, 127, "Channel 15" },
{ 16, 0, 127, "Channel 16" },
};
DEFINE_MODULE(fluidsynth, 0, 2)
#endif

173
template/calfbox/fuzz.c

@ -1,173 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "biquad-float.h"
#include "config.h"
#include "config-api.h"
#include "dspmath.h"
#include "module.h"
#include <glib.h>
#include <malloc.h>
#include <math.h>
#include <memory.h>
#include <sndfile.h>
#include <stdio.h>
#include <stdlib.h>
#define MODULE_PARAMS fuzz_params
struct fuzz_params
{
float drive;
float wet_dry;
float rectify;
float band;
float bandwidth;
float band2;
float bandwidth2;
};
struct fuzz_module
{
struct cbox_module module;
struct fuzz_params *params, *old_params;
struct cbox_biquadf_coeffs split_coeffs;
struct cbox_biquadf_coeffs post_coeffs;
struct cbox_biquadf_state split_state[2];
struct cbox_biquadf_state post_state[2];
};
gboolean fuzz_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
struct fuzz_module *m = (struct fuzz_module *)ct->user_data;
EFFECT_PARAM("/drive", "f", drive, double, dB2gain_simple, -36, 36) else
EFFECT_PARAM("/wet_dry", "f", wet_dry, double, , 0, 1) else
EFFECT_PARAM("/rectify", "f", rectify, double, , 0, 1) else
EFFECT_PARAM("/band", "f", band, double, , 100, 5000) else
EFFECT_PARAM("/bandwidth", "f", bandwidth, double, , 0.25, 4) else
EFFECT_PARAM("/band2", "f", band2, double, , 100, 5000) else
EFFECT_PARAM("/bandwidth2", "f", bandwidth2, double, , 0.25, 4) else
if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
return cbox_execute_on(fb, NULL, "/drive", "f", error, gain2dB_simple(m->params->drive))
&& cbox_execute_on(fb, NULL, "/wet_dry", "f", error, m->params->wet_dry)
&& cbox_execute_on(fb, NULL, "/rectify", "f", error, m->params->rectify)
&& cbox_execute_on(fb, NULL, "/band", "f", error, m->params->band)
&& cbox_execute_on(fb, NULL, "/bandwidth", "f", error, m->params->bandwidth)
&& cbox_execute_on(fb, NULL, "/band2", "f", error, m->params->band2)
&& cbox_execute_on(fb, NULL, "/bandwidth2", "f", error, m->params->bandwidth2)
&& CBOX_OBJECT_DEFAULT_STATUS(&m->module, fb, error)
;
}
else
return cbox_object_default_process_cmd(ct, fb, cmd, error);
return TRUE;
}
void fuzz_process_event(struct cbox_module *module, const uint8_t *data, uint32_t len)
{
// struct fuzz_module *m = module->user_data;
}
void fuzz_process_block(struct cbox_module *module, cbox_sample_t **inputs, cbox_sample_t **outputs)
{
struct fuzz_module *m = module->user_data;
if (m->params != m->old_params)
{
// update calculated values
}
cbox_biquadf_set_bp_rbj(&m->split_coeffs, m->params->band, 0.7 / m->params->bandwidth, m->module.srate);
cbox_biquadf_set_bp_rbj(&m->post_coeffs, m->params->band2, 0.7 / m->params->bandwidth2, m->module.srate);
float splitbuf[2][CBOX_BLOCK_SIZE];
float drive = m->params->drive;
float sdrive = pow(drive, -0.7);
for (int c = 0; c < 2; c++)
{
cbox_biquadf_process_to(&m->split_state[c], &m->split_coeffs, inputs[c], splitbuf[c]);
for (int i = 0; i < CBOX_BLOCK_SIZE; i++)
{
float in = inputs[c][i];
float val = splitbuf[c][i];
val *= drive;
val += m->params->rectify;
if (fabs(val) > 1.0)
val = (val > 0) ? 1 : -1;
else
val = val * (3 - val * val) * 0.5;
val *= sdrive;
val = cbox_biquadf_process_sample(&m->post_state[c], &m->post_coeffs, val);
outputs[c][i] = in + (val - in) * m->params->wet_dry;
}
}
}
MODULE_SIMPLE_DESTROY_FUNCTION(fuzz)
MODULE_CREATE_FUNCTION(fuzz)
{
static int inited = 0;
if (!inited)
{
inited = 1;
}
struct fuzz_module *m = malloc(sizeof(struct fuzz_module));
CALL_MODULE_INIT(m, 2, 2, fuzz);
m->module.process_event = fuzz_process_event;
m->module.process_block = fuzz_process_block;
struct fuzz_params *p = malloc(sizeof(struct fuzz_params));
p->drive = cbox_config_get_gain_db(cfg_section, "drive", 0.f);
p->wet_dry = cbox_config_get_float(cfg_section, "wet_dry", 0.5f);
p->rectify = cbox_config_get_float(cfg_section, "rectify", 0.5f);
p->band = cbox_config_get_float(cfg_section, "band", 1000.f);
p->bandwidth = cbox_config_get_float(cfg_section, "bandwidth", 1);
p->band2 = cbox_config_get_float(cfg_section, "band2", 2000.f);
p->bandwidth2 = cbox_config_get_float(cfg_section, "bandwidth2", 1);
m->params = p;
m->old_params = NULL;
cbox_biquadf_reset(&m->split_state[0]);
cbox_biquadf_reset(&m->split_state[1]);
cbox_biquadf_reset(&m->post_state[0]);
cbox_biquadf_reset(&m->post_state[1]);
return &m->module;
}
struct cbox_module_keyrange_metadata fuzz_keyranges[] = {
};
struct cbox_module_livecontroller_metadata fuzz_controllers[] = {
};
DEFINE_MODULE(fuzz, 2, 2)

0
template/calfbox/py/fx_gui.py → template/calfbox/fx_gui.py

231
template/calfbox/fxchain.c

@ -1,231 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "config-api.h"
#include "dspmath.h"
#include "module.h"
#include "rt.h"
#include <glib.h>
#include <malloc.h>
#include <math.h>
#include <memory.h>
#include <sndfile.h>
#include <stdio.h>
#include <stdlib.h>
struct fxchain_module
{
struct cbox_module module;
struct cbox_module **modules;
uint32_t module_count;
};
void fxchain_move(struct fxchain_module *m, unsigned int oldpos, unsigned int newpos)
{
if (oldpos == newpos)
return;
struct cbox_module **modules = malloc(sizeof(struct cbox_module *) * m->module_count);
for (uint32_t i = 0; i < m->module_count; i++)
{
int s;
if (i == newpos)
s = oldpos;
else
{
if (oldpos < newpos)
s = (i < oldpos || i > newpos) ? i : i + 1;
else
s = (i < newpos || i > oldpos) ? i : i - 1;
}
modules[i] = m->modules[s];
}
free(cbox_rt_swap_pointers(m->module.rt, (void **)&m->modules, modules));
}
gboolean fxchain_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
struct fxchain_module *m = (struct fxchain_module *)ct->user_data;
const char *subcommand = NULL;
int index = 0;
//EFFECT_PARAM("/module_count", "i", stages, int, , 1, 12) else
if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
for (uint32_t i = 0; i < m->module_count; i++)
{
gboolean res = FALSE;
if (m->modules[i])
res = cbox_execute_on(fb, NULL, "/module", "ss", error, m->modules[i]->engine_name, m->modules[i]->instance_name);
else
res = cbox_execute_on(fb, NULL, "/module", "ss", error, "", "");
if (!res)
return FALSE;
res = cbox_execute_on(fb, NULL, "/bypass", "ii", error, i + 1, m->modules[i] ? m->modules[i]->bypass : 0);
}
return CBOX_OBJECT_DEFAULT_STATUS(&m->module, fb, error);
}
else if (cbox_parse_path_part_int(cmd, "/module/", &subcommand, &index, 1, m->module_count, error))
{
if (!subcommand)
return FALSE;
return cbox_module_slot_process_cmd(&m->modules[index - 1], fb, cmd, subcommand, CBOX_GET_DOCUMENT(&m->module), m->module.rt, m->module.engine, error);
}
else if (!strcmp(cmd->command, "/insert") && !strcmp(cmd->arg_types, "i"))
{
int pos = CBOX_ARG_I(cmd, 0) - 1;
struct cbox_module **new_modules = malloc((m->module_count + 1) * sizeof(struct cbox_module *));
memcpy(new_modules, m->modules, pos * sizeof(struct cbox_module *));
new_modules[pos] = NULL;
memcpy(new_modules + pos + 1, m->modules + pos, (m->module_count - pos) * sizeof(struct cbox_module *));
void *old_modules = cbox_rt_swap_pointers_and_update_count(m->module.rt, (void **)&m->modules, new_modules, &m->module_count, m->module_count + 1);
free(old_modules);
return TRUE;
}
else if (!strcmp(cmd->command, "/delete") && !strcmp(cmd->arg_types, "i"))
{
int pos = CBOX_ARG_I(cmd, 0) - 1;
struct cbox_module **new_modules = malloc((m->module_count + 1) * sizeof(struct cbox_module *));
memcpy(new_modules, m->modules, pos * sizeof(struct cbox_module *));
memcpy(new_modules + pos, m->modules + pos + 1, (m->module_count - pos - 1) * sizeof(struct cbox_module *));
struct cbox_module *deleted_module = m->modules[pos];
void *old_modules = cbox_rt_swap_pointers_and_update_count(m->module.rt, (void **)&m->modules, new_modules, &m->module_count, m->module_count - 1);
free(old_modules);
if (deleted_module)
CBOX_DELETE(deleted_module);
return TRUE;
}
else if (!strcmp(cmd->command, "/move") && !strcmp(cmd->arg_types, "ii"))
{
int oldpos = CBOX_ARG_I(cmd, 0) - 1;
int newpos = CBOX_ARG_I(cmd, 1) - 1;
fxchain_move(m, oldpos, newpos);
}
else
return cbox_object_default_process_cmd(ct, fb, cmd, error);
return TRUE;
}
void fxchain_process_event(struct cbox_module *module, const uint8_t *data, uint32_t len)
{
// struct fxchain_module *m = module->user_data;
}
void fxchain_process_block(struct cbox_module *module, cbox_sample_t **inputs, cbox_sample_t **outputs)
{
struct fxchain_module *m = module->user_data;
float bufs[2][2][CBOX_BLOCK_SIZE];
for (uint32_t i = 0; i < m->module_count; i++)
{
float *input_bufs[2], *output_bufs[2];
for (int c = 0; c < 2; c++)
{
input_bufs[c] = i == 0 ? inputs[c] : bufs[i & 1][c];
output_bufs[c] = i == m->module_count - 1 ? outputs[c] : bufs[(i + 1) & 1][c];
}
if (m->modules[i] && !m->modules[i]->bypass)
m->modules[i]->process_block(m->modules[i]->user_data, input_bufs, output_bufs);
else
{
// this is not eficient at all, but empty modules aren't likely to be used except
// when setting up a chain.
for (int c = 0; c < 2; c++)
memcpy(output_bufs[c], input_bufs[c], CBOX_BLOCK_SIZE * sizeof(float));
}
}
}
static void fxchain_destroyfunc(struct cbox_module *module)
{
struct fxchain_module *m = module->user_data;
for (uint32_t i = 0; i < m->module_count; i++)
{
CBOX_DELETE(m->modules[i]);
m->modules[i] = NULL;
}
free(m->modules);
}
MODULE_CREATE_FUNCTION(fxchain)
{
static int inited = 0;
if (!inited)
{
inited = 1;
}
int i, fx_count = 0;
for (i = 0; ; i++)
{
gchar *name = g_strdup_printf("effect%d", i + 1);
const char *fx_name = cbox_config_get_string(cfg_section, name);
g_free(name);
if (!fx_name)
break;
}
fx_count = i;
if (cfg_section && !fx_count)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "No effects defined");
return NULL;
}
struct fxchain_module *m = malloc(sizeof(struct fxchain_module));
CALL_MODULE_INIT(m, 2, 2, fxchain);
m->module.process_event = fxchain_process_event;
m->module.process_block = fxchain_process_block;
m->modules = malloc(sizeof(struct cbox_module *) * fx_count);
m->module_count = fx_count;
for (i = 0; i < fx_count; i++)
m->modules[i] = NULL;
for (i = 0; i < fx_count; i++)
{
gchar *name = g_strdup_printf("effect%d", i + 1);
const char *fx_preset_name = cbox_config_get_string(cfg_section, name);
g_free(name);
m->modules[i] = cbox_module_new_from_fx_preset(fx_preset_name, doc, rt, engine, error);
if (!m->modules[i])
goto failed;
}
fx_count = i;
return &m->module;
failed:
m->module_count = i;
CBOX_DELETE(&m->module);
return NULL;
}
struct cbox_module_keyrange_metadata fxchain_keyranges[] = {
};
struct cbox_module_livecontroller_metadata fxchain_controllers[] = {
};
DEFINE_MODULE(fxchain, 0, 2)

181
template/calfbox/gate.c

@ -1,181 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2012 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "config-api.h"
#include "dspmath.h"
#include "module.h"
#include "onepole-float.h"
#include <glib.h>
#include <malloc.h>
#include <math.h>
#include <memory.h>
#include <sndfile.h>
#include <stdio.h>
#include <stdlib.h>
#define MODULE_PARAMS gate_params
struct gate_params
{
float threshold;
float ratio;
float attack;
float hold;
float release;
};
struct gate_module
{
struct cbox_module module;
struct gate_params *params, *old_params;
struct cbox_onepolef_coeffs attack_lp, release_lp, shifter_lp;
struct cbox_onepolef_state shifter1, shifter2;
struct cbox_onepolef_state tracker;
int hold_time, hold_threshold;
};
gboolean gate_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
struct gate_module *m = (struct gate_module *)ct->user_data;
EFFECT_PARAM("/threshold", "f", threshold, double, dB2gain_simple, -100, 100) else
EFFECT_PARAM("/ratio", "f", ratio, double, , 1, 100) else
EFFECT_PARAM("/attack", "f", attack, double, , 1, 1000) else
EFFECT_PARAM("/hold", "f", hold, double, , 1, 1000) else
EFFECT_PARAM("/release", "f", release, double, , 1, 1000) else
if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
return cbox_execute_on(fb, NULL, "/threshold", "f", error, gain2dB_simple(m->params->threshold))
&& cbox_execute_on(fb, NULL, "/ratio", "f", error, m->params->ratio)
&& cbox_execute_on(fb, NULL, "/attack", "f", error, m->params->attack)
&& cbox_execute_on(fb, NULL, "/hold", "f", error, m->params->hold)
&& cbox_execute_on(fb, NULL, "/release", "f", error, m->params->release)
&& CBOX_OBJECT_DEFAULT_STATUS(&m->module, fb, error)
;
}
else
return cbox_object_default_process_cmd(ct, fb, cmd, error);
return TRUE;
}
void gate_process_event(struct cbox_module *module, const uint8_t *data, uint32_t len)
{
// struct gate_module *m = module->user_data;
}
void gate_process_block(struct cbox_module *module, cbox_sample_t **inputs, cbox_sample_t **outputs)
{
struct gate_module *m = module->user_data;
if (m->params != m->old_params)
{
float scale = M_PI * 1000 / m->module.srate;
cbox_onepolef_set_lowpass(&m->attack_lp, scale / m->params->attack);
cbox_onepolef_set_lowpass(&m->release_lp, scale / m->params->release);
cbox_onepolef_set_allpass(&m->shifter_lp, M_PI * 100 / m->module.srate);
m->hold_threshold = (int)(m->module.srate * m->params->hold * 0.001);
m->old_params = m->params;
}
float threshold = m->params->threshold;
float threshold2 = threshold * threshold * 1.73;
for (int i = 0; i < CBOX_BLOCK_SIZE; i++)
{
float left = inputs[0][i], right = inputs[1][i];
float sig = fabs(left) > fabs(right) ? fabs(left) : fabs(right);
// Primitive envelope detector - may not work so well with more interesting stereo signals
float shf1 = cbox_onepolef_process_sample(&m->shifter1, &m->shifter_lp, 0.5 * (left + right));
float shf2 = cbox_onepolef_process_sample(&m->shifter2, &m->shifter_lp, shf1);
sig = sig*sig + shf1*shf1 + shf2 * shf2;
// attack - hold - release logic based on signal envelope
int release = 1;
float gain = 1.0;
if (sig < threshold2)
{
// hold vs release
if (m->hold_time >= m->hold_threshold)
{
gain = powf(sig / threshold2, 0.5 * (m->params->ratio - 1));
// gain = powf(sqrt(sig) / threshold, (m->params->ratio - 1));
}
else
m->hold_time++;
}
else
{
// attack - going to 1 using attack rate
m->hold_time = 0;
gain = 1.0;
release = 0;
}
gain = cbox_onepolef_process_sample(&m->tracker, release ? &m->release_lp : &m->attack_lp, gain);
outputs[0][i] = left * gain;
outputs[1][i] = right * gain;
}
}
MODULE_SIMPLE_DESTROY_FUNCTION(gate)
MODULE_CREATE_FUNCTION(gate)
{
static int inited = 0;
if (!inited)
{
inited = 1;
}
struct gate_module *m = malloc(sizeof(struct gate_module));
CALL_MODULE_INIT(m, 2, 2, gate);
m->module.process_event = gate_process_event;
m->module.process_block = gate_process_block;
m->hold_time = 0;
m->hold_threshold = 0;
struct gate_params *p = malloc(sizeof(struct gate_params));
p->threshold = cbox_config_get_gain_db(cfg_section, "threshold", -28.0);
p->ratio = cbox_config_get_float(cfg_section, "ratio", 3.0);
p->attack = cbox_config_get_float(cfg_section, "attack", 3.0);
p->hold = cbox_config_get_float(cfg_section, "hold", 100.0);
p->release = cbox_config_get_float(cfg_section, "release", 100.0);
m->params = p;
m->old_params = NULL;
cbox_onepolef_reset(&m->tracker);
cbox_onepolef_reset(&m->shifter1);
cbox_onepolef_reset(&m->shifter2);
return &m->module;
}
struct cbox_module_keyrange_metadata gate_keyranges[] = {
};
struct cbox_module_livecontroller_metadata gate_controllers[] = {
};
DEFINE_MODULE(gate, 2, 2)

0
template/calfbox/py/gui_tools.py → template/calfbox/gui_tools.py

172
template/calfbox/hwcfg.c

@ -1,172 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#if USE_JACK
#include "config-api.h"
#include "io.h"
#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
static char *cfg(const char *section, const char *name, char *defvalue)
{
char *value = cbox_config_get_string(section, name);
if (value)
return value;
return cbox_config_get_string_with_default("autojack", name, defvalue);
}
static void generate_jack_config(const char *section, const char *id)
{
char *rcfile = cbox_config_get_string("autojack", "jackdrc");
FILE *f;
if (!rcfile)
{
rcfile = g_strdup_printf("%s/.jackdrc", getenv("HOME"));
g_message("Generating JACK config: %s\n", rcfile);
f = fopen(rcfile, "w");
if (!f)
{
g_error("Cannot open file %s", rcfile);
return;
}
g_free(rcfile);
}
else
{
g_message("Generating JACK config: %s\n", rcfile);
f = fopen(rcfile, "w");
if (!f)
{
g_error("Cannot open file %s", rcfile);
return;
}
}
fprintf(f, "%s %s -d alsa -d hw:%s -r 44100 %s\n",
cfg(section, "jackd", "/usr/bin/jackd"),
cfg(section, "jack_options", "-R -T"),
id,
cfg(section, "alsa_options", ""));
fclose(f);
}
static int try_soundcard(const char *name)
{
gchar *id;
if (!cbox_config_has_section(name))
return 0;
g_message("Trying section %s", name);
id = cbox_config_get_string(name, "device");
if (id != NULL)
{
struct stat s;
int result;
gchar *fn = g_strdup_printf("/proc/asound/%s", id);
result = stat(fn, &s);
if (!result)
generate_jack_config(name, id);
g_free(fn);
return !result;
}
id = cbox_config_get_string(name, "usbid");
if (id != NULL)
{
int vid, pid;
if (sscanf(id, "%x:%x\n", &vid, &pid) !=2)
{
g_error("Invalid VID:PID value: %s", id);
return 0;
}
for (int i = 0; ; i++)
{
struct stat s;
int result;
FILE *f = NULL;
int tvid, tpid;
// check if it's not beyond the last soundcard index
gchar *fn = g_strdup_printf("/proc/asound/card%d", i);
result = stat(fn, &s);
g_free(fn);
if (result)
break;
// check if it has a USB ID
fn = g_strdup_printf("/proc/asound/card%d/usbid", i);
f = fopen(fn, "r");
g_free(fn);
if (!f)
continue;
if (fscanf(f, "%x:%x", &tvid, &tpid) == 2)
{
if (vid == tvid && pid == tpid)
{
gchar *fn = g_strdup_printf("%d", i);
generate_jack_config(name, fn);
g_free(fn);
fclose(f);
return 1;
}
}
fclose(f);
}
return 0;
}
return 0;
}
int cbox_hwcfg_setup_jack(void)
{
int i;
if (!cbox_config_has_section("autojack"))
return 0;
for (i = 0; ; i++)
{
int result;
gchar *cardnum = g_strdup_printf("soundcard%d", i);
char *secname = cbox_config_get_string("autojack", cardnum);
g_free(cardnum);
if (!secname)
break;
secname = g_strdup_printf("soundcard:%s", secname);
result = try_soundcard(secname);
g_free(secname);
if (result)
return 1;
}
return 0;
}
#endif

28
template/calfbox/hwcfg.h

@ -1,28 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_HWCFG_H
#define CBOX_HWCFG_H
/**
* Autodetect JACK config based on cbox configuration vs ALSA devices present.
* @retval 1 if OK
*/
extern int cbox_hwcfg_setup_jack(void);
#endif

251
template/calfbox/instr.c

@ -1,251 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "auxbus.h"
#include "config-api.h"
#include "instr.h"
#include "module.h"
#include "io.h"
#include "rt.h"
#include "scene.h"
#include <assert.h>
#include <glib.h>
CBOX_CLASS_DEFINITION_ROOT(cbox_instrument)
static gboolean cbox_instrument_output_process_cmd(struct cbox_instrument *instr, struct cbox_instrument_output *output, struct cbox_command_target *fb, struct cbox_osc_command *cmd, const char *subcmd, GError **error)
{
if (!strcmp(subcmd, "/status") && !strcmp(cmd->arg_types, ""))
{
if (!(cbox_execute_on(fb, NULL, "/gain_linear", "f", error, output->gain_obj.lin_gain) &&
cbox_execute_on(fb, NULL, "/gain", "f", error, output->gain_obj.db_gain) &&
cbox_execute_on(fb, NULL, "/output", "i", error, output->output_bus + 1)))
return FALSE;
return cbox_module_slot_process_cmd(&output->insert, fb, cmd, subcmd, CBOX_GET_DOCUMENT(instr->scene), instr->scene->rt, instr->scene->engine, error);
}
if (!strcmp(subcmd, "/gain") && !strcmp(cmd->arg_types, "f"))
{
// XXXKF this needs proper handling of concurrency/race conditions, might
// be built into the gain class in future.
cbox_gain_set_db(&output->gain_obj, CBOX_ARG_F(cmd, 0));
return TRUE;
}
if (!strcmp(subcmd, "/output") && !strcmp(cmd->arg_types, "i"))
{
int obus = CBOX_ARG_I(cmd, 0);
int max_outputs = instr->scene->rt->io ? instr->scene->rt->io->io_env.output_count : 2;
int max_obus = 1 + (max_outputs - 1) / 2;
if (obus < 0 || obus > max_obus) {
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Invalid output %d (must be between 1 and %d, or 0 for none)", obus, max_obus);
return FALSE;
}
output->output_bus = obus - 1;
return TRUE;
}
if (!strncmp(subcmd, "/rec_dry/", 9))
return cbox_execute_sub(&output->rec_dry.cmd_target, fb, cmd, subcmd + 8, error);
if (!strncmp(subcmd, "/rec_wet/", 9))
return cbox_execute_sub(&output->rec_wet.cmd_target, fb, cmd, subcmd + 8, error);
return cbox_module_slot_process_cmd(&output->insert, fb, cmd, subcmd, CBOX_GET_DOCUMENT(instr->scene), instr->scene->rt, instr->scene->engine, error);
}
static gboolean cbox_instrument_aux_process_cmd(struct cbox_instrument *instr, struct cbox_instrument_output *output, int id, struct cbox_command_target *fb, struct cbox_osc_command *cmd, const char *subcmd, GError **error)
{
if (!strcmp(subcmd, "/status") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
if (!(cbox_execute_on(fb, NULL, "/gain_linear", "f", error, output->gain_obj.lin_gain) &&
cbox_execute_on(fb, NULL, "/gain", "f", error, output->gain_obj.db_gain) &&
cbox_execute_on(fb, NULL, "/bus", "s", error, instr->aux_output_names[id] ? instr->aux_output_names[id] : "")))
return FALSE;
return cbox_module_slot_process_cmd(&output->insert, fb, cmd, subcmd, CBOX_GET_DOCUMENT(instr->scene), instr->scene->rt, instr->scene->engine, error);
}
else if (!strcmp(subcmd, "/bus") && !strcmp(cmd->arg_types, "s"))
{
struct cbox_scene *scene = instr->scene;
if (!CBOX_ARG_S(cmd, 0))
{
struct cbox_aux_bus *old_bus = cbox_rt_swap_pointers(instr->module->rt, (void **)&instr->aux_outputs[id], NULL);
if (old_bus)
cbox_aux_bus_unref(old_bus);
return TRUE;
}
for (uint32_t i = 0; i < scene->aux_bus_count; i++)
{
if (!scene->aux_buses[i])
continue;
if (!strcmp(scene->aux_buses[i]->name, CBOX_ARG_S(cmd, 0)))
{
g_free(instr->aux_output_names[id]);
instr->aux_output_names[id] = g_strdup(scene->aux_buses[i]->name);
cbox_aux_bus_ref(scene->aux_buses[i]);
struct cbox_aux_bus *old_bus = cbox_rt_swap_pointers(instr->module->rt, (void **)&instr->aux_outputs[id], scene->aux_buses[i]);
if (old_bus)
cbox_aux_bus_unref(old_bus);
return TRUE;
}
}
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Unknown aux bus: %s", CBOX_ARG_S(cmd, 0));
return FALSE;
}
else if (!strcmp(subcmd, "/output") && !strcmp(cmd->arg_types, "i")) // not supported
{
cbox_set_command_error(error, cmd);
return FALSE;
}
else // otherwise, treat just like an command on normal (non-aux) output
return cbox_instrument_output_process_cmd(instr, output, fb, cmd, subcmd, error);
}
gboolean cbox_instrument_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
struct cbox_instrument *instr = ct->user_data;
const char *subcommand = NULL;
int index = 0;
int aux_offset = instr->module->aux_offset / 2;
if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
if (!cbox_execute_on(fb, NULL, "/engine", "s", error, instr->module->engine_name))
return FALSE;
if (!cbox_execute_on(fb, NULL, "/aux_offset", "i", error, instr->module->aux_offset / 2 + 1))
return FALSE;
if (!cbox_execute_on(fb, NULL, "/outputs", "i", error, instr->module->outputs / 2))
return FALSE;
return CBOX_OBJECT_DEFAULT_STATUS(instr, fb, error);
}
else if (cbox_parse_path_part_int(cmd, "/output/", &subcommand, &index, 1, aux_offset, error))
{
if (!subcommand)
return FALSE;
if (index < 1 || index > (int)(1 + instr->module->aux_offset))
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Invalid position %d (valid are 1..%d)", index, instr->module->aux_offset);
return FALSE;
}
return cbox_instrument_output_process_cmd(instr, &instr->outputs[index - 1], fb, cmd, subcommand, error);
}
else if (cbox_parse_path_part_int(cmd, "/aux/", &subcommand, &index, 1, instr->aux_output_count, error))
{
if (!subcommand)
return FALSE;
int acount = 1 + instr->module->outputs - instr->module->aux_offset;
if (index < 1 || index > acount)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Invalid position %d (valid are 1..%d)", index, acount);
return FALSE;
}
return cbox_instrument_aux_process_cmd(instr, &instr->outputs[aux_offset + index - 1], index - 1, fb, cmd, subcommand, error);
}
else
if (!strncmp(cmd->command, "/engine/",8))
{
if (!instr->module->cmd_target.process_cmd)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "The engine %s has no command target defined", instr->module->engine_name);
return FALSE;
}
return cbox_execute_sub(&instr->module->cmd_target, fb, cmd, cmd->command + 7, error);
}
else if (!strcmp(cmd->command, "/move_to") && !strcmp(cmd->arg_types, "si"))
{
struct cbox_scene *new_scene = (struct cbox_scene *)CBOX_ARG_O(cmd, 0, instr->scene, cbox_scene, error);
if (!new_scene)
return FALSE;
int dstpos = CBOX_ARG_I(cmd, 1) - 1;
if (dstpos < 0 || (uint32_t)dstpos > new_scene->layer_count)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Invalid position %d (valid are 1..%d or 0 for append)", dstpos + 1, 1 + new_scene->layer_count);
return FALSE;
}
return cbox_scene_move_instrument_to(instr->scene, instr, new_scene, dstpos, error);
}
else
return cbox_object_default_process_cmd(ct, fb, cmd, error);
}
void cbox_instrument_destroy_if_unused(struct cbox_instrument *instrument)
{
if (instrument->refcount == 0)
CBOX_DELETE(instrument);
}
void cbox_instrument_destroyfunc(struct cbox_objhdr *objhdr)
{
struct cbox_instrument *instrument = CBOX_H2O(objhdr);
assert(instrument->refcount == 0);
for (uint32_t i = 0; i < (uint32_t)instrument->module->outputs >> 1; i ++)
{
cbox_instrument_output_uninit(&instrument->outputs[i]);
}
free(instrument->outputs);
for (uint32_t i = 0; i < instrument->aux_output_count; i++)
{
g_free(instrument->aux_output_names[i]);
}
free(instrument->aux_output_names);
free(instrument->aux_outputs);
CBOX_DELETE(instrument->module);
free(instrument);
}
void cbox_instrument_unref_aux_buses(struct cbox_instrument *instrument)
{
for (uint32_t j = 0; j < instrument->aux_output_count; j++)
{
if (instrument->aux_outputs[j])
cbox_aux_bus_unref(instrument->aux_outputs[j]);
}
}
void cbox_instrument_disconnect_aux_bus(struct cbox_instrument *instrument, struct cbox_aux_bus *bus)
{
for (uint32_t j = 0; j < instrument->aux_output_count; j++)
{
if (instrument->aux_outputs[j] == bus)
{
cbox_aux_bus_unref(instrument->aux_outputs[j]);
instrument->aux_outputs[j] = NULL;
}
}
}
void cbox_instrument_output_init(struct cbox_instrument_output *output, struct cbox_scene *scene, uint32_t max_numsamples)
{
cbox_recording_source_init(&output->rec_dry, scene, max_numsamples, 2);
cbox_recording_source_init(&output->rec_wet, scene, max_numsamples, 2);
output->insert = NULL;
output->output_bus = 0;
cbox_gain_init(&output->gain_obj);
}
void cbox_instrument_output_uninit(struct cbox_instrument_output *output)
{
cbox_recording_source_uninit(&output->rec_dry);
cbox_recording_source_uninit(&output->rec_wet);
if (output->insert)
{
CBOX_DELETE(output->insert);
output->insert = NULL;
}
}

61
template/calfbox/instr.h

@ -1,61 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_INSTR_H
#define CBOX_INSTR_H
#include "dspmath.h"
#include "recsrc.h"
CBOX_EXTERN_CLASS(cbox_instrument)
struct cbox_module;
struct cbox_rt;
struct cbox_scene;
struct cbox_instruments;
struct cbox_instrument_output
{
struct cbox_module *insert;
int output_bus;
struct cbox_gain gain_obj;
struct cbox_recording_source rec_dry, rec_wet;
};
struct cbox_instrument
{
CBOX_OBJECT_HEADER()
struct cbox_command_target cmd_target;
struct cbox_module *module;
struct cbox_instrument_output *outputs;
struct cbox_scene *scene;
int refcount;
gchar **aux_output_names;
struct cbox_aux_bus **aux_outputs;
uint32_t aux_output_count;
};
extern void cbox_instrument_unref_aux_buses(struct cbox_instrument *instrument);
extern void cbox_instrument_disconnect_aux_bus(struct cbox_instrument *instrument, struct cbox_aux_bus *bus);
extern void cbox_instrument_destroy_if_unused(struct cbox_instrument *instrument);
extern gboolean cbox_instrument_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error);
extern void cbox_instrument_output_init(struct cbox_instrument_output *output, struct cbox_scene *scene, uint32_t max_numsamples);
extern void cbox_instrument_output_uninit(struct cbox_instrument_output *output);
#endif

0
template/calfbox/py/instr_gui.py → template/calfbox/instr_gui.py

625
template/calfbox/io.c

@ -1,625 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "app.h"
#include "config.h"
#include "config-api.h"
#include "engine.h"
#include "errors.h"
#include "hwcfg.h"
#include "io.h"
#include "meter.h"
#include "midi.h"
#include "mididest.h"
#include "recsrc.h"
#include "seq.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
const char *cbox_io_section = "io";
gboolean cbox_io_init(struct cbox_io *io, struct cbox_open_params *const params, struct cbox_command_target *fb, GError **error)
{
#if USE_JACK
#if USE_LIBUSB
if (cbox_config_get_int(cbox_io_section, "use_usb", 0))
return cbox_io_init_usb(io, params, fb, error);
#endif
return cbox_io_init_jack(io, params, fb, error);
#else
#if USE_LIBUSB
return cbox_io_init_usb(io, params, fb, error);
#endif
#endif
}
int cbox_io_get_sample_rate(struct cbox_io *io)
{
return io->impl->getsampleratefunc(io->impl);
}
void cbox_io_poll_ports(struct cbox_io *io, struct cbox_command_target *fb)
{
io->impl->pollfunc(io->impl, fb);
}
int cbox_io_get_midi_data(struct cbox_io *io, struct cbox_midi_buffer *destination)
{
return io->impl->getmidifunc(io->impl, destination);
}
int cbox_io_start(struct cbox_io *io, struct cbox_io_callbacks *cb, struct cbox_command_target *fb)
{
io->cb = cb;
return io->impl->startfunc(io->impl, fb, NULL);
}
gboolean cbox_io_get_disconnect_status(struct cbox_io *io, GError **error)
{
return io->impl->getstatusfunc(io->impl, error);
}
gboolean cbox_io_cycle(struct cbox_io *io, struct cbox_command_target *fb, GError **error)
{
return io->impl->cyclefunc(io->impl, fb, error);
}
int cbox_io_stop(struct cbox_io *io)
{
int result = io->impl->stopfunc(io->impl, NULL);
if (io->cb && io->cb->on_stopped)
io->cb->on_stopped(io->cb->user_data);
io->cb = NULL;
return result;
}
struct cbox_midi_output *cbox_io_get_midi_output(struct cbox_io *io, const char *name, const struct cbox_uuid *uuid)
{
if (uuid)
{
for (GSList *p = io->midi_outputs; p; p = g_slist_next(p))
{
struct cbox_midi_output *midiout = p->data;
if (!midiout->removing && cbox_uuid_equal(&midiout->uuid, uuid))
return midiout;
}
}
if (name)
{
for (GSList *p = io->midi_outputs; p; p = g_slist_next(p))
{
struct cbox_midi_output *midiout = p->data;
if (!midiout->removing && !strcmp(midiout->name, name))
return midiout;
}
}
return NULL;
}
struct cbox_midi_input *cbox_io_get_midi_input(struct cbox_io *io, const char *name, const struct cbox_uuid *uuid)
{
if (uuid)
{
for (GSList *p = io->midi_inputs; p; p = g_slist_next(p))
{
struct cbox_midi_input *midiin = p->data;
if (!midiin->removing && cbox_uuid_equal(&midiin->uuid, uuid))
return midiin;
}
}
if (name)
{
for (GSList *p = io->midi_inputs; p; p = g_slist_next(p))
{
struct cbox_midi_input *midiin = p->data;
if (!midiin->removing && !strcmp(midiin->name, name))
return midiin;
}
}
return NULL;
}
struct cbox_audio_output *cbox_io_get_audio_output(struct cbox_io *io, const char *name, const struct cbox_uuid *uuid)
{
if (uuid)
{
for (GSList *p = io->audio_outputs; p; p = g_slist_next(p))
{
struct cbox_audio_output *audioout = p->data;
if (!audioout->removing && cbox_uuid_equal(&audioout->uuid, uuid))
return audioout;
}
}
if (name)
{
for (GSList *p = io->audio_outputs; p; p = g_slist_next(p))
{
struct cbox_audio_output *audioout = p->data;
if (!audioout->removing && !strcmp(audioout->name, name))
return audioout;
}
}
return NULL;
}
struct cbox_midi_output *cbox_io_create_midi_output(struct cbox_io *io, const char *name, GError **error)
{
struct cbox_midi_output *midiout = cbox_io_get_midi_output(io, name, NULL);
if (midiout)
return midiout;
midiout = io->impl->createmidioutfunc(io->impl, name, error);
if (!midiout)
return NULL;
io->midi_outputs = g_slist_prepend(io->midi_outputs, midiout);
// Notify client code to connect to new outputs if needed
if (io->cb->on_midi_outputs_changed)
io->cb->on_midi_outputs_changed(io->cb->user_data);
return midiout;
}
void cbox_io_destroy_midi_output(struct cbox_io *io, struct cbox_midi_output *midiout)
{
midiout->removing = TRUE;
// This is not a very efficient way to do it. However, in this case,
// the list will rarely contain more than 10 elements, so simplicity
// and correctness may be more important.
GSList *copy = g_slist_copy(io->midi_outputs);
copy = g_slist_remove(copy, midiout);
GSList *old = io->midi_outputs;
io->midi_outputs = copy;
cbox_midi_merger_close(&midiout->merger, app.rt);
assert(!midiout->merger.inputs);
// Notify client code to disconnect the output and to make sure the RT code
// is not using the old list anymore
if (io->cb->on_midi_outputs_changed)
io->cb->on_midi_outputs_changed(io->cb->user_data);
assert(!midiout->merger.inputs);
g_slist_free(old);
io->impl->destroymidioutfunc(io->impl, midiout);
}
struct cbox_midi_input *cbox_io_create_midi_input(struct cbox_io *io, const char *name, GError **error)
{
struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, name, NULL);
if (midiin)
return midiin;
midiin = io->impl->createmidiinfunc(io->impl, name, error);
if (!midiin)
return NULL;
io->midi_inputs = g_slist_prepend(io->midi_inputs, midiin);
// Notify client code to connect to new inputs if needed
if (io->cb->on_midi_inputs_changed)
io->cb->on_midi_inputs_changed(io->cb->user_data);
return midiin;
}
void cbox_io_destroy_midi_input(struct cbox_io *io, struct cbox_midi_input *midiin)
{
midiin->removing = TRUE;
// This is not a very efficient way to do it. However, in this case,
// the list will rarely contain more than 10 elements, so simplicity
// and correctness may be more important.
GSList *copy = g_slist_copy(io->midi_inputs);
copy = g_slist_remove(copy, midiin);
GSList *old = io->midi_inputs;
io->midi_inputs = copy;
// Notify client code to disconnect the input and to make sure the RT code
// is not using the old list anymore
if (io->cb->on_midi_inputs_changed)
io->cb->on_midi_inputs_changed(io->cb->user_data);
g_slist_free(old);
io->impl->destroymidiinfunc(io->impl, midiin);
}
void cbox_io_destroy_all_midi_ports(struct cbox_io *io)
{
for (GSList *p = io->midi_outputs; p; p = g_slist_next(p))
{
struct cbox_midi_output *midiout = p->data;
midiout->removing = TRUE;
}
for (GSList *p = io->midi_inputs; p; p = g_slist_next(p))
{
struct cbox_midi_output *midiin = p->data;
midiin->removing = TRUE;
}
GSList *old_i = io->midi_inputs, *old_o = io->midi_outputs;
io->midi_outputs = NULL;
io->midi_inputs = NULL;
// Notify client code to disconnect the output and to make sure the RT code
// is not using the old list anymore
if (io->cb && io->cb->on_midi_outputs_changed)
io->cb->on_midi_outputs_changed(io->cb->user_data);
if (io->cb && io->cb->on_midi_inputs_changed)
io->cb->on_midi_inputs_changed(io->cb->user_data);
while(old_o)
{
struct cbox_midi_output *midiout = old_o->data;
cbox_midi_merger_close(&midiout->merger, app.rt);
assert(!midiout->merger.inputs);
io->impl->destroymidioutfunc(io->impl, midiout);
old_o = g_slist_remove(old_o, midiout);
}
g_slist_free(old_o);
while(old_i)
{
struct cbox_midi_input *midiin = old_i->data;
io->impl->destroymidiinfunc(io->impl, midiin);
old_i = g_slist_remove(old_i, midiin);
}
g_slist_free(old_i);
}
static void cbox_audio_output_router_record_block(struct cbox_recorder *handler, const float **buffers, uint32_t offset, uint32_t numsamples)
{
struct cbox_audio_output_router *router = handler->user_data;
if (router->left->removing || router->right->removing)
return;
cbox_gain_add_stereo(&router->gain, &router->left->buffer[offset], buffers[0], &router->right->buffer[offset], buffers[1], numsamples);
}
static gboolean cbox_audio_output_router_attach(struct cbox_recorder *handler, struct cbox_recording_source *src, GError **error)
{
struct cbox_audio_output_router *router = handler->user_data;
if (router->attached)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Router already attached");
return FALSE;
}
router->source = src;
router->attached++;
return TRUE;
}
static gboolean cbox_audio_output_router_detach(struct cbox_recorder *handler, GError **error)
{
struct cbox_audio_output_router *router = handler->user_data;
if (router->attached != 1)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Router not yet attached");
return FALSE;
}
assert (router->source);
--router->attached;
assert (router->attached == 0);
router->source = NULL;
return TRUE;
}
static void cbox_audio_output_router_destroy(struct cbox_recorder *handler)
{
struct cbox_audio_output_router *router = handler->user_data;
if (router->attached)
cbox_recording_source_detach(router->source, &router->recorder, NULL);
assert(!router->attached);
router->left->users--;
router->right->users--;
}
static gboolean cbox_audio_output_router_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
struct cbox_audio_output_router *router = ct->user_data;
if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
if (!cbox_execute_on(fb, NULL, "/gain", "f", error, router->gain.db_gain))
return FALSE;
return CBOX_OBJECT_DEFAULT_STATUS(&router->recorder, fb, error);
}
if (!strcmp(cmd->command, "/gain") && !strcmp(cmd->arg_types, "f"))
{
cbox_gain_set_db(&router->gain, CBOX_ARG_F(cmd, 0));
return TRUE;
}
return cbox_object_default_process_cmd(ct, fb, cmd, error);
}
struct cbox_audio_output_router *cbox_io_create_audio_output_router(struct cbox_io *io, struct cbox_engine *engine, struct cbox_audio_output *left, struct cbox_audio_output *right)
{
struct cbox_audio_output_router *router = calloc(1, sizeof(struct cbox_audio_output_router));
CBOX_OBJECT_HEADER_INIT(&router->recorder, cbox_recorder, CBOX_GET_DOCUMENT(engine));
cbox_command_target_init(&router->recorder.cmd_target, cbox_audio_output_router_process_cmd, &router->recorder);
router->recorder.user_data = router;
router->recorder.attach = cbox_audio_output_router_attach;
router->recorder.record_block = cbox_audio_output_router_record_block;
router->recorder.detach = cbox_audio_output_router_detach;
router->recorder.destroy = cbox_audio_output_router_destroy;
router->source = NULL;
router->left = left;
router->right = right;
router->attached = 0;
cbox_gain_init(&router->gain);
cbox_gain_set_db(&router->gain, 12.0);
left->users++;
right->users++;
CBOX_OBJECT_REGISTER(&router->recorder);
return router;
}
struct cbox_audio_output *cbox_io_create_audio_output(struct cbox_io *io, const char *name, GError **error)
{
struct cbox_audio_output *audioout = cbox_io_get_audio_output(io, name, NULL);
if (audioout)
return audioout;
audioout = io->impl->createaudiooutfunc(io->impl, name, error);
if (!audioout)
return NULL;
io->audio_outputs = g_slist_prepend(io->audio_outputs, audioout);
// Notify client code to connect to new outputs if needed
if (io->cb->on_audio_outputs_changed)
io->cb->on_audio_outputs_changed(io->cb->user_data);
return audioout;
}
struct cbox_audio_output *cbox_io_get_audio_output_by_uuid_string(struct cbox_io *io, const char *uuidstr, GError **error)
{
struct cbox_uuid uuid;
if (!cbox_uuid_fromstring(&uuid, uuidstr, error))
return NULL;
struct cbox_audio_output *audioout = cbox_io_get_audio_output(io, NULL, &uuid);
if (!audioout)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr);
return NULL;
}
return audioout;
}
gboolean cbox_io_destroy_audio_output(struct cbox_io *io, struct cbox_audio_output *audioout, GError **error)
{
if (audioout->users)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' is in use", audioout->name);
return FALSE;
}
audioout->removing = TRUE;
// This is not a very efficient way to do it. However, in this case,
// the list will rarely contain more than 10 elements, so simplicity
// and correctness may be more important.
GSList *copy = g_slist_copy(io->audio_outputs);
copy = g_slist_remove(copy, audioout);
GSList *old = io->audio_outputs;
io->audio_outputs = copy;
// Notify client code to disconnect the output and to make sure the RT code
// is not using the old list anymore
if (io->cb->on_audio_outputs_changed)
io->cb->on_audio_outputs_changed(io->cb->user_data);
g_slist_free(old);
io->impl->destroyaudiooutfunc(io->impl, audioout);
return TRUE;
}
gboolean cbox_io_process_cmd(struct cbox_io *io, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error, gboolean *cmd_handled)
{
*cmd_handled = FALSE;
if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
{
*cmd_handled = TRUE;
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
for (GSList *p = io->midi_inputs; p; p = g_slist_next(p))
{
struct cbox_midi_input *midiin = p->data;
if (!midiin->removing)
{
if (!cbox_execute_on(fb, NULL, "/midi_input", "su", error, midiin->name, &midiin->uuid))
return FALSE;
}
}
for (GSList *p = io->midi_outputs; p; p = g_slist_next(p))
{
struct cbox_midi_output *midiout = p->data;
if (!midiout->removing)
{
if (!cbox_execute_on(fb, NULL, "/midi_output", "su", error, midiout->name, &midiout->uuid))
return FALSE;
}
}
return cbox_execute_on(fb, NULL, "/audio_inputs", "i", error, io->io_env.input_count) &&
cbox_execute_on(fb, NULL, "/audio_outputs", "i", error, io->io_env.output_count) &&
cbox_execute_on(fb, NULL, "/sample_rate", "i", error, io->io_env.srate) &&
cbox_execute_on(fb, NULL, "/buffer_size", "i", error, io->io_env.buffer_size);
}
else if (io->impl->createmidiinfunc && !strcmp(cmd->command, "/create_midi_input") && !strcmp(cmd->arg_types, "s"))
{
*cmd_handled = TRUE;
struct cbox_midi_input *midiin;
midiin = cbox_io_create_midi_input(io, CBOX_ARG_S(cmd, 0), error);
if (!midiin)
return FALSE;
cbox_midi_appsink_init(&midiin->appsink, app.rt, &app.engine->stmap->tmap);
return cbox_uuid_report(&midiin->uuid, fb, error);
}
else if (!strcmp(cmd->command, "/route_midi_input") && !strcmp(cmd->arg_types, "ss"))
{
*cmd_handled = TRUE;
const char *uuidstr = CBOX_ARG_S(cmd, 0);
struct cbox_uuid uuid;
if (!cbox_uuid_fromstring(&uuid, uuidstr, error))
return FALSE;
struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid);
if (!midiin)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr);
return FALSE;
}
if (*CBOX_ARG_S(cmd, 1))
{
if (cbox_uuid_fromstring(&midiin->output, CBOX_ARG_S(cmd, 1), error))
midiin->output_set = TRUE;
}
else
midiin->output_set = FALSE;
if (io->impl->updatemidiinroutingfunc)
io->impl->updatemidiinroutingfunc(io->impl);
if (io->cb->on_midi_inputs_changed)
io->cb->on_midi_inputs_changed(io->cb->user_data);
return TRUE;
}
else if (!strcmp(cmd->command, "/set_appsink_for_midi_input") && !strcmp(cmd->arg_types, "si"))
{
*cmd_handled = TRUE;
const char *uuidstr = CBOX_ARG_S(cmd, 0);
struct cbox_uuid uuid;
if (!cbox_uuid_fromstring(&uuid, uuidstr, error))
return FALSE;
struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid);
if (!midiin)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr);
return FALSE;
}
midiin->enable_appsink = CBOX_ARG_I(cmd, 1);
return TRUE;
}
else if (!strcmp(cmd->command, "/get_new_events") && !strcmp(cmd->arg_types, "s"))
{
*cmd_handled = TRUE;
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
const char *uuidstr = CBOX_ARG_S(cmd, 0);
struct cbox_uuid uuid;
if (!cbox_uuid_fromstring(&uuid, uuidstr, error))
return FALSE;
struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid);
if (!midiin)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr);
return FALSE;
}
if (!midiin->enable_appsink)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "App sink not enabled for port '%s'", uuidstr);
return FALSE;
}
return cbox_midi_appsink_send_to(&midiin->appsink, fb, error);
}
else if (io->impl->createmidioutfunc && !strcmp(cmd->command, "/create_midi_output") && !strcmp(cmd->arg_types, "s"))
{
*cmd_handled = TRUE;
struct cbox_midi_output *midiout;
midiout = cbox_io_create_midi_output(io, CBOX_ARG_S(cmd, 0), error);
if (!midiout)
return FALSE;
return cbox_uuid_report(&midiout->uuid, fb, error);
}
else if (io->impl->destroymidiinfunc && !strcmp(cmd->command, "/delete_midi_input") && !strcmp(cmd->arg_types, "s"))
{
*cmd_handled = TRUE;
const char *uuidstr = CBOX_ARG_S(cmd, 0);
struct cbox_uuid uuid;
if (!cbox_uuid_fromstring(&uuid, uuidstr, error))
return FALSE;
struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid);
if (!midiin)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr);
return FALSE;
}
cbox_io_destroy_midi_input(io, midiin);
return TRUE;
}
else if (io->impl->destroymidioutfunc && !strcmp(cmd->command, "/delete_midi_output") && !strcmp(cmd->arg_types, "s"))
{
*cmd_handled = TRUE;
const char *uuidstr = CBOX_ARG_S(cmd, 0);
struct cbox_uuid uuid;
if (!cbox_uuid_fromstring(&uuid, uuidstr, error))
return FALSE;
struct cbox_midi_output *midiout = cbox_io_get_midi_output(io, NULL, &uuid);
if (!midiout)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr);
return FALSE;
}
cbox_io_destroy_midi_output(io, midiout);
return TRUE;
}
else if (io->impl->createaudiooutfunc && !strcmp(cmd->command, "/create_audio_output") && !strcmp(cmd->arg_types, "s"))
{
*cmd_handled = TRUE;
struct cbox_audio_output *audioout;
audioout = cbox_io_create_audio_output(io, CBOX_ARG_S(cmd, 0), error);
if (!audioout)
return FALSE;
return cbox_uuid_report(&audioout->uuid, fb, error);
}
else if (io->impl->destroyaudiooutfunc && !strcmp(cmd->command, "/delete_audio_output") && !strcmp(cmd->arg_types, "s"))
{
*cmd_handled = TRUE;
const char *uuidstr = CBOX_ARG_S(cmd, 0);
struct cbox_audio_output *audioout = cbox_io_get_audio_output_by_uuid_string(io, uuidstr, error);
if (!audioout)
return FALSE;
return cbox_io_destroy_audio_output(io, audioout, error);
}
else if (io->impl->createmidioutfunc && !strcmp(cmd->command, "/create_audio_output_router") && !strcmp(cmd->arg_types, "ss"))
{
*cmd_handled = TRUE;
const char *uuidstr = CBOX_ARG_S(cmd, 0);
struct cbox_audio_output *left = cbox_io_get_audio_output_by_uuid_string(io, uuidstr, error);
if (!left)
return FALSE;
uuidstr = CBOX_ARG_S(cmd, 1);
struct cbox_audio_output *right = cbox_io_get_audio_output_by_uuid_string(io, uuidstr, error);
if (!right)
return FALSE;
// XXXKF hack alert
struct cbox_audio_output_router *router = cbox_io_create_audio_output_router(io, app.engine, left, right);
return cbox_uuid_report(&router->recorder._obj_hdr.instance_uuid, fb, error);
}
return FALSE;
}
void cbox_io_close(struct cbox_io *io)
{
io->impl->destroyfunc(io->impl);
io->impl = NULL;
}

194
template/calfbox/io.h

@ -1,194 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_IO_H
#define CBOX_IO_H
#include <glib.h>
#include "config.h"
#if USE_JACK
#include <jack/jack.h>
#endif
#include "dspmath.h"
#include "dom.h"
#include "ioenv.h"
#include "master.h"
#include "mididest.h"
#include "recsrc.h"
struct cbox_io;
struct cbox_io_callbacks;
struct cbox_recording_source;
struct cbox_meter;
struct cbox_midi_buffer;
struct cbox_scene;
struct cbox_open_params
{
};
struct cbox_io_impl
{
struct cbox_io *pio;
int (*getsampleratefunc)(struct cbox_io_impl *ioi);
gboolean (*startfunc)(struct cbox_io_impl *ioi, struct cbox_command_target *fb, GError **error);
gboolean (*stopfunc)(struct cbox_io_impl *ioi, GError **error);
gboolean (*cyclefunc)(struct cbox_io_impl *ioi, struct cbox_command_target *fb, GError **error);
gboolean (*getstatusfunc)(struct cbox_io_impl *ioi, GError **error);
void (*pollfunc)(struct cbox_io_impl *ioi, struct cbox_command_target *fb);
int (*getmidifunc)(struct cbox_io_impl *ioi, struct cbox_midi_buffer *destination);
struct cbox_midi_output *(*createmidioutfunc)(struct cbox_io_impl *ioi, const char *name, GError **error);
void (*destroymidioutfunc)(struct cbox_io_impl *ioi, struct cbox_midi_output *midiout);
struct cbox_midi_input *(*createmidiinfunc)(struct cbox_io_impl *ioi, const char *name, GError **error);
void (*destroymidiinfunc)(struct cbox_io_impl *ioi, struct cbox_midi_input *midiout);
void (*updatemidiinroutingfunc)(struct cbox_io_impl *ioi);
struct cbox_audio_output *(*createaudiooutfunc)(struct cbox_io_impl *ioi, const char *name, GError **error);
void (*destroyaudiooutfunc)(struct cbox_io_impl *ioi, struct cbox_audio_output *audioout);
void (*controltransportfunc)(struct cbox_io_impl *ioi, gboolean roll, uint32_t pos); // (uint32_t)-1 if no change
gboolean (*getsynccompletedfunc)(struct cbox_io_impl *ioi);
void (*destroyfunc)(struct cbox_io_impl *ioi);
};
struct cbox_io
{
struct cbox_io_impl *impl;
struct cbox_command_target cmd_target;
float **input_buffers; // only valid inside jack_rt_process
float **output_buffers; // only valid inside jack_rt_process
struct cbox_io_env io_env;
struct cbox_io_callbacks *cb;
GSList *midi_inputs;
GSList *midi_outputs;
GSList *audio_outputs;
uint32_t free_running_frame_counter;
};
enum cbox_transport_state
{
ts_stopping,
ts_stopped,
ts_starting,
ts_rolling,
};
struct cbox_transport_position
{
uint32_t bar;
uint32_t beat;
uint32_t tick;
uint32_t offset;
double tempo;
double ticks_per_beat;
double bar_start_tick;
uint32_t timesig_num;
uint32_t timesig_denom;
};
struct cbox_io_callbacks
{
void *user_data;
void (*process)(void *user_data, struct cbox_io *io, uint32_t nframes);
void (*on_started)(void *user_data);
void (*on_stopped)(void *user_data);
void (*on_disconnected)(void *user_data);
void (*on_reconnected)(void *user_data);
void (*on_midi_inputs_changed)(void *user_data);
void (*on_midi_outputs_changed)(void *user_data);
void (*on_audio_outputs_changed)(void *user_data);
gboolean (*on_transport_sync)(void *user_data, enum cbox_transport_state state, uint32_t frame);
void (*get_transport_data)(void *user_data, gboolean explicit_pos, uint32_t time_samples, struct cbox_transport_position *tp);
gboolean (*on_tempo_sync)(void *user_data, double beats_per_minute);
};
struct cbox_midi_input
{
gchar *name;
struct cbox_uuid uuid;
struct cbox_midi_buffer buffer;
gboolean removing;
gboolean output_set;
struct cbox_uuid output;
gboolean enable_appsink;
struct cbox_midi_appsink appsink;
};
struct cbox_midi_output
{
gchar *name;
struct cbox_uuid uuid;
struct cbox_midi_buffer buffer;
struct cbox_midi_merger merger;
// This is set if the output is in process of being removed and should not
// be used for output.
gboolean removing;
};
struct cbox_audio_output
{
gchar *name;
struct cbox_uuid uuid;
// This is set if the output is in process of being removed and should not
// be used for output.
gboolean removing;
float *buffer;
uint32_t users;
};
struct cbox_audio_output_router
{
struct cbox_recorder recorder;
struct cbox_recording_source *source;
struct cbox_audio_output *left, *right;
struct cbox_gain gain;
int attached;
};
extern gboolean cbox_io_init(struct cbox_io *io, struct cbox_open_params *const params, struct cbox_command_target *fb, GError **error);
#if USE_JACK
extern gboolean cbox_io_init_jack(struct cbox_io *io, struct cbox_open_params *const params, struct cbox_command_target *fb, GError **error);
#endif
extern gboolean cbox_io_init_usb(struct cbox_io *io, struct cbox_open_params *const params, struct cbox_command_target *fb, GError **error);
extern int cbox_io_start(struct cbox_io *io, struct cbox_io_callbacks *cb, struct cbox_command_target *fb);
extern int cbox_io_stop(struct cbox_io *io);
extern int cbox_io_get_sample_rate(struct cbox_io *io);
extern int cbox_io_get_midi_data(struct cbox_io *io, struct cbox_midi_buffer *destination);
extern gboolean cbox_io_get_disconnect_status(struct cbox_io *io, GError **error);
extern gboolean cbox_io_cycle(struct cbox_io *io, struct cbox_command_target *fb, GError **error);
extern void cbox_io_poll_ports(struct cbox_io *io, struct cbox_command_target *fb);
extern struct cbox_midi_input *cbox_io_get_midi_input(struct cbox_io *io, const char *name, const struct cbox_uuid *uuid);
extern struct cbox_midi_output *cbox_io_get_midi_output(struct cbox_io *io, const char *name, const struct cbox_uuid *uuid);
extern struct cbox_audio_output *cbox_io_get_audio_output(struct cbox_io *io, const char *name, const struct cbox_uuid *uuid);
extern struct cbox_audio_output *cbox_io_get_audio_output_by_uuid_string(struct cbox_io *io, const char *uuidstr, GError **error);
extern struct cbox_midi_output *cbox_io_create_midi_output(struct cbox_io *io, const char *name, GError **error);
extern void cbox_io_destroy_midi_output(struct cbox_io *io, struct cbox_midi_output *midiout);
extern struct cbox_audio_output *cbox_io_create_audio_output(struct cbox_io *io, const char *name, GError **error);
extern gboolean cbox_io_destroy_audio_output(struct cbox_io *io, struct cbox_audio_output *audioout, GError **error);
extern struct cbox_midi_input *cbox_io_create_midi_input(struct cbox_io *io, const char *name, GError **error);
extern void cbox_io_destroy_midi_input(struct cbox_io *io, struct cbox_midi_input *midiin);
extern void cbox_io_destroy_all_midi_ports(struct cbox_io *io);
extern gboolean cbox_io_process_cmd(struct cbox_io *io, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error, gboolean *cmd_handled);
extern void cbox_io_close(struct cbox_io *io);
extern const char *cbox_io_section;
#endif

46
template/calfbox/ioenv.h

@ -1,46 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2013 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_IOENV_H
#define CBOX_IOENV_H
struct cbox_io_env
{
int srate;
uint32_t buffer_size;
uint32_t input_count, output_count;
};
static inline void cbox_io_env_clear(struct cbox_io_env *env)
{
env->srate = 0;
env->buffer_size = 0;
env->input_count = 0;
env->output_count = 0;
}
static inline void cbox_io_env_copy(struct cbox_io_env *dest, const struct cbox_io_env *src)
{
dest->srate = src->srate;
dest->buffer_size = src->buffer_size;
dest->input_count = src->input_count;
dest->output_count = src->output_count;
}
#endif

177
template/calfbox/jack_api_example.py

@ -1,177 +0,0 @@
from calfbox import cbox
import time
def cmd_dumper(cmd, fb, args):
print ("%s(%s)" % (cmd, ",".join(list(map(repr,args)))))
cbox.init_engine()
cbox.Config.add_section("drumpattern:pat1", """
title=Straight - Verse
beats=4
track1=bd
track2=sd
track3=hh
track4=ho
bd_note=c1
sd_note=d1
hh_note=f#1
ho_note=a#1
bd_trigger=9... .... 9.6. ....
sd_trigger=.... 9..5 .2.. 9...
hh_trigger=9353 7353 7353 73.3
ho_trigger=.... .... .... ..3.
""")
cbox.Config.set("io", "use_usb", 0)
cbox.start_audio(cmd_dumper)
global Document
Document = cbox.Document
status = cbox.JackIO.status()
client_name = status.client_name
print ("Client name: %s" % client_name)
print ("Audio inputs: %d, outputs: %d" % (status.audio_inputs, status.audio_outputs))
print ("Sample rate: %d frames/sec" % (status.sample_rate))
print ("JACK period: %d frames" % (status.buffer_size))
uuid_bad = cbox.JackIO.create_midi_output('bad')
uuid_bad2 = cbox.JackIO.create_midi_input('bad2')
cbox.JackIO.autoconnect_midi_output(uuid_bad, '%s:bad2' % client_name)
print (cbox.JackIO.get_connected_ports('%s:bad' % client_name))
try:
cbox.JackIO.disconnect_midi_input(uuid_bad)
assert False
except:
pass
try:
cbox.JackIO.disconnect_midi_output(uuid_bad2)
assert False
except:
pass
assert len(cbox.JackIO.get_connected_ports('%s:bad' % client_name)) == 1
assert cbox.JackIO.get_connected_ports('%s:bad' % client_name) == cbox.JackIO.get_connected_ports(uuid_bad)
assert cbox.JackIO.get_connected_ports('%s:bad2' % client_name) == cbox.JackIO.get_connected_ports(uuid_bad2)
cbox.JackIO.disconnect_midi_output(uuid_bad)
assert cbox.JackIO.get_connected_ports('%s:bad' % client_name) == []
assert cbox.JackIO.get_connected_ports('%s:bad2' % client_name) == []
assert cbox.JackIO.get_connected_ports(uuid_bad) == []
assert cbox.JackIO.get_connected_ports(uuid_bad2) == []
cbox.JackIO.autoconnect_midi_output(uuid_bad2, '%s:bad' % client_name)
assert len(cbox.JackIO.get_connected_ports('%s:bad' % client_name)) == 1
assert cbox.JackIO.get_connected_ports('%s:bad' % client_name) == cbox.JackIO.get_connected_ports(uuid_bad)
assert cbox.JackIO.get_connected_ports('%s:bad2' % client_name) == cbox.JackIO.get_connected_ports(uuid_bad2)
cbox.JackIO.disconnect_midi_input(uuid_bad2)
assert cbox.JackIO.get_connected_ports('%s:bad' % client_name) == []
assert cbox.JackIO.get_connected_ports('%s:bad2' % client_name) == []
assert cbox.JackIO.get_connected_ports(uuid_bad) == []
assert cbox.JackIO.get_connected_ports(uuid_bad2) == []
cbox.JackIO.autoconnect_midi_output(uuid_bad2, '%s:bad' % client_name)
assert len(cbox.JackIO.get_connected_ports('%s:bad' % client_name)) == 1
assert cbox.JackIO.get_connected_ports('%s:bad' % client_name) == cbox.JackIO.get_connected_ports(uuid_bad)
assert cbox.JackIO.get_connected_ports('%s:bad2' % client_name) == cbox.JackIO.get_connected_ports(uuid_bad2)
cbox.JackIO.disconnect_midi_port(uuid_bad)
assert cbox.JackIO.get_connected_ports('%s:bad' % client_name) == []
assert cbox.JackIO.get_connected_ports('%s:bad2' % client_name) == []
assert cbox.JackIO.get_connected_ports(uuid_bad) == []
assert cbox.JackIO.get_connected_ports(uuid_bad2) == []
cbox.JackIO.autoconnect_midi_output(uuid_bad2, '%s:bad' % client_name)
assert len(cbox.JackIO.get_connected_ports('%s:bad' % client_name)) == 1
assert cbox.JackIO.get_connected_ports('%s:bad' % client_name) == cbox.JackIO.get_connected_ports(uuid_bad)
assert cbox.JackIO.get_connected_ports('%s:bad2' % client_name) == cbox.JackIO.get_connected_ports(uuid_bad2)
cbox.JackIO.disconnect_midi_port(uuid_bad2)
assert cbox.JackIO.get_connected_ports('%s:bad' % client_name) == []
assert cbox.JackIO.get_connected_ports('%s:bad2' % client_name) == []
assert cbox.JackIO.get_connected_ports(uuid_bad) == []
assert cbox.JackIO.get_connected_ports(uuid_bad2) == []
cbox.JackIO.delete_midi_output(uuid_bad)
cbox.JackIO.delete_midi_input(uuid_bad2)
uuid = cbox.JackIO.create_midi_output('drums')
cbox.JackIO.autoconnect_midi_output(uuid, '*alsa_pcm:.*')
cbox.JackIO.rename_midi_output(uuid, 'kettles')
uuid_in = cbox.JackIO.create_midi_input('extra')
cbox.JackIO.autoconnect_midi_input(uuid_in, '*alsa_pcm:.*')
cbox.JackIO.rename_midi_input(uuid_in, 'extra_port')
uuid2 = cbox.JackIO.create_midi_output('violins')
print (cbox.JackIO.jack_transport_position())
status = cbox.JackIO.status()
print ("Before deleting, MIDI outputs: %s" % status.midi_output)
cbox.JackIO.delete_midi_output(uuid2)
status = cbox.JackIO.status()
print ("After deleting, MIDI outputs: %s" % status.midi_output)
print ("Physical audio inputs: %s" % (",".join(cbox.JackIO.get_ports(".*", cbox.JackIO.AUDIO_TYPE, cbox.JackIO.PORT_IS_SOURCE | cbox.JackIO.PORT_IS_PHYSICAL))))
print ("Physical audio outputs: %s" % (",".join(cbox.JackIO.get_ports(".*", cbox.JackIO.AUDIO_TYPE, cbox.JackIO.PORT_IS_SINK | cbox.JackIO.PORT_IS_PHYSICAL))))
print ("Physical MIDI inputs: %s" % (",".join(cbox.JackIO.get_ports(".*", cbox.JackIO.MIDI_TYPE, cbox.JackIO.PORT_IS_SOURCE | cbox.JackIO.PORT_IS_PHYSICAL))))
print ("Physical MIDI outputs: %s" % (",".join(cbox.JackIO.get_ports(".*", cbox.JackIO.MIDI_TYPE, cbox.JackIO.PORT_IS_SINK | cbox.JackIO.PORT_IS_PHYSICAL))))
inputs = cbox.JackIO.get_ports(".*", cbox.JackIO.AUDIO_TYPE, cbox.JackIO.PORT_IS_SOURCE | cbox.JackIO.PORT_IS_PHYSICAL)
outputs = cbox.JackIO.get_ports(".*", cbox.JackIO.AUDIO_TYPE, cbox.JackIO.PORT_IS_SINK | cbox.JackIO.PORT_IS_PHYSICAL)
cbox.JackIO.port_connect(inputs[0], outputs[0])
cbox.JackIO.port_connect(inputs[1], outputs[1])
#assert "cbox:in_3" in cbox.JackIO.get_connected_ports(inputs[0])
cbox.JackIO.port_disconnect(inputs[0], outputs[0])
cbox.JackIO.port_disconnect(inputs[1], outputs[1])
scene = Document.get_scene()
scene.clear()
instrument = scene.add_new_instrument_layer("test_sampler", "sampler").get_instrument()
pgm_no = instrument.engine.get_unused_program()
pgm = instrument.engine.load_patch_from_file(pgm_no, 'synthbass.sfz', 'SynthBass')
instrument.engine.set_patch(1, pgm_no)
instrument.engine.set_patch(10, pgm_no)
song = Document.get_song()
track = song.add_track()
track.set_external_output(uuid)
print ("Track outputs to: %s:%s" % (client_name, track.status().external_output))
pattern = song.load_drum_pattern("pat1")
track.add_clip(0, 0, pattern.status().loop_end, pattern)
song.set_loop(0, pattern.status().loop_end)
song.update_playback()
cbox.Transport.play()
cbox.JackIO.transport_mode(True, False)
while not cbox.JackIO.jack_transport_position().is_master:
print ("Waiting to become the master")
time.sleep(0.01)
cbox.JackIO.transport_mode(False)
while cbox.JackIO.jack_transport_position().is_master:
print ("Waiting to stop being the master")
time.sleep(0.01)
cbox.JackIO.external_tempo(False)
assert cbox.JackIO.status().external_tempo == False
cbox.JackIO.external_tempo(True)
assert cbox.JackIO.status().external_tempo == True
uuid3 = cbox.JackIO.create_audio_output('noises')
assert "cbox:noises" in cbox.JackIO.get_ports(".*:noises", cbox.JackIO.AUDIO_TYPE, cbox.JackIO.PORT_IS_SOURCE)
cbox.JackIO.rename_audio_output(uuid3, "silence")
router = cbox.JackIO.create_audio_output_router(uuid3, uuid3)
assert type(router) is cbox.DocRecorder
try:
cbox.JackIO.delete_audio_output(uuid3)
assert False
except Exception as e:
assert 'is in use' in str(e)
router.delete()
assert "cbox:noises" not in cbox.JackIO.get_ports(".*:noises", cbox.JackIO.AUDIO_TYPE, cbox.JackIO.PORT_IS_SOURCE)
assert "cbox:silence" in cbox.JackIO.get_ports(".*:silence", cbox.JackIO.AUDIO_TYPE, cbox.JackIO.PORT_IS_SOURCE)
cbox.JackIO.delete_audio_output(uuid3)
assert "cbox:silence" not in cbox.JackIO.get_ports(".*:silence", cbox.JackIO.AUDIO_TYPE, cbox.JackIO.PORT_IS_SOURCE)
print("Ready!")
while True:
events = cbox.get_new_events()
if events:
print (events)
time.sleep(0.05)

65
template/calfbox/jack_audio_routing.py

@ -1,65 +0,0 @@
from calfbox import cbox
import time
def cmd_dumper(cmd, fb, args):
print ("%s(%s)" % (cmd, ",".join(list(map(repr,args)))))
cbox.init_engine()
cbox.Config.set("io", "use_usb", 0)
cbox.start_audio(cmd_dumper)
global Document
Document = cbox.Document
status = cbox.JackIO.status()
client_name = status.client_name
print ("Client name: %s" % client_name)
print ("Audio inputs: %d, outputs: %d" % (status.audio_inputs, status.audio_outputs))
print ("Sample rate: %d frames/sec" % (status.sample_rate))
print ("JACK period: %d frames" % (status.buffer_size))
inputs = cbox.JackIO.get_ports(".*", cbox.JackIO.AUDIO_TYPE, cbox.JackIO.PORT_IS_SOURCE | cbox.JackIO.PORT_IS_PHYSICAL)
outputs = cbox.JackIO.get_ports(".*", cbox.JackIO.AUDIO_TYPE, cbox.JackIO.PORT_IS_SINK | cbox.JackIO.PORT_IS_PHYSICAL)
scene = Document.get_scene()
scene.clear()
instrument = scene.add_new_instrument_layer("test_sampler", "sampler").get_instrument()
pgm_no = instrument.engine.get_unused_program()
pgm = instrument.engine.load_patch_from_file(pgm_no, 'synthbass.sfz', 'SynthBass')
instrument.engine.set_patch(1, pgm_no)
instrument.engine.set_patch(10, pgm_no)
print ("Connecting")
uuid = cbox.JackIO.create_audio_output('noises')
router = cbox.JackIO.create_audio_output_router(uuid, uuid)
assert type(router) is cbox.DocRecorder
router2 = cbox.JackIO.create_audio_output_router(uuid, uuid)
assert type(router2) is cbox.DocRecorder
instrument.get_output_slot(0).rec_wet.attach(router)
instrument.get_output_slot(0).rec_wet.attach(router2)
exc = None
try:
instrument.get_output_slot(0).rec_wet.attach(router2)
except Exception as e:
exc = e
assert "Router already attached" in str(exc)
instrument.get_output_slot(0).rec_wet.detach(router2)
try:
instrument.get_output_slot(0).rec_wet.detach(router2)
except Exception as e:
exc = e
assert "Recorder is not attached" in str(exc)
router.delete()
print("Ready!")
while True:
events = cbox.get_new_events()
if events:
print (events)
time.sleep(0.05)

50
template/calfbox/jack_output_routing.py

@ -1,50 +0,0 @@
from calfbox import cbox
import time
def cmd_dumper(cmd, fb, args):
print ("%s(%s)" % (cmd, ",".join(list(map(repr,args)))))
cbox.init_engine()
cbox.Config.set("io", "use_usb", 0)
cbox.Config.set("io", "midi", "*.*")
cbox.start_audio(cmd_dumper)
global Document
Document = cbox.Document
status = cbox.JackIO.status()
client_name = status.client_name
print ("Client name: %s" % client_name)
print ("Audio inputs: %d, outputs: %d" % (status.audio_inputs, status.audio_outputs))
print ("Sample rate: %d frames/sec" % (status.sample_rate))
print ("JACK period: %d frames" % (status.buffer_size))
left_dry = cbox.JackIO.create_audio_output('left_dry')
right_dry = cbox.JackIO.create_audio_output('right_dry')
left_wet = cbox.JackIO.create_audio_output('left_wet', '#1')
right_wet = cbox.JackIO.create_audio_output('right_wet', '#2')
router_dry = cbox.JackIO.create_audio_output_router(left_dry, right_dry)
assert type(router_dry) is cbox.DocRecorder
router_wet = cbox.JackIO.create_audio_output_router(left_wet, right_wet)
assert type(router_wet) is cbox.DocRecorder
scene = Document.get_scene()
scene.clear()
instrument = scene.add_new_instrument_layer("test_sampler", "tonewheel_organ").get_instrument()
instrument.get_output_slot(0).set_insert_engine("delay")
instrument.get_output_slot(0).rec_dry.attach(router_dry)
instrument.get_output_slot(0).rec_wet.attach(router_wet)
assert router_dry.uuid == instrument.get_output_slot(0).rec_dry.status().handler[0].uuid
assert router_wet.uuid == instrument.get_output_slot(0).rec_wet.status().handler[0].uuid
router_wet.set_gain(-3.0)
assert router_wet.status().gain == -3
print("Ready!")
while True:
events = cbox.get_new_events()
if events:
print (events)
time.sleep(0.05)

36
template/calfbox/jack_scene_routing.py

@ -1,36 +0,0 @@
from calfbox import cbox
import time
def cmd_dumper(cmd, fb, args):
print ("%s(%s)" % (cmd, ",".join(list(map(repr,args)))))
cbox.init_engine()
cbox.Config.set("io", "use_usb", 0)
cbox.start_audio(cmd_dumper)
global Document
Document = cbox.Document
status = cbox.JackIO.status()
client_name = status.client_name
print ("Client name: %s" % client_name)
print ("Audio inputs: %d, outputs: %d" % (status.audio_inputs, status.audio_outputs))
print ("Sample rate: %d frames/sec" % (status.sample_rate))
print ("JACK period: %d frames" % (status.buffer_size))
uuid_ext1 = cbox.JackIO.create_midi_output('ext1')
uuid_ext2 = cbox.JackIO.create_midi_output('ext2')
scene = Document.get_scene()
scene.clear()
layer = scene.add_new_midi_layer(uuid_ext2)
#layer.set_external_output(uuid_ext1)
print("Ready!")
while True:
events = cbox.get_new_events()
if events:
print (events)
time.sleep(0.05)

153
template/calfbox/jackinput.c

@ -1,153 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "app.h"
#include "config.h"
#include "config-api.h"
#include "dspmath.h"
#include "module.h"
#include <glib.h>
#include <malloc.h>
#include <math.h>
#include <memory.h>
#include <sndfile.h>
#include <stdio.h>
#include <stdlib.h>
#if USE_JACK
struct jack_input_module
{
struct cbox_module module;
int inputs[2];
int offset;
};
void jack_input_process_event(struct cbox_module *module, const uint8_t *data, uint32_t len)
{
// struct jack_input_module *m = module->user_data;
}
void jack_input_process_block(struct cbox_module *module, cbox_sample_t **inputs, cbox_sample_t **outputs)
{
struct jack_input_module *m = module->user_data;
for (int i = 0; i < 2; i++)
{
if (m->inputs[i] < 0)
{
for (int j = 0; j < CBOX_BLOCK_SIZE; j++)
outputs[i][j] = 0;
}
else
{
float *src = module->rt->io->input_buffers[m->inputs[i]] + m->offset;
for (int j = 0; j < CBOX_BLOCK_SIZE; j++)
outputs[i][j] = src[j];
}
}
m->offset = (m->offset + CBOX_BLOCK_SIZE) % app.io.io_env.buffer_size;
}
static gboolean validate_input_index(int input, const char *cfg_section, const char *type, GError **error)
{
if ((input < 1 || input > (int)app.io.io_env.input_count) && input != -1)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_OUT_OF_RANGE, "%s: invalid value for %s (%d), allowed values are 1..%d or -1 for unconnected", cfg_section, type, input, app.io.io_env.input_count);
return FALSE;
}
return TRUE;
}
static void jack_input_destroyfunc(struct cbox_module *module)
{
}
static int to_base1(int val)
{
if (val < 0)
return val;
return 1 + val;
}
gboolean jack_input_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
struct jack_input_module *m = ct->user_data;
if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
if (!cbox_execute_on(fb, NULL, "/inputs", "ii", error, to_base1(m->inputs[0]), to_base1(m->inputs[1])))
return FALSE;
return CBOX_OBJECT_DEFAULT_STATUS(&m->module, fb, error);
}
else if (!strcmp(cmd->command, "/inputs") && !strcmp(cmd->arg_types, "ii"))
{
int left_input = CBOX_ARG_I(cmd, 0);
int right_input = CBOX_ARG_I(cmd, 1);
if (!validate_input_index(left_input, "script", "left input", error))
return FALSE;
if (!validate_input_index(right_input, "script", "right input", error))
return FALSE;
m->inputs[0] = left_input < 0 ? -1 : left_input - 1;
m->inputs[1] = right_input < 0 ? -1 : right_input - 1;
return TRUE;
}
else
return cbox_object_default_process_cmd(ct, fb, cmd, error);
return TRUE;
}
MODULE_CREATE_FUNCTION(jack_input)
{
static int inited = 0;
if (!inited)
{
inited = 1;
}
int left_input = cbox_config_get_int(cfg_section, "left_input", 1);
int right_input = cbox_config_get_int(cfg_section, "right_input", 2);
if (!validate_input_index(left_input, cfg_section, "left_input", error))
return NULL;
if (!validate_input_index(right_input, cfg_section, "right_input", error))
return NULL;
struct jack_input_module *m = malloc(sizeof(struct jack_input_module));
CALL_MODULE_INIT(m, 0, 2, jack_input);
m->module.process_event = jack_input_process_event;
m->module.process_block = jack_input_process_block;
m->inputs[0] = left_input - 1;
m->inputs[1] = right_input - 1;
m->offset = 0;
return &m->module;
}
struct cbox_module_keyrange_metadata jack_input_keyranges[] = {
};
struct cbox_module_livecontroller_metadata jack_input_controllers[] = {
};
DEFINE_MODULE(jack_input, 0, 2)
#endif

1429
template/calfbox/jackio.c

File diff suppressed because it is too large

293
template/calfbox/layer.c

@ -1,293 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config-api.h"
#include "errors.h"
#include "instr.h"
#include "layer.h"
#include "midi.h"
#include "module.h"
#include "rt.h"
#include "scene.h"
#include <glib.h>
gboolean cbox_layer_load(struct cbox_layer *layer, const char *name, GError **error)
{
const char *cv = NULL;
struct cbox_instrument *instr = NULL;
gchar *section = g_strdup_printf("layer:%s", name);
if (!cbox_config_has_section(section))
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Missing section for layer %s", name);
goto error;
}
cv = cbox_config_get_string(section, "instrument");
if (cv)
{
instr = cbox_scene_get_instrument_by_name(layer->scene, cv, TRUE, error);
if (!instr)
{
cbox_force_error(error);
g_prefix_error(error, "Cannot get instrument %s for layer %s: ", cv, name);
goto error;
}
}
layer->enabled = cbox_config_get_int(section, "enabled", TRUE);
layer->low_note = 0;
layer->high_note = 127;
cv = cbox_config_get_string(section, "low_note");
if (cv)
layer->low_note = note_from_string(cv);
cv = cbox_config_get_string(section, "high_note");
if (cv)
layer->high_note = note_from_string(cv);
layer->transpose = cbox_config_get_int(section, "transpose", 0);
layer->fixed_note = cbox_config_get_int(section, "fixed_note", -1);
layer->in_channel = cbox_config_get_int(section, "in_channel", 0) - 1;
layer->out_channel = cbox_config_get_int(section, "out_channel", 0) - 1;
layer->disable_aftertouch = !cbox_config_get_int(section, "aftertouch", TRUE);
layer->invert_sustain = cbox_config_get_int(section, "invert_sustain", FALSE);
layer->consume = cbox_config_get_int(section, "consume", FALSE);
layer->ignore_scene_transpose = cbox_config_get_int(section, "ignore_scene_transpose", FALSE);
layer->ignore_program_changes = cbox_config_get_int(section, "ignore_program_changes", FALSE);
layer->external_output_set = FALSE;
g_free(section);
cbox_layer_set_instrument(layer, instr);
return 1;
error:
if (instr)
cbox_instrument_destroy_if_unused(instr);
g_free(section);
return 0;
}
void cbox_layer_set_instrument(struct cbox_layer *layer, struct cbox_instrument *instrument)
{
if (layer->instrument)
{
layer->instrument->refcount--;
cbox_instrument_destroy_if_unused(layer->instrument);
layer->instrument = NULL;
}
layer->instrument = instrument;
if (layer->instrument)
layer->instrument->refcount++;
}
static gboolean cbox_layer_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error);
static void cbox_layer_destroyfunc(struct cbox_objhdr *objhdr)
{
struct cbox_layer *layer = CBOX_H2O(objhdr);
if (layer->instrument && !--(layer->instrument->refcount))
{
if (layer->instrument->scene)
cbox_scene_remove_instrument(layer->instrument->scene, layer->instrument);
cbox_instrument_destroy_if_unused(layer->instrument);
}
if (layer->external_merger) {
cbox_midi_merger_disconnect(layer->external_merger, &layer->output_buffer, layer->scene->rt);
}
free(layer);
}
gboolean cbox_layer_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
struct cbox_layer *layer = ct->user_data;
if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
if (!(cbox_execute_on(fb, NULL, "/enable", "i", error, (int)layer->enabled) &&
(layer->instrument
? cbox_execute_on(fb, NULL, "/instrument_name", "s", error, layer->instrument->module->instance_name) &&
cbox_execute_on(fb, NULL, "/instrument_uuid", "o", error, layer->instrument)
: (layer->external_output_set
? cbox_uuid_report_as(&layer->external_output, "/external_output", fb, error)
: TRUE)) &&
cbox_execute_on(fb, NULL, "/consume", "i", error, (int)layer->consume) &&
cbox_execute_on(fb, NULL, "/ignore_scene_transpose", "i", error, (int)layer->ignore_scene_transpose) &&
cbox_execute_on(fb, NULL, "/ignore_program_changes", "i", error, (int)layer->ignore_program_changes) &&
cbox_execute_on(fb, NULL, "/disable_aftertouch", "i", error, (int)layer->disable_aftertouch) &&
cbox_execute_on(fb, NULL, "/transpose", "i", error, (int)layer->transpose) &&
cbox_execute_on(fb, NULL, "/fixed_note", "i", error, (int)layer->fixed_note) &&
cbox_execute_on(fb, NULL, "/low_note", "i", error, (int)layer->low_note) &&
cbox_execute_on(fb, NULL, "/high_note", "i", error, (int)layer->high_note) &&
cbox_execute_on(fb, NULL, "/in_channel", "i", error, layer->in_channel + 1) &&
cbox_execute_on(fb, NULL, "/out_channel", "i", error, layer->out_channel + 1) &&
CBOX_OBJECT_DEFAULT_STATUS(layer, fb, error)))
return FALSE;
return TRUE;
}
else if (!strcmp(cmd->command, "/enable") && !strcmp(cmd->arg_types, "i"))
{
layer->enabled = 0 != CBOX_ARG_I(cmd, 0);
return TRUE;
}
else if (!strcmp(cmd->command, "/consume") && !strcmp(cmd->arg_types, "i"))
{
layer->consume = 0 != CBOX_ARG_I(cmd, 0);
return TRUE;
}
else if (!strcmp(cmd->command, "/ignore_scene_transpose") && !strcmp(cmd->arg_types, "i"))
{
layer->ignore_scene_transpose = 0 != CBOX_ARG_I(cmd, 0);
return TRUE;
}
else if (!strcmp(cmd->command, "/ignore_program_changes") && !strcmp(cmd->arg_types, "i"))
{
layer->ignore_program_changes = 0 != CBOX_ARG_I(cmd, 0);
return TRUE;
}
else if (!strcmp(cmd->command, "/disable_aftertouch") && !strcmp(cmd->arg_types, "i"))
{
layer->disable_aftertouch = 0 != CBOX_ARG_I(cmd, 0);
return TRUE;
}
else if (!strcmp(cmd->command, "/transpose") && !strcmp(cmd->arg_types, "i"))
{
layer->transpose = CBOX_ARG_I(cmd, 0);
return TRUE;
}
else if (!strcmp(cmd->command, "/fixed_note") && !strcmp(cmd->arg_types, "i"))
{
layer->fixed_note = CBOX_ARG_I(cmd, 0);
return TRUE;
}
else if (!strcmp(cmd->command, "/low_note") && !strcmp(cmd->arg_types, "i"))
{
layer->low_note = CBOX_ARG_I(cmd, 0);
return TRUE;
}
else if (!strcmp(cmd->command, "/high_note") && !strcmp(cmd->arg_types, "i"))
{
layer->high_note = CBOX_ARG_I(cmd, 0);
return TRUE;
}
else if (!strcmp(cmd->command, "/in_channel") && !strcmp(cmd->arg_types, "i"))
{
layer->in_channel = CBOX_ARG_I(cmd, 0) - 1;
return TRUE;
}
else if (!strcmp(cmd->command, "/out_channel") && !strcmp(cmd->arg_types, "i"))
{
layer->out_channel = CBOX_ARG_I(cmd, 0) - 1;
return TRUE;
}
else if (!strcmp(cmd->command, "/external_output") && !strcmp(cmd->arg_types, "s"))
{
if (*CBOX_ARG_S(cmd, 0))
{
if (cbox_uuid_fromstring(&layer->external_output, CBOX_ARG_S(cmd, 0), error)) {
layer->external_output_set = TRUE;
}
}
else {
layer->external_output_set = FALSE;
}
cbox_scene_update_connected_outputs(layer->scene);
return TRUE;
}
else // otherwise, treat just like an command on normal (non-aux) output
return cbox_object_default_process_cmd(ct, fb, cmd, error);
}
CBOX_CLASS_DEFINITION_ROOT(cbox_layer)
struct cbox_layer *cbox_layer_new(struct cbox_scene *scene)
{
struct cbox_document *doc = CBOX_GET_DOCUMENT(scene);
struct cbox_layer *l = malloc(sizeof(struct cbox_layer));
CBOX_OBJECT_HEADER_INIT(l, cbox_layer, doc);
cbox_command_target_init(&l->cmd_target, cbox_layer_process_cmd, l);
l->enabled = TRUE;
l->instrument = NULL;
l->low_note = 0;
l->high_note = 127;
l->transpose = 0;
l->fixed_note = -1;
l->in_channel = -1;
l->out_channel = -1;
l->disable_aftertouch = FALSE;
l->invert_sustain = FALSE;
l->consume = FALSE;
l->ignore_scene_transpose = FALSE;
l->ignore_program_changes = FALSE;
l->scene = scene;
cbox_uuid_clear(&l->external_output);
l->external_output_set = FALSE;
l->external_merger = NULL;
CBOX_OBJECT_REGISTER(l);
return l;
}
struct cbox_layer *cbox_layer_new_with_instrument(struct cbox_scene *scene, const char *instrument_name, GError **error)
{
struct cbox_layer *layer = cbox_layer_new(scene);
struct cbox_instrument *instr = NULL;
if (!layer) goto error;
instr = cbox_scene_get_instrument_by_name(scene, instrument_name, TRUE, error);
if (!instr)
{
cbox_force_error(error);
g_prefix_error(error, "Cannot get instrument %s for new layer: ", instrument_name);
CBOX_DELETE(layer);
return NULL;
}
cbox_layer_set_instrument(layer, instr);
return layer;
error:
CBOX_DELETE(layer);
if (instr)
cbox_instrument_destroy_if_unused(instr);
return NULL;
}
struct cbox_layer *cbox_layer_new_from_config(struct cbox_scene *scene, const char *layer_name, GError **error)
{
struct cbox_layer *layer = cbox_layer_new(scene);
if (!layer)
goto error;
layer->scene = scene;
if (!cbox_layer_load(layer, layer_name, error))
goto error;
return layer;
error:
CBOX_DELETE(layer);
return NULL;
}

63
template/calfbox/layer.h

@ -1,63 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_LAYER_H
#define CBOX_LAYER_H
#include "dom.h"
#include "midi.h"
#include <glib.h>
#include <stdint.h>
struct cbox_module;
struct cbox_rt;
CBOX_EXTERN_CLASS(cbox_layer)
struct cbox_layer
{
CBOX_OBJECT_HEADER()
struct cbox_scene *scene;
struct cbox_instrument *instrument;
struct cbox_command_target cmd_target;
gboolean enabled;
int8_t in_channel; // -1 for Omni
int8_t out_channel; // -1 for Omni
uint8_t low_note;
uint8_t high_note;
int8_t transpose;
int8_t fixed_note;
gboolean disable_aftertouch;
gboolean invert_sustain;
gboolean consume;
gboolean ignore_scene_transpose;
gboolean ignore_program_changes;
gboolean external_output_set;
struct cbox_uuid external_output;
struct cbox_midi_buffer output_buffer;
struct cbox_midi_merger *external_merger;
};
extern struct cbox_layer *cbox_layer_new(struct cbox_scene *scene);
extern struct cbox_layer *cbox_layer_new_with_instrument(struct cbox_scene *scene, const char *instrument_name, GError **error);
extern struct cbox_layer *cbox_layer_new_from_config(struct cbox_scene *scene, const char *instrument_name, GError **error);
extern gboolean cbox_layer_load(struct cbox_layer *layer, const char *name, GError **error);
extern void cbox_layer_set_instrument(struct cbox_layer *layer, struct cbox_instrument *instrument);
extern void cbox_layer_destroy(struct cbox_layer *layer);
#endif

154
template/calfbox/limiter.c

@ -1,154 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "config-api.h"
#include "dspmath.h"
#include "module.h"
#include "onepole-float.h"
#include <glib.h>
#include <malloc.h>
#include <math.h>
#include <memory.h>
#include <sndfile.h>
#include <stdio.h>
#include <stdlib.h>
#define MODULE_PARAMS limiter_params
struct limiter_params
{
float threshold;
float attack;
float release;
};
struct limiter_module
{
struct cbox_module module;
struct limiter_params *params, *old_params;
double cur_gain;
double atk_coeff, rel_coeff;
};
gboolean limiter_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
struct limiter_module *m = (struct limiter_module *)ct->user_data;
EFFECT_PARAM("/threshold", "f", threshold, double, , -100, 12) else
EFFECT_PARAM("/attack", "f", attack, double, , 1, 1000) else
EFFECT_PARAM("/release", "f", release, double, , 1, 5000) else
if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
return
cbox_execute_on(fb, NULL, "/threshold", "f", error, m->params->threshold) &&
cbox_execute_on(fb, NULL, "/attack", "f", error, m->params->attack) &&
cbox_execute_on(fb, NULL, "/release", "f", error, m->params->release) &&
CBOX_OBJECT_DEFAULT_STATUS(&m->module, fb, error);
}
else
return cbox_object_default_process_cmd(ct, fb, cmd, error);
return TRUE;
}
void limiter_process_event(struct cbox_module *module, const uint8_t *data, uint32_t len)
{
// struct limiter_module *m = module->user_data;
}
void limiter_process_block(struct cbox_module *module, cbox_sample_t **inputs, cbox_sample_t **outputs)
{
struct limiter_module *m = module->user_data;
struct limiter_params *mp = m->params;
if (m->params != m->old_params)
{
m->atk_coeff = 1 - exp(-1000.0 / (mp->attack * m->module.srate));
m->rel_coeff = 1 - exp(-1000.0 / (mp->release * m->module.srate));
// update calculated values
}
const double minval = pow(2.0, -110.0);
for (int i = 0; i < CBOX_BLOCK_SIZE; ++i)
{
float left = inputs[0][i], right = inputs[1][i];
float level = fabs(left);
if (fabs(right) > level)
level = fabs(right);
if (level < minval)
level = minval;
level = log(level);
float gain = 0.0;
if (level > mp->threshold * 0.11552)
gain = mp->threshold * 0.11552 - level;
// instantaneous attack + slow release
if (gain >= m->cur_gain)
m->cur_gain += m->rel_coeff * (gain - m->cur_gain);
else
m->cur_gain += m->atk_coeff * (gain - m->cur_gain);
gain = exp(m->cur_gain);
//if (gain < 1)
// printf("level = %f gain = %f\n", m->cur_level, gain);
outputs[0][i] = left * gain;
outputs[1][i] = right * gain;
}
}
MODULE_SIMPLE_DESTROY_FUNCTION(limiter)
MODULE_CREATE_FUNCTION(limiter)
{
static int inited = 0;
if (!inited)
{
inited = 1;
}
struct limiter_module *m = malloc(sizeof(struct limiter_module));
CALL_MODULE_INIT(m, 2, 2, limiter);
m->module.process_event = limiter_process_event;
m->module.process_block = limiter_process_block;
struct limiter_params *p = malloc(sizeof(struct limiter_params));
p->threshold = -1;
p->attack = 10.f;
p->release = 2000.f;
m->params = p;
m->old_params = NULL;
m->cur_gain = 0.f;
return &m->module;
}
struct cbox_module_keyrange_metadata limiter_keyranges[] = {
};
struct cbox_module_livecontroller_metadata limiter_controllers[] = {
};
DEFINE_MODULE(limiter, 0, 2)

450
template/calfbox/main.c

@ -1,450 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "app.h"
#include "config.h"
#include "config-api.h"
#include "dom.h"
#include "engine.h"
#include "instr.h"
#include "io.h"
#include "layer.h"
#include "menu.h"
#include "menuitem.h"
#include "midi.h"
#include "module.h"
#include "pattern.h"
#include "rt.h"
#include "scene.h"
#include "scripting.h"
#include "song.h"
#include "tarfile.h"
#include "ui.h"
#include "wavebank.h"
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <glib.h>
#include <getopt.h>
#include <math.h>
#if USE_NCURSES
#include <ncurses.h>
#endif
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
static const char *short_options = "i:c:"
#if USE_PYTHON
"r:"
#endif
"e:s:t:b:d:D:N:o:nmhpP";
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"no-ui", 0, 0, 'n'},
{"play", 0, 0, 'p'},
{"no-io", 1, 0, 'N'},
{"instrument", 1, 0, 'i'},
{"scene", 1, 0, 's'},
{"effect", 1, 0, 'e'},
{"config", 1, 0, 'c'},
{"metronome", 0, 0, 'm'},
{"tempo", 1, 0, 't'},
{"beats", 1, 0, 'b'},
{"drum-pattern", 1, 0, 'd'},
{"drum-track", 1, 0, 'D'},
#if USE_PYTHON
{"run-script", 1, 0, 'r'},
#endif
{"output", 1, 0, 'o'},
{0,0,0,0},
};
void print_help(char *progname)
{
printf("Usage: %s [options]\n"
"\n"
"Options:\n"
" -h | --help Show this help text\n"
" -m | --metronome Create a simple metronome pattern\n"
#if USE_NCURSES
" -n | --no-ui Do not start the user interface\n"
#endif
" -p | --play Start pattern playback (default for -d/-D)\n"
" -P | --no-play Don't start pattern playback\n"
" -N | --no-io <rate> Use off-line processing instead of JACK I/O\n"
" -d | --drum-pattern <p> Load drum pattern with a given name\n"
" -D | --drum-track <t> Load drum track with a given name\n"
" -t | --tempo <bpm> Use given tempo (specified in beats/min)\n"
" -b | --beats <bpb> Use given beats/bar\n"
" -e | --effect <e> Override master effect with preset <e>\n"
" -i | --instrument <i> Load instrument <i> as a single-instrument scene\n"
" -s | --scene <s> Load a scene <s>\n"
" -c | --config <c> Use specified config file instead of default\n"
#if USE_PYTHON
" -r | --run-script <s> Run a Python script from a given file\n"
#endif
" -o | --output <o> Write the first stereo output to a WAV file\n"
"\n",
progname);
exit(0);
}
#if USE_PYTHON
// This is a workaround for what I consider a defect in pyconfig.h
#undef _XOPEN_SOURCE
#undef _POSIX_C_SOURCE
#include <Python.h>
static gboolean set_error_from_python(GError **error)
{
PyObject *ptype = NULL, *pvalue = NULL, *ptraceback = NULL;
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
PyObject *ptypestr = PyObject_Str(ptype);
PyObject *pvaluestr = PyObject_Str(pvalue);
PyObject *ptypestr_unicode = PyUnicode_AsUTF8String(ptypestr);
PyObject *pvaluestr_unicode = PyUnicode_AsUTF8String(pvaluestr);
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "%s: %s", PyBytes_AsString(ptypestr_unicode), PyBytes_AsString(pvaluestr_unicode));
Py_DECREF(pvaluestr_unicode);
Py_DECREF(ptypestr_unicode);
//g_error("%s:%s", PyString_AsString(ptypestr), PyString_AsString(pvaluestr));
Py_DECREF(ptypestr);
Py_DECREF(pvaluestr);
Py_DECREF(ptype);
Py_XDECREF(pvalue);
Py_XDECREF(ptraceback);
return FALSE;
}
void cbox_script_run(const char *name)
{
FILE *fp = fopen(name, "rb");
if (!fp)
{
g_warning("Cannot open script file '%s': %s", name, strerror(errno));
return;
}
// (_cbox module is discontinued, use _cbox2)
// PyImport_AppendInittab("_cbox", &PyInit_cbox);
Py_Initialize();
#if 0
if (PyType_Ready(&CboxCallbackType) < 0)
{
g_warning("Cannot install the C callback type");
return;
}
Py_INCREF(&CboxCallbackType);
engine_initialised = TRUE;
#endif
if (PyRun_SimpleFile(fp, name) == 1)
{
GError *error = NULL;
set_error_from_python(&error);
cbox_print_error(error);
}
Py_Finalize();
}
#endif
#if USE_NCURSES
static int (*old_menu_on_idle)(struct cbox_ui_page *page);
static int on_idle_with_ui_poll(struct cbox_ui_page *page)
{
cbox_app_on_idle(NULL, NULL);
if (old_menu_on_idle)
return old_menu_on_idle(page);
else
return 0;
}
void run_ui()
{
struct cbox_menu_state *st = NULL;
struct cbox_menu_page *page = cbox_menu_page_new();
cbox_ui_start();
old_menu_on_idle = page->page.on_idle;
page->page.on_idle = on_idle_with_ui_poll;
struct cbox_menu *main_menu = create_main_menu();
st = cbox_menu_state_new(page, main_menu, stdscr, NULL);
page->state = st;
cbox_ui_run(&page->page);
cbox_ui_stop();
cbox_menu_state_destroy(st);
cbox_menu_page_destroy(page);
cbox_menu_destroy(main_menu);
}
#endif
void run_no_ui()
{
printf("Ready. Press ENTER to exit.\n");
fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NONBLOCK);
do {
int ch = getchar();
if (ch == 10 || (ch == -1 && errno != EWOULDBLOCK))
break;
usleep(100000);
cbox_app_on_idle(NULL, NULL);
} while(1);
fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) &~ O_NONBLOCK);
}
int main(int argc, char *argv[])
{
struct cbox_open_params params;
struct cbox_layer *layer;
const char *config_name = NULL;
const char *instrument_name = NULL;
const char *scene_name = NULL;
const char *effect_preset_name = NULL;
const char *drum_pattern_name = NULL;
const char *drum_track_name = NULL;
#if USE_PYTHON
const char *script_name = NULL;
#endif
const char *output_name = NULL;
char *instr_section = NULL;
struct cbox_scene *scene = NULL;
int metronome = 0;
int bpb = 0;
float tempo = 0;
GError *error = NULL;
#if USE_NCURSES
gboolean no_ui = FALSE;
#endif
gboolean no_io = FALSE;
int play_immediately = 0;
int no_io_srate = 0;
cbox_dom_init();
while(1)
{
int option_index;
int c = getopt_long(argc, argv, short_options, long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 'c':
config_name = optarg;
break;
case 'i':
instrument_name = optarg;
break;
case 'o':
output_name = optarg;
break;
case 's':
scene_name = optarg;
break;
case 'e':
effect_preset_name = optarg;
break;
case 'd':
drum_pattern_name = optarg;
break;
case 'D':
drum_track_name = optarg;
break;
#if USE_PYTHON
case 'r':
script_name = optarg;
break;
#endif
case 'm':
metronome = 1;
break;
case 'n':
#if USE_NCURSES
no_ui = TRUE;
#endif
break;
case 'N':
no_io = TRUE;
no_io_srate = atoi(optarg);
break;
case 'p':
play_immediately = 1;
break;
case 'P':
play_immediately = -1;
break;
case 'b':
bpb = atoi(optarg);
break;
case 't':
tempo = atof(optarg);
break;
case 'h':
case '?':
print_help(argv[0]);
return 0;
}
}
app.tarpool = cbox_tarpool_new();
app.document = cbox_document_new();
app.rt = cbox_rt_new(app.document);
app.engine = cbox_engine_new(app.document, app.rt);
app.rt->engine = app.engine;
cbox_config_init(config_name);
if (tempo < 1)
tempo = cbox_config_get_float("master", "tempo", 120);
if (bpb < 1)
bpb = cbox_config_get_int("master", "beats_per_bar", 4);
if (no_io)
{
cbox_rt_set_offline(app.rt, no_io_srate, 1024);
}
else
{
GError *error = NULL;
if (!cbox_io_init(&app.io, &params, NULL, &error))
{
fprintf(stderr, "Cannot initialise sound I/O: %s\n", (error && error->message) ? error->message : "Unknown error");
return 1;
}
cbox_rt_set_io(app.rt, &app.io);
}
cbox_wavebank_init();
if (!scene_name && !instrument_name)
{
scene_name = cbox_config_get_string("init", "scene");
instrument_name = cbox_config_get_string("init", "instrument");
if (!scene_name && !instrument_name)
{
if (cbox_config_has_section("scene:default"))
scene_name = "default";
else
if (cbox_config_has_section("instrument:default"))
instrument_name = "default";
}
}
scene = cbox_scene_new(app.document, app.engine);
if (!scene)
goto fail;
if (scene_name)
{
app.current_scene_name = g_strdup_printf("scene:%s", scene_name);
if (!cbox_scene_load(scene, scene_name, &error))
goto fail;
}
else
if (instrument_name)
{
app.current_scene_name = g_strdup_printf("instrument:%s", instrument_name);
layer = cbox_layer_new_with_instrument(scene, instrument_name, &error);
if (!layer)
goto fail;
if (!cbox_scene_add_layer(scene, layer, &error))
goto fail;
}
if (!effect_preset_name)
effect_preset_name = cbox_config_get_string("master", "effect");
if (effect_preset_name && *effect_preset_name)
{
app.engine->effect = cbox_module_new_from_fx_preset(effect_preset_name, app.document, app.rt, app.engine, &error);
if (!app.engine->effect)
goto fail;
}
cbox_master_set_tempo(app.engine->master, tempo);
cbox_master_set_timesig(app.engine->master, bpb, 4);
if (output_name && scene)
{
GError *error = NULL;
if (!cbox_recording_source_attach(&scene->rec_stereo_outputs[0], cbox_recorder_new_stream(app.engine, app.rt, output_name), &error))
cbox_print_error(error);
}
cbox_rt_start(app.rt, NULL);
if (drum_pattern_name)
cbox_song_use_looped_pattern(app.engine->master->song, cbox_midi_pattern_load(app.engine->master->song, drum_pattern_name, 1, app.engine->master->ppqn_factor));
else if (drum_track_name)
cbox_song_use_looped_pattern(app.engine->master->song, cbox_midi_pattern_load_track(app.engine->master->song, drum_track_name, 1, app.engine->master->ppqn_factor));
else if (metronome)
cbox_song_use_looped_pattern(app.engine->master->song, cbox_midi_pattern_new_metronome(app.engine->master->song, app.engine->master->timesig_num, app.engine->master->ppqn_factor));
gboolean has_song = drum_pattern_name || drum_track_name || metronome;
if (play_immediately == 1 || (play_immediately != -1 && has_song))
cbox_master_play(app.engine->master);
#if USE_PYTHON
if (script_name)
cbox_script_run(script_name);
else
#endif
#if USE_NCURSES
if (!no_ui)
run_ui();
else
run_no_ui();
#else
run_no_ui();
#endif
cbox_rt_stop(app.rt);
if (!no_io)
cbox_io_close(&app.io);
goto ok;
fail:
fprintf(stderr, "Cannot start: %s\n", error ? error->message : "unknown error");
ok:
if (error)
g_error_free(error);
if (app.engine->effect)
{
CBOX_DELETE(app.engine->effect);
app.engine->effect = NULL;
}
CBOX_DELETE(app.engine);
CBOX_DELETE(app.rt);
cbox_tarpool_destroy(app.tarpool);
if (cbox_wavebank_get_maxbytes() > 0)
g_message("Max waveform usage: %f MB", (float)(cbox_wavebank_get_maxbytes() / 1048576.0));
cbox_document_destroy(app.document);
cbox_wavebank_close();
cbox_config_close();
g_free(instr_section);
cbox_dom_close();
return 0;
}

389
template/calfbox/master.c

@ -1,389 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "engine.h"
#include "errors.h"
#include "master.h"
#include "seq.h"
#include "rt.h"
#include "song.h"
#include <string.h>
static gboolean master_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
struct cbox_master *m = ct->user_data;
if (!strcmp(cmd->command, "/status") && !*cmd->arg_types)
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
if (!cbox_execute_on(fb, NULL, "/sample_rate", "i", error, m->srate))
return FALSE;
if (!m->spb)
return TRUE;
return cbox_execute_on(fb, NULL, "/tempo", "f", error, m->tempo) &&
cbox_execute_on(fb, NULL, "/timesig", "ii", error, m->timesig_num, m->timesig_denom) &&
cbox_execute_on(fb, NULL, "/playing", "i", error, (int)m->state) &&
cbox_execute_on(fb, NULL, "/pos", "i", error, m->spb->song_pos_samples) &&
cbox_execute_on(fb, NULL, "/pos_ppqn", "i", error, m->spb->song_pos_ppqn) &&
cbox_execute_on(fb, NULL, "/ppqn_factor", "i", error, (int)m->ppqn_factor);
}
else
if (!strcmp(cmd->command, "/tell") && !*cmd->arg_types)
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
if (!m->spb)
return TRUE;
return cbox_execute_on(fb, NULL, "/playing", "i", error, (int)m->state) &&
cbox_execute_on(fb, NULL, "/pos", "i", error, m->spb->song_pos_samples) &&
cbox_execute_on(fb, NULL, "/pos_ppqn", "i", error, m->spb->song_pos_ppqn);
}
else
if (!strcmp(cmd->command, "/set_tempo") && !strcmp(cmd->arg_types, "f"))
{
cbox_master_set_tempo(m, CBOX_ARG_F(cmd, 0));
return TRUE;
}
else
if (!strcmp(cmd->command, "/set_timesig") && !strcmp(cmd->arg_types, "ii"))
{
cbox_master_set_timesig(m, CBOX_ARG_I(cmd, 0), CBOX_ARG_I(cmd, 1));
return TRUE;
}
else
if (!strcmp(cmd->command, "/set_ppqn_factor") && !strcmp(cmd->arg_types, "i"))
{
m->ppqn_factor = CBOX_ARG_I(cmd, 0);
return TRUE;
}
else
if (!strcmp(cmd->command, "/play") && !strcmp(cmd->arg_types, ""))
{
cbox_master_play(m);
return TRUE;
}
else
if (!strcmp(cmd->command, "/stop") && !strcmp(cmd->arg_types, ""))
{
cbox_master_stop(m);
return TRUE;
}
else
if (!strcmp(cmd->command, "/panic") && !strcmp(cmd->arg_types, ""))
{
cbox_master_panic(m);
return TRUE;
}
else
if (!strcmp(cmd->command, "/seek_samples") && !strcmp(cmd->arg_types, "i"))
{
cbox_master_seek_samples(m, CBOX_ARG_I(cmd, 0));
return TRUE;
}
else
if (!strcmp(cmd->command, "/seek_ppqn") && !strcmp(cmd->arg_types, "i"))
{
cbox_master_seek_ppqn(m, CBOX_ARG_I(cmd, 0));
return TRUE;
}
else
if ((!strcmp(cmd->command, "/samples_to_ppqn") || !strcmp(cmd->command, "/ppqn_to_samples")) &&
!strcmp(cmd->arg_types, "i"))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
if (m->spb)
{
if (cmd->command[1] == 's')
return cbox_execute_on(fb, NULL, "/value", "i", error, cbox_master_samples_to_ppqn(m, CBOX_ARG_I(cmd, 0)));
else
return cbox_execute_on(fb, NULL, "/value", "i", error, cbox_master_ppqn_to_samples(m, CBOX_ARG_I(cmd, 0)));
}
else
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Song playback not initialised.");
return FALSE;
}
}
else
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Unknown combination of target path and argument: '%s', '%s'", cmd->command, cmd->arg_types);
return FALSE;
}
}
static void cbox_master_init(struct cbox_master *master, struct cbox_engine *engine)
{
master->srate = engine->io_env.srate;
master->tempo = 120.0;
master->new_tempo = 120.0;
master->timesig_num = 4;
master->timesig_denom = 4;
master->state = CMTS_STOP;
master->engine = engine;
master->song = NULL;
master->spb = NULL;
master->ppqn_factor = 48;
cbox_command_target_init(&master->cmd_target, master_process_cmd, master);
}
struct cbox_master *cbox_master_new(struct cbox_engine *engine)
{
struct cbox_master *master = malloc(sizeof(struct cbox_master));
cbox_master_init(master, engine);
return master;
}
void cbox_master_set_sample_rate(struct cbox_master *master, int srate)
{
master->srate = srate;
}
void cbox_master_set_tempo(struct cbox_master *master, float tempo)
{
// XXXKF not realtime-safe; won't crash, but may lose tempo
// changes when used multiple times in rapid succession
master->new_tempo = tempo;
}
void cbox_master_set_timesig(struct cbox_master *master, int beats, int unit)
{
if (beats > 0)
master->timesig_num = beats;
if (unit > 0)
master->timesig_denom = unit;
}
#define cbox_master_play_args(ARG)
DEFINE_RT_VOID_FUNC(cbox_master, master, cbox_master_play)
{
struct cbox_rt *rt = master->engine->rt;
if (rt && rt->io && rt->io->impl->controltransportfunc)
{
rt->io->impl->controltransportfunc(rt->io->impl, FALSE, master->spb ? master->spb->song_pos_samples : (uint32_t)-1);
if (!rt->io->impl->getsynccompletedfunc(rt->io->impl))
RT_CALL_AGAIN_LATER();
rt->io->impl->controltransportfunc(rt->io->impl, TRUE, master->spb ? master->spb->song_pos_samples : (uint32_t)-1);
return;
}
// wait for the notes to be released
if (master->state == CMTS_STOPPING)
{
RT_CALL_AGAIN_LATER();
return;
}
master->state = CMTS_ROLLING;
}
#define cbox_master_stop_args(ARG)
DEFINE_RT_VOID_FUNC(cbox_master, master, cbox_master_stop)
{
struct cbox_rt *rt = master->engine->rt;
if (rt && rt->io && rt->io->impl->controltransportfunc)
{
rt->io->impl->controltransportfunc(rt->io->impl, FALSE, -1);
return;
}
if (master->state == CMTS_ROLLING)
master->state = CMTS_STOPPING;
if (master->state != CMTS_STOP)
RT_CALL_AGAIN_LATER();
}
struct seek_command_arg
{
struct cbox_master *master;
gboolean is_ppqn;
uint32_t target_pos;
gboolean was_rolling;
gboolean status_known;
gboolean seek_in_progress;
};
static int seek_transport_execute(void *arg_)
{
struct seek_command_arg *arg = arg_;
struct cbox_rt *rt = arg->master->engine->rt;
if (rt && rt->io && rt->io->impl->controltransportfunc)
{
if (!arg->seek_in_progress)
{
arg->seek_in_progress = TRUE;
uint32_t pos = arg->target_pos;
if (arg->is_ppqn)
arg->target_pos = pos = cbox_master_ppqn_to_samples(arg->master, pos);
rt->io->impl->controltransportfunc(rt->io->impl, arg->master->state == CMTS_ROLLING, pos);
// JACK slow-sync won't be performed if unless transport is rolling
if (!arg->was_rolling)
{
if (arg->master->spb)
cbox_song_playback_seek_samples(arg->master->spb, arg->target_pos);
return 5;
}
}
if (rt->io->impl->getsynccompletedfunc(rt->io->impl))
{
if (arg->master->spb)
cbox_song_playback_seek_samples(arg->master->spb, arg->target_pos);
return 5;
}
return 0;
}
// On first pass, check if transport is rolling from the DSP thread
if (!arg->status_known)
{
arg->status_known = TRUE;
arg->was_rolling = arg->master->state == CMTS_ROLLING;
}
// If transport was rolling, stop, release notes, seek, then restart
if (arg->master->state == CMTS_ROLLING)
arg->master->state = CMTS_STOPPING;
// wait until transport stopped
if (arg->master->state != CMTS_STOP)
return 0;
if (arg->master->spb)
{
if (arg->is_ppqn)
cbox_song_playback_seek_ppqn(arg->master->spb, arg->target_pos, FALSE);
else
cbox_song_playback_seek_samples(arg->master->spb, arg->target_pos);
}
if (arg->was_rolling)
arg->master->state = CMTS_ROLLING;
return 1;
}
void cbox_master_seek_ppqn(struct cbox_master *master, uint32_t pos_ppqn)
{
static struct cbox_rt_cmd_definition cmd = { NULL, seek_transport_execute, NULL };
struct seek_command_arg arg = { master, TRUE, pos_ppqn, FALSE, FALSE, FALSE };
cbox_rt_execute_cmd_sync(master->engine->rt, &cmd, &arg);
}
void cbox_master_seek_samples(struct cbox_master *master, uint32_t pos_samples)
{
static struct cbox_rt_cmd_definition cmd = { NULL, seek_transport_execute, NULL };
struct seek_command_arg arg = { master, FALSE, pos_samples, FALSE, FALSE, FALSE };
cbox_rt_execute_cmd_sync(master->engine->rt, &cmd, &arg);
}
void cbox_master_panic(struct cbox_master *master)
{
cbox_master_stop(master);
struct cbox_midi_buffer buf;
cbox_midi_buffer_init(&buf);
for (int ch = 0; ch < 16; ch++)
{
cbox_midi_buffer_write_inline(&buf, ch, 0xB0 + ch, 120, 0);
cbox_midi_buffer_write_inline(&buf, ch, 0xB0 + ch, 123, 0);
cbox_midi_buffer_write_inline(&buf, ch, 0xB0 + ch, 121, 0);
}
// Send to all outputs
cbox_engine_send_events_to(master->engine, NULL, &buf);
}
uint32_t cbox_master_ppqn_to_samples(struct cbox_master *master, uint32_t time_ppqn)
{
double tempo = master->tempo;
int offset = 0;
if (master->spb)
{
int idx = cbox_song_playback_tmi_from_ppqn(master->spb, time_ppqn);
if (idx != -1)
{
const struct cbox_tempo_map_item *tmi = &master->spb->tempo_map_items[idx];
tempo = tmi->tempo;
time_ppqn -= tmi->time_ppqn;
offset = tmi->time_samples;
}
}
return offset + (int)(master->srate * 60.0 * time_ppqn / (tempo * master->ppqn_factor));
}
uint32_t cbox_master_samples_to_ppqn(struct cbox_master *master, uint32_t time_samples)
{
double tempo = master->tempo;
uint32_t offset = 0;
if (master->spb)
{
int idx = cbox_song_playback_tmi_from_samples(master->spb, time_samples);
if (idx != -1 && idx < master->spb->tempo_map_item_count)
{
const struct cbox_tempo_map_item *tmi = &master->spb->tempo_map_items[idx];
tempo = tmi->tempo;
time_samples -= tmi->time_samples;
offset = tmi->time_ppqn;
}
}
return offset + (uint32_t)(tempo * master->ppqn_factor * time_samples / (master->srate * 60.0));
}
void cbox_master_ppqn_to_bbt(const struct cbox_master *master, struct cbox_bbt *bbt, int time_ppqn, struct cbox_master_track_item *mti)
{
bbt->bar = 0;
bbt->beat = 0;
bbt->tick = 0;
bbt->offset_samples = 0;
uint32_t rel_ppqn = time_ppqn;
int idx = -1;
if (master->spb)
idx = cbox_song_playback_tmi_from_ppqn(master->spb, time_ppqn);
if (idx != -1 && idx < master->spb->tempo_map_item_count)
{
struct cbox_tempo_map_item *tmi = &master->spb->tempo_map_items[idx];
rel_ppqn = time_ppqn - tmi->time_ppqn;
cbox_bbt_add(bbt, rel_ppqn, master->ppqn_factor, tmi->timesig_num, tmi->timesig_denom);
if (mti)
{
mti->tempo = tmi->tempo;
mti->timesig_num = tmi->timesig_num;
mti->timesig_denom = tmi->timesig_denom;
}
}
else
{
cbox_bbt_add(bbt, rel_ppqn, master->ppqn_factor, master->timesig_num, master->timesig_denom);
if (mti)
{
mti->tempo = master->tempo;
mti->timesig_num = master->timesig_num;
mti->timesig_denom = master->timesig_denom;
}
}
}
void cbox_master_destroy(struct cbox_master *master)
{
if (master->spb)
{
cbox_song_playback_destroy(master->spb);
master->spb = NULL;
}
free(master);
}

100
template/calfbox/master.h

@ -1,100 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_MASTER_H
#define CBOX_MASTER_H
#include <stdint.h>
#include "cmd.h"
extern uint64_t PPQN;
struct cbox_song;
struct cbox_rt;
#define GET_RT_FROM_cbox_master(ptr) ((ptr)->engine->rt)
enum cbox_master_transport_state
{
CMTS_STOP,
CMTS_ROLLING,
CMTS_STOPPING,
};
struct cbox_master
{
int srate;
float tempo, new_tempo;
int timesig_num;
int timesig_denom; // must be 4 for now
uint64_t ppqn_factor;
enum cbox_master_transport_state state;
struct cbox_engine *engine;
struct cbox_song *song;
struct cbox_song_playback *spb;
struct cbox_command_target cmd_target;
};
struct cbox_bbt
{
uint32_t bar;
uint32_t beat;
uint32_t tick;
uint32_t offset_samples;
};
struct cbox_master_track_item;
static inline void cbox_bbt_add(struct cbox_bbt *accum, uint32_t ticks, uint32_t ppqn_factor, uint32_t timesig_num, uint32_t timesig_denom)
{
uint32_t ticks_per_beat = ppqn_factor * 4 / timesig_denom;
uint32_t beats_per_bar = timesig_num;
accum->tick += ticks % ticks_per_beat;
if (accum->tick >= ticks_per_beat)
{
accum->tick -= ticks_per_beat;
accum->beat++;
}
uint32_t inc_beats = ticks / ticks_per_beat;
accum->beat += inc_beats % beats_per_bar;
if (accum->beat >= beats_per_bar)
{
accum->beat -= beats_per_bar;
accum->bar++;
}
accum->bar += inc_beats / beats_per_bar;
}
extern struct cbox_master *cbox_master_new(struct cbox_engine *engine);
extern void cbox_master_set_sample_rate(struct cbox_master *master, int srate);
extern void cbox_master_set_tempo(struct cbox_master *master, float tempo);
extern void cbox_master_set_timesig(struct cbox_master *master, int beats, int unit);
extern void cbox_master_ppqn_to_bbt(const struct cbox_master *master, struct cbox_bbt *bbt, int time_ppqn, struct cbox_master_track_item *mti);
//extern uint32_t cbox_master_song_pos_from_bbt(struct cbox_master *master, const struct cbox_bbt *bbt);
extern void cbox_master_play(struct cbox_master *master);
extern void cbox_master_stop(struct cbox_master *master);
extern void cbox_master_panic(struct cbox_master *master);
extern void cbox_master_seek_ppqn(struct cbox_master *master, uint32_t pos_ppqn);
extern void cbox_master_seek_samples(struct cbox_master *master, uint32_t pos_samples);
extern void cbox_master_destroy(struct cbox_master *master);
uint32_t cbox_master_ppqn_to_samples(struct cbox_master *master, uint32_t time_ppqn);
uint32_t cbox_master_samples_to_ppqn(struct cbox_master *master, uint32_t time_samples);
#endif

288
template/calfbox/menu.c

@ -1,288 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "menu.h"
#include "menuitem.h"
#include "ui.h"
#if USE_NCURSES
#include <assert.h>
#include <glib.h>
#include <malloc.h>
#include <ncurses.h>
#include <string.h>
struct cbox_menu
{
GPtrArray *items;
GStringChunk *strings;
};
static int cbox_menu_page_on_key(struct cbox_ui_page *p, int ch);
static int cbox_menu_page_on_idle(struct cbox_ui_page *p);
struct cbox_menu *cbox_menu_new()
{
struct cbox_menu *menu = malloc(sizeof(struct cbox_menu));
menu->items = g_ptr_array_new();
menu->strings = g_string_chunk_new(100);
return menu;
}
struct cbox_menu_item *cbox_menu_add_item(struct cbox_menu *menu, struct cbox_menu_item *item)
{
g_ptr_array_add(menu->items, item);
return item;
}
void cbox_menu_destroy(struct cbox_menu *menu)
{
guint i;
for (i = 0; i < menu->items->len; i++)
cbox_menu_item_destroy(g_ptr_array_index(menu->items, i));
g_ptr_array_free(menu->items, TRUE);
g_string_chunk_free(menu->strings);
free(menu);
}
/*
gchar *cbox_menu_item_value_format(const struct cbox_menu_item *item, void *context)
{
switch(item->type)
{
case menu_item_static:
if (item->extras)
return ((struct cbox_menu_item_extras_static *)(item->extras))->format_value(item, context);
else
return g_strdup_printf("");
case menu_item_submenu:
return g_strdup_printf("...");
case menu_item_command:
return g_strdup_printf("<cmd>");
default:
if (!item->value)
return g_strdup_printf("(null)");
switch(item->type)
{
case menu_item_value_int:
return g_strdup_printf(((struct cbox_menu_item_extras_int *)(item->extras))->fmt, *(int *)item->value);
case menu_item_value_double:
return g_strdup_printf(((struct cbox_menu_item_extras_double *)(item->extras))->fmt, *(double *)item->value);
case menu_item_value_enum:
return g_strdup_printf("<enum>%d", *(int *)item->value);
default:
return g_strdup_printf("");
}
}
assert(0);
return NULL;
}
*/
void cbox_menu_state_size(struct cbox_menu_state *menu_state)
{
struct cbox_menu *menu = menu_state->menu;
guint i;
menu_state->size.label_width = 0;
menu_state->size.value_width = 0;
menu_state->size.height = 0;
menu_state->yspace = getmaxy(menu_state->window) - 2;
for (i = 0; i < menu->items->len; i++)
{
struct cbox_menu_item *item = g_ptr_array_index(menu->items, i);
item->x = 1;
item->y = 1 + menu_state->size.height;
item->item_class->measure(item, menu_state);
}
}
void cbox_menu_state_draw(struct cbox_menu_state *menu_state)
{
struct cbox_menu *menu = menu_state->menu;
guint i;
werase(menu_state->window);
box(menu_state->window, 0, 0);
for (i = 0; i < menu->items->len; i++)
{
struct cbox_menu_item *item = g_ptr_array_index(menu->items, i);
gchar *str = item->item_class->format_value(item, menu_state);
item->item_class->draw(item, menu_state, str, menu_state->cursor == i);
g_free(str);
}
wrefresh(menu_state->window);
}
static void cbox_menu_page_draw(struct cbox_ui_page *p)
{
struct cbox_menu_page *mp = p->user_data;
struct cbox_menu_state *st = mp->state;
cbox_menu_state_size(st);
cbox_menu_state_draw(st);
}
static int cbox_menu_is_item_enabled(struct cbox_menu *menu, unsigned int item)
{
assert(item < menu->items->len);
return ((struct cbox_menu_item *)g_ptr_array_index(menu->items, item))->item_class->on_key != NULL;
}
struct cbox_menu_state *cbox_menu_state_new(struct cbox_menu_page *page, struct cbox_menu *menu, WINDOW *window, void *context)
{
struct cbox_menu_state *st = malloc(sizeof(struct cbox_menu_state));
st->page = page;
st->menu = menu;
st->cursor = 0;
st->yoffset = 0;
st->window = window;
st->context = context;
st->caller = NULL;
st->menu_is_temporary = 0;
while(st->cursor < menu->items->len - 1 && !cbox_menu_is_item_enabled(menu, st->cursor))
st->cursor++;
return st;
}
int cbox_menu_page_on_idle(struct cbox_ui_page *p)
{
struct cbox_menu_page *mp = p->user_data;
struct cbox_menu_state *st = mp->state;
cbox_menu_state_size(st);
cbox_menu_state_draw(st);
return 0;
}
int cbox_menu_page_on_key(struct cbox_ui_page *p, int ch)
{
struct cbox_menu_page *mp = p->user_data;
struct cbox_menu_state *st = mp->state;
struct cbox_menu *menu = st->menu;
struct cbox_menu_item *item = NULL;
int pos = st->cursor;
int res = 0;
if (st->cursor >= 0 && st->cursor < menu->items->len)
item = g_ptr_array_index(menu->items, st->cursor);
if (ch == 27)
return ch;
if (item->item_class->on_key)
{
res = item->item_class->on_key(item, st, ch);
st = mp->state;
if (res < 0)
{
cbox_menu_state_size(st);
cbox_menu_state_draw(st);
return 0;
}
}
if (res > 0)
return res;
switch(ch)
{
case 12:
wclear(st->window);
return 0;
case 27:
return ch;
case KEY_UP:
case KEY_END:
pos = ch == KEY_END ? menu->items->len - 1 : st->cursor - 1;
while(pos >= 0 && !cbox_menu_is_item_enabled(menu, pos))
pos--;
if (pos >= 0)
st->cursor = pos;
if (ch == KEY_END)
{
st->yoffset = st->size.height - st->yspace;
if (st->yoffset < 0)
st->yoffset = 0;
}
else
if (pos >= 0 && (guint)pos < menu->items->len)
{
int npos = st->cursor;
int count = 0;
// show up to 2 disabled items above
while(npos >= 1 && !cbox_menu_is_item_enabled(menu, npos - 1) && count < 2)
{
npos--;
count++;
}
item = g_ptr_array_index(menu->items, npos);
if (item->y < 1 + st->yoffset)
st->yoffset = item->y - 1;
}
cbox_menu_state_draw(st);
return 0;
case KEY_HOME:
case KEY_DOWN:
pos = ch == KEY_HOME ? 0 : st->cursor + 1;
while(pos < (int)menu->items->len && !cbox_menu_is_item_enabled(menu, pos))
pos++;
if (pos < (int)menu->items->len)
st->cursor = pos;
if (ch == KEY_HOME)
st->yoffset = 0;
else if (pos >= 0 && pos < (int)menu->items->len)
{
item = g_ptr_array_index(menu->items, st->cursor);
if (item->y - 1 - st->yoffset >= st->yspace)
st->yoffset = item->y - st->yspace;
}
cbox_menu_state_draw(st);
return 0;
}
return 0;
}
void cbox_menu_state_destroy(struct cbox_menu_state *st)
{
free(st);
}
struct cbox_menu_page *cbox_menu_page_new()
{
struct cbox_menu_page *page = malloc(sizeof(struct cbox_menu_page));
page->state = NULL;
page->page.user_data = page;
page->page.draw = cbox_menu_page_draw;
page->page.on_key = cbox_menu_page_on_key;
page->page.on_idle = cbox_menu_page_on_idle;
return page;
}
void cbox_menu_page_destroy(struct cbox_menu_page *p)
{
free(p);
}
#endif

67
template/calfbox/menu.h

@ -1,67 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_MENU_H
#define CBOX_MENU_H
#include "config.h"
#if USE_NCURSES
#include <ncurses.h>
#include <stdint.h>
#include "menuitem.h"
#include "ui.h"
struct cbox_menu;
struct cbox_menu_item;
struct cbox_menu_page;
struct cbox_menu_state
{
struct cbox_menu_page *page;
struct cbox_menu *menu;
guint cursor;
int yoffset, yspace;
struct cbox_menu_measure size;
WINDOW *window;
void *context;
struct cbox_menu_state *caller;
int menu_is_temporary;
};
extern struct cbox_menu *cbox_menu_new(void);
extern struct cbox_menu_item *cbox_menu_add_item(struct cbox_menu *menu, struct cbox_menu_item *item);
extern void cbox_menu_destroy(struct cbox_menu *menu);
extern struct cbox_menu_state *cbox_menu_state_new(struct cbox_menu_page *page, struct cbox_menu *menu, WINDOW *window, void *context);
extern void cbox_menu_state_destroy(struct cbox_menu_state *st);
struct cbox_menu_page
{
struct cbox_ui_page page;
struct cbox_menu_state *state;
};
extern struct cbox_menu_page *cbox_menu_page_new(void);
extern void cbox_menu_page_destroy(struct cbox_menu_page *st);
#endif
#endif

303
template/calfbox/menuitem.c

@ -1,303 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "menu.h"
#if USE_NCURSES
#include "menuitem.h"
#include <malloc.h>
#include <string.h>
/*******************************************************************/
static void item_measure(struct cbox_menu_item *item, struct cbox_menu_state *state)
{
struct cbox_menu_measure *m = &state->size;
gchar *value = item->item_class->format_value(item, state);
int len = strlen(item->label);
int len2 = value ? strlen(value) : 0;
if (len > m->label_width)
m->label_width = len;
if (len2 > m->value_width)
m->value_width = len2;
m->height++;
g_free(value);
}
static void item_destroy(struct cbox_menu_item *item)
{
if (item->flags & mif_free_label)
g_free(item->label);
if (item->flags & mif_free_context)
free(item->item_context);
if (item->flags & mif_context_is_struct)
{
struct cbox_menu_item_context *ctx = item->item_context;
ctx->destroy_func(ctx);
}
g_free(item);
}
static void item_draw(struct cbox_menu_item *item, struct cbox_menu_state *state, gchar *value, int hilited)
{
int y = item->y - state->yoffset;
if (y < 1 || y > state->yspace)
return;
if (hilited)
wattron(state->window, A_REVERSE);
mvwprintw(state->window, item->y - state->yoffset, item->x, "%-*s %*s", state->size.label_width, item->label, state->size.value_width, value);
wattroff(state->window, A_REVERSE);
}
/*******************************************************************/
static gchar *command_format(const struct cbox_menu_item *item, struct cbox_menu_state *state)
{
return g_strdup("*");
}
static int command_on_key(struct cbox_menu_item *item, struct cbox_menu_state *state, int key)
{
if (key == 10)
{
struct cbox_menu_item_command *citem = (struct cbox_menu_item_command *)item;
return citem->execute(citem, state->context);
}
return 0;
}
struct cbox_menu_item_class menu_item_class_command = {
.measure = item_measure,
.draw = item_draw,
.format_value = command_format,
.on_idle = NULL,
.on_key = command_on_key,
.destroy = item_destroy
};
/*******************************************************************/
void static_draw(struct cbox_menu_item *item, struct cbox_menu_state *state, gchar *value, int hilited)
{
int y = item->y - state->yoffset;
if (y < 1 || y > state->yspace)
return;
if (!value)
{
wattron(state->window, A_BOLD);
mvwprintw(state->window, y, item->x, "%-*s", state->size.label_width + state->size.value_width, item->label);
wattroff(state->window, A_BOLD);
}
else
mvwprintw(state->window, y, item->x, "%-*s %*s", state->size.label_width, item->label, state->size.value_width, value);
}
static gchar *static_format(const struct cbox_menu_item *item, struct cbox_menu_state *state)
{
struct cbox_menu_item_static *sitem = (struct cbox_menu_item_static *)item;
if (!sitem->format_value)
return NULL;
return sitem->format_value(sitem, state->context);
}
struct cbox_menu_item_class menu_item_class_static = {
.measure = item_measure,
.draw = static_draw,
.format_value = static_format,
.on_idle = NULL,
.on_key = NULL,
.destroy = item_destroy
};
/*******************************************************************/
static gchar *intvalue_format(const struct cbox_menu_item *item, struct cbox_menu_state *state)
{
struct cbox_menu_item_int *iitem = (struct cbox_menu_item_int *)item;
return g_strdup_printf("%d", *iitem->value);
}
static int intvalue_on_key(struct cbox_menu_item *item, struct cbox_menu_state *state, int key)
{
struct cbox_menu_item_int *iitem = (struct cbox_menu_item_int *)item;
int *pv;
switch(key)
{
case KEY_LEFT:
pv = iitem->value;
if (*pv > iitem->vmin)
{
(*pv)--;
if (iitem->on_change)
iitem->on_change(iitem, state->context);
return -1;
}
return 0;
case KEY_RIGHT:
pv = iitem->value;
if (*pv < iitem->vmax)
{
(*pv)++;
if (iitem->on_change)
iitem->on_change(iitem, state->context);
return -1;
}
return 0;
}
return 0;
}
struct cbox_menu_item_class menu_item_class_int = {
.measure = item_measure,
.draw = item_draw,
.format_value = intvalue_format,
.on_idle = NULL,
.on_key = intvalue_on_key,
.destroy = item_destroy
};
/*******************************************************************/
static gchar *menu_format(const struct cbox_menu_item *item, struct cbox_menu_state *state)
{
struct cbox_menu_item_menu *mitem = (struct cbox_menu_item_menu *)item;
return g_strdup((mitem->menu || mitem->create_menu) ? "->" : "<-");
}
static int menu_on_key(struct cbox_menu_item *item, struct cbox_menu_state *state, int key)
{
struct cbox_menu_page *page = state->page;
if (key == 10)
{
struct cbox_menu_item_menu *mitem = (struct cbox_menu_item_menu *)item;
if (mitem->create_menu)
{
struct cbox_menu_state *new_state = cbox_menu_state_new(page, mitem->create_menu(mitem, state->context), state->window, state->context);
new_state->caller = state;
new_state->menu_is_temporary = 1;
page->state = new_state;
}
else
if (mitem->menu)
{
struct cbox_menu_state *new_state = cbox_menu_state_new(page, mitem->menu, state->window, state->context);
new_state->caller = state;
page->state = new_state;
}
else
{
struct cbox_menu_state *caller_state = state->caller;
if (state->menu_is_temporary)
cbox_menu_destroy(state->menu);
cbox_menu_state_destroy(state);
page->state = caller_state;
return -1;
}
return 0;
}
return 0;
}
struct cbox_menu_item_class menu_item_class_menu = {
.measure = item_measure,
.draw = item_draw,
.format_value = menu_format,
.on_idle = NULL,
.on_key = menu_on_key,
.destroy = item_destroy
};
/*******************************************************************/
#define TREAT_LABEL(label) ((flags & mif_dup_label) == mif_dup_label ? g_strdup(label) : (char *)(label))
struct cbox_menu_item *cbox_menu_item_new_command(const char *label, cbox_menu_item_execute_func exec, void *item_context, uint32_t flags)
{
struct cbox_menu_item_command *item = calloc(1, sizeof(struct cbox_menu_item_command));
item->item.label = TREAT_LABEL(label);
item->item.flags = flags;
item->item.item_class = &menu_item_class_command;
item->item.item_context = item_context;
item->execute = exec;
return &item->item;
}
struct cbox_menu_item *cbox_menu_item_new_static(const char *label, cbox_menu_item_format_value fmt, void *item_context, uint32_t flags)
{
struct cbox_menu_item_static *item = calloc(1, sizeof(struct cbox_menu_item_static));
item->item.label = TREAT_LABEL(label);
item->item.flags = flags;
item->item.item_class = &menu_item_class_static;
item->item.item_context = item_context;
item->format_value = fmt;
return &item->item;
}
struct cbox_menu_item *cbox_menu_item_new_int(const char *label, int *value, int vmin, int vmax, void *item_context, uint32_t flags)
{
struct cbox_menu_item_int *item = calloc(1, sizeof(struct cbox_menu_item_int));
item->item.label = TREAT_LABEL(label);
item->item.flags = flags;
item->item.item_class = &menu_item_class_int;
item->item.item_context = item_context;
item->value = value;
item->vmin = vmin;
item->vmax = vmax;
item->on_change = NULL;
return &item->item;
}
struct cbox_menu_item *cbox_menu_item_new_menu(const char *label, struct cbox_menu *menu, void *item_context, uint32_t flags)
{
struct cbox_menu_item_menu *item = calloc(1, sizeof(struct cbox_menu_item_menu));
item->item.label = TREAT_LABEL(label);
item->item.flags = flags;
item->item.item_class = &menu_item_class_menu;
item->item.item_context = item_context;
item->menu = menu;
item->create_menu = NULL;
return &item->item;
}
struct cbox_menu_item *cbox_menu_item_new_dynamic_menu(const char *label, create_menu_func func, void *item_context, uint32_t flags)
{
struct cbox_menu_item_menu *item = calloc(1, sizeof(struct cbox_menu_item_menu));
item->item.label = TREAT_LABEL(label);
item->item.flags = flags;
item->item.item_class = &menu_item_class_menu;
item->item.item_context = item_context;
item->menu = NULL;
item->create_menu = func;
return &item->item;
}
void cbox_menu_item_destroy(struct cbox_menu_item *item)
{
item->item_class->destroy(item);
}
#endif

133
template/calfbox/menuitem.h

@ -1,133 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_MENUITEM_H
#define CBOX_MENUITEM_H
#if USE_NCURSES
#include <glib.h>
#include <ncurses.h>
#include <stdint.h>
struct cbox_menu;
struct cbox_menu_item;
struct cbox_menu_item_command;
struct cbox_menu_item_static;
struct cbox_menu_item_menu;
struct cbox_menu_state;
struct cbox_menu_measure
{
int label_width;
int value_width;
int height;
};
struct cbox_menu_item_class
{
void (*measure)(struct cbox_menu_item *item, struct cbox_menu_state *state);
void (*draw)(struct cbox_menu_item *item, struct cbox_menu_state *state, gchar *value, int hilited);
gchar *(*format_value)(const struct cbox_menu_item *item, struct cbox_menu_state *state);
int (*on_key)(struct cbox_menu_item *item, struct cbox_menu_state *state, int key);
int (*on_idle)(struct cbox_menu_item *item, struct cbox_menu_state *state);
void (*destroy)(struct cbox_menu_item *item);
};
typedef int (*cbox_menu_item_execute_func)(struct cbox_menu_item_command *item, void *context);
typedef char *(*cbox_menu_item_format_value)(const struct cbox_menu_item_static *item, void *context);
struct cbox_menu_item
{
gchar *label;
struct cbox_menu_item_class *item_class;
void *item_context;
uint32_t flags;
int x, y;
/* TODO: is_active? */
};
struct cbox_menu_item_command
{
struct cbox_menu_item item;
int (*execute)(struct cbox_menu_item_command *item, void *menu_context);
};
struct cbox_menu_item_int
{
struct cbox_menu_item item;
int *value;
int vmin, vmax;
const char *fmt;
int (*on_change)(struct cbox_menu_item_int *item, void *menu_context);
};
struct cbox_menu_item_double
{
struct cbox_menu_item item;
double *value;
double vmin, vmax;
const char *fmt;
double step_arg;
double (*step)(struct cbox_menu_item_double *item, int where);
int (*on_change)(struct cbox_menu_item_double *item, void *menu_context);
};
struct cbox_menu_item_static
{
struct cbox_menu_item item;
char *(*format_value)(const struct cbox_menu_item_static *item, void *menu_context);
};
typedef struct cbox_menu *(*create_menu_func)(struct cbox_menu_item_menu *item, void *menu_context);
struct cbox_menu_item_context
{
void (*destroy_func)(void *menu_context);
};
struct cbox_menu_item_menu
{
struct cbox_menu_item item;
struct cbox_menu *menu;
create_menu_func create_menu;
};
enum {
mif_free_label = 1, // release the label on destroy
mif_free_context = 2, // release the context on destroy
mif_dup_label = 4 | mif_free_label, // clone the label, release the clone on destroy
mif_context_is_struct = 8, // cast context to cbox_menu_item_context and call destroy_func on destroy (it may or may not free() itself)
};
extern struct cbox_menu_item *cbox_menu_item_new_command(const char *label, cbox_menu_item_execute_func exec, void *item_context, uint32_t flags);
extern struct cbox_menu_item *cbox_menu_item_new_static(const char *label, cbox_menu_item_format_value fmt, void *item_context, uint32_t flags);
extern struct cbox_menu_item *cbox_menu_item_new_int(const char *label, int *value, int vmin, int vmax, void *item_context, uint32_t flags);
extern struct cbox_menu_item *cbox_menu_item_new_menu(const char *label, struct cbox_menu *menu, void *item_context, uint32_t flags);
extern struct cbox_menu_item *cbox_menu_item_new_dynamic_menu(const char *label, create_menu_func func, void *item_context, uint32_t flags);
extern void cbox_menu_item_destroy(struct cbox_menu_item *);
static inline struct cbox_menu_item *cbox_menu_item_new_ok(void)
{
return cbox_menu_item_new_menu("OK", NULL, NULL, 0);
}
#endif
#endif

5
template/calfbox/py/metadata.py → template/calfbox/metadata.py

@ -10,7 +10,10 @@ import base64 # for icons
import os.path
#get_thing
from calfbox._cbox2 import do_cmd
try:
from _cbox2 import do_cmd #local file _cbox2.py
except ModuleNotFoundError:
from ._cbox2 import do_cmd
def get_thing(): pass #overwritten by cbox.py after import

137
template/calfbox/meter.c

@ -1,137 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dspmath.h"
#include "errors.h"
#include "meter.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>
static void clear_meter(struct cbox_meter *m)
{
for (int i = 0; i < 2; i++)
{
m->volume[i] = 0.f;
m->peak[i] = 0.f;
m->last_peak[i] = 0.f;
}
m->smpcounter = 0;
}
gboolean cbox_meter_attach(struct cbox_recorder *handler, struct cbox_recording_source *src, GError **error)
{
struct cbox_meter *m = handler->user_data;
m->channels = src->channels;
clear_meter(m);
return TRUE;
}
void cbox_meter_record_block(struct cbox_recorder *handler, const float **buffers, uint32_t offset, uint32_t numsamples)
{
struct cbox_meter *m = handler->user_data;
for (int c = 0; c < m->channels; c++)
{
float peak = m->peak[c];
float volume = m->volume[c];
for (uint32_t i = 0; i < numsamples; i++)
{
float s = buffers[c][i];
if (fabs(s) > peak)
peak = fabs(s);
volume += (s * s - volume) * 0.01; // XXXKF this is too simplistic, needs sample rate and proper time constant
}
m->peak[c] = peak;
m->volume[c] = sanef(volume);
}
m->smpcounter += numsamples;
if (m->smpcounter > m->srate)
{
for (int c = 0; c < m->channels; c++)
{
m->last_peak[c] = m->peak[c];
m->peak[c] = 0;
}
m->smpcounter = 0;
}
}
gboolean cbox_meter_detach(struct cbox_recorder *handler, GError **error)
{
struct cbox_meter *m = handler->user_data;
m->channels = 0;
clear_meter(m);
return TRUE;
}
void cbox_meter_destroy(struct cbox_recorder *handler)
{
struct cbox_meter *m = handler->user_data;
free(m);
}
static gboolean cbox_meter_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
{
struct cbox_meter *m = ct->user_data;
if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
{
return CBOX_OBJECT_DEFAULT_STATUS(&m->recorder, fb, error);
}
if (!strcmp(cmd->command, "/get_peak") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
float peak[2];
for (int c = 0; c < 2; c++)
{
float v = m->peak[c], w = m->last_peak[c];
if (v < w)
v = w;
peak[c] = v;
}
return cbox_execute_on(fb, NULL, "/peak", "ff", error, peak[0], peak[1]);
}
else
if (!strcmp(cmd->command, "/get_rms") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
return cbox_execute_on(fb, NULL, "/rms", "ff", error, sqrt(m->volume[0]), sqrt(m->volume[1]));
}
else
return cbox_object_default_process_cmd(ct, fb, cmd, error);
}
struct cbox_meter *cbox_meter_new(struct cbox_document *document, int srate)
{
struct cbox_meter *m = malloc(sizeof(struct cbox_meter));
CBOX_OBJECT_HEADER_INIT(&m->recorder, cbox_recorder, document);
m->recorder.user_data = m;
cbox_command_target_init(&m->recorder.cmd_target, cbox_meter_process_cmd, m);
m->recorder.attach = cbox_meter_attach;
m->recorder.detach = cbox_meter_detach;
m->recorder.record_block = cbox_meter_record_block;
m->recorder.destroy = cbox_meter_destroy;
m->srate = srate;
clear_meter(m);
CBOX_OBJECT_REGISTER(&m->recorder);
return m;
}

38
template/calfbox/meter.h

@ -1,38 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_METER_H
#define CBOX_METER_H
#include "recsrc.h"
struct cbox_meter
{
struct cbox_recorder recorder;
float volume[2]; // lowpassed squared
float peak[2];
float last_peak[2];
int srate;
int channels;
int smpcounter;
};
extern struct cbox_meter *cbox_meter_new(struct cbox_document *document, int srate);
#endif

113
template/calfbox/midi.c

@ -1,113 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config-api.h"
#include "midi.h"
#include <stdarg.h>
int cbox_midi_buffer_write_inline(struct cbox_midi_buffer *buffer, uint32_t time, ...)
{
uint8_t buf[4];
va_list va;
va_start(va, time);
buf[0] = va_arg(va, int);
int size = midi_cmd_size(buf[0]);
for (int i = 1; i < size; i++)
buf[i] = va_arg(va, int);
return cbox_midi_buffer_write_event(buffer, time, buf, size);
}
int cbox_midi_buffer_write_event(struct cbox_midi_buffer *buffer, uint32_t time, uint8_t *data, uint32_t size)
{
struct cbox_midi_event *evt;
if (buffer->count >= CBOX_MIDI_MAX_EVENTS)
return 0;
if (size > 4 && size > CBOX_MIDI_MAX_LONG_DATA - buffer->long_data_size)
return 0;
evt = &buffer->events[buffer->count++];
evt->time = time;
evt->size = size;
if (size <= 4)
{
memcpy(evt->data_inline, data, size);
}
else
{
evt->data_ext = buffer->long_data + buffer->long_data_size;
memcpy(evt->data_ext, data, size);
buffer->long_data_size += size;
}
return 1;
}
int cbox_midi_buffer_copy_event(struct cbox_midi_buffer *buffer, const struct cbox_midi_event *event, int new_time)
{
struct cbox_midi_event *evt;
if (buffer->count >= CBOX_MIDI_MAX_EVENTS)
return 0;
if (event->size > 4 && event->size > CBOX_MIDI_MAX_LONG_DATA - buffer->long_data_size)
return 0;
evt = &buffer->events[buffer->count++];
evt->time = new_time;
evt->size = event->size;
if (event->size <= 4)
{
memcpy(evt->data_inline, event->data_inline, event->size);
}
else
{
evt->data_ext = buffer->long_data + buffer->long_data_size;
memcpy(evt->data_ext, event->data_ext, event->size);
buffer->long_data_size += event->size;
}
return 1;
}
int note_from_string(const char *note)
{
static const int semis[] = {9, 11, 0, 2, 4, 5, 7};
int pos;
int nn = tolower(note[0]);
int nv;
if (nn >= '0' && nn <= '9')
return atoi(note);
if (nn < 'a' && nn > 'g')
return -1;
nv = semis[nn - 'a'];
for (pos = 1; note[pos] == 'b' || note[pos] == '#'; pos++)
nv += (note[pos] == 'b') ? -1 : +1;
if ((note[pos] == '-' && note[pos + 1] >= '1' && note[pos + 1] <= '2' && note[pos + 2] == '\0') || (note[pos] >= '0' && note[pos] <= '9' && note[pos + 1] == '\0'))
{
return nv + 12 * (2 + atoi(note + pos));
}
return -1;
}
int cbox_config_get_note(const char *cfg_section, const char *key, int def_value)
{
const char *cv = cbox_config_get_string(cfg_section, key);
if (cv)
return note_from_string(cv);
return def_value;
}

125
template/calfbox/midi.h

@ -1,125 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2013 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_MIDI_H
#define CBOX_MIDI_H
#include <ctype.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
struct cbox_midi_event
{
uint32_t time;
uint32_t size;
union {
uint8_t data_inline[4]; /* up to 4 bytes */
uint8_t *data_ext; /* if larger than 4 bytes */
};
};
#define CBOX_MIDI_MAX_EVENTS 256
#define CBOX_MIDI_MAX_LONG_DATA 256
struct cbox_midi_buffer
{
uint32_t count;
uint32_t long_data_size;
struct cbox_midi_event events[CBOX_MIDI_MAX_EVENTS];
uint8_t long_data[CBOX_MIDI_MAX_LONG_DATA];
};
static inline void cbox_midi_buffer_init(struct cbox_midi_buffer *buffer)
{
buffer->count = 0;
buffer->long_data_size = 0;
}
static inline void cbox_midi_buffer_clear(struct cbox_midi_buffer *buffer)
{
buffer->count = 0;
buffer->long_data_size = 0;
}
static inline void cbox_midi_buffer_copy(struct cbox_midi_buffer *dst, const struct cbox_midi_buffer *src)
{
dst->count = src->count;
dst->long_data_size = src->long_data_size;
memcpy(dst->events, src->events, src->count * sizeof(struct cbox_midi_event));
memcpy(dst->long_data, src->long_data, src->long_data_size);
// for any long events, update data pointers
for (uint32_t i = 0; i < src->count; i++)
{
if (dst->events[i].size > 4)
dst->events[i].data_ext += &dst->long_data[0] - &src->long_data[0];
}
}
static inline uint32_t cbox_midi_buffer_get_count(struct cbox_midi_buffer *buffer)
{
return buffer->count;
}
static inline uint32_t cbox_midi_buffer_get_last_event_time(struct cbox_midi_buffer *buffer)
{
if (!buffer->count)
return 0;
return buffer->events[buffer->count - 1].time;
}
static inline int cbox_midi_buffer_can_store_msg(struct cbox_midi_buffer *buffer, int size)
{
if (buffer->count >= CBOX_MIDI_MAX_EVENTS)
return 0;
if (size < 4)
return 1;
return buffer->long_data_size + size <= CBOX_MIDI_MAX_LONG_DATA;
}
static inline const struct cbox_midi_event *cbox_midi_buffer_get_event(const struct cbox_midi_buffer *buffer, uint32_t pos)
{
if (pos >= buffer->count)
return NULL;
return &buffer->events[pos];
}
static inline const uint8_t *cbox_midi_event_get_data(const struct cbox_midi_event *evt)
{
return evt->size > 4 ? evt->data_ext : evt->data_inline;
}
static inline int midi_cmd_size(uint8_t cmd)
{
static const int sizes[] = { 3, 3, 3, 3, 2, 2, 3, 1 };
if (cmd < 128)
return 0;
return sizes[(cmd >> 4) - 8];
}
extern int cbox_midi_buffer_write_event(struct cbox_midi_buffer *buffer, uint32_t time, uint8_t *data, uint32_t size);
extern int cbox_midi_buffer_write_inline(struct cbox_midi_buffer *buffer, uint32_t time, ...);
extern int cbox_midi_buffer_copy_event(struct cbox_midi_buffer *buffer, const struct cbox_midi_event *event, int new_time);
extern int note_from_string(const char *note);
extern int cbox_config_get_note(const char *cfg_section, const char *key, int def_value);
#endif

254
template/calfbox/mididest.c

@ -1,254 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2013 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "blob.h"
#include "mididest.h"
#include "rt.h"
#include "stm.h"
void cbox_midi_merger_init(struct cbox_midi_merger *dest, struct cbox_midi_buffer *output)
{
dest->inputs = NULL;
dest->output = output;
if (dest->output)
cbox_midi_buffer_clear(dest->output);
}
// void cbox_midi_buffer_merge(struct cbox_midi_buffer *output, struct cbox_midi_buffer **inputs, int count, int *positions)
void cbox_midi_merger_render_to(struct cbox_midi_merger *dest, struct cbox_midi_buffer *output)
{
if (!output)
return;
cbox_midi_buffer_clear(output);
for (struct cbox_midi_source *p = dest->inputs; p; p = p->next)
{
if (p->streaming)
p->bpos = 0;
}
struct cbox_midi_source *first = dest->inputs;
struct cbox_midi_source *first_not = NULL;
while(first)
{
struct cbox_midi_source *earliest_source = NULL;
uint32_t earliest_time = (uint32_t)-1;
for (struct cbox_midi_source *p = first; p != first_not; p = p->next)
{
struct cbox_midi_buffer *data = p->data;
if (p->bpos < data->count)
{
const struct cbox_midi_event *event = cbox_midi_buffer_get_event(data, p->bpos);
if (event->time < earliest_time)
{
earliest_source = p;
earliest_time = event->time;
}
}
else
{
// Narrow down the range from top and bottom
if (p == first)
first = p->next;
if (p->next == first_not)
{
first_not = p;
break;
}
}
}
if (earliest_source)
{
cbox_midi_buffer_copy_event(output, cbox_midi_buffer_get_event(earliest_source->data, earliest_source->bpos), earliest_time);
earliest_source->bpos++;
}
else
break;
}
}
struct cbox_midi_source **cbox_midi_merger_find_source(struct cbox_midi_merger *dest, struct cbox_midi_buffer *buffer)
{
for (struct cbox_midi_source **pp = &dest->inputs; *pp; pp = &((*pp)->next))
if ((*pp)->data == buffer)
return pp;
return NULL;
}
void cbox_midi_merger_connect(struct cbox_midi_merger *dest, struct cbox_midi_buffer *buffer, struct cbox_rt *rt, struct cbox_midi_merger **dest_ptr)
{
if (cbox_midi_merger_find_source(dest, buffer) != NULL)
return;
struct cbox_midi_source *src = calloc(1, sizeof(struct cbox_midi_source));
src->data = buffer;
src->bpos = 0;
src->streaming = TRUE;
src->next = NULL; // will be updated by the swap
src->merger_ptr = dest_ptr;
if (src->merger_ptr)
*src->merger_ptr = dest;
cbox_rt_swap_pointers_into(rt, (void **)&dest->inputs, src, (void **)&src->next);
}
void cbox_midi_merger_disconnect(struct cbox_midi_merger *dest, struct cbox_midi_buffer *buffer, struct cbox_rt *rt)
{
// Make sure there are no old commands that could modify the chain
// between find_source and swap_pointers.
cbox_rt_handle_cmd_queue(rt);
struct cbox_midi_source **pp = cbox_midi_merger_find_source(dest, buffer);
if (!pp)
return;
struct cbox_midi_source *ms = *pp;
void *old_ptr = cbox_rt_swap_pointers(rt, (void **)pp, ms->next);
assert(old_ptr == ms);
if (ms->merger_ptr)
*ms->merger_ptr = NULL;
free(ms);
}
void cbox_midi_merger_push(struct cbox_midi_merger *dest, struct cbox_midi_buffer *buffer, struct cbox_rt *rt)
{
if (!buffer->count)
return;
assert(!cbox_midi_merger_find_source(dest, buffer));
struct cbox_midi_source src;
src.data = buffer;
src.bpos = 0;
src.streaming = FALSE;
src.next = dest->inputs;
src.merger_ptr = NULL;
cbox_rt_swap_pointers_into(rt, (void **)&dest->inputs, &src, (void **)&src.next);
while(src.bpos < buffer->count)
cbox_rt_handle_cmd_queue(rt);
struct cbox_midi_source **pp = cbox_midi_merger_find_source(dest, buffer);
if (!pp)
return;
assert(*pp == &src);
void *old_ptr = cbox_rt_swap_pointers(rt, (void **)pp, src.next);
assert(old_ptr == &src);
}
void cbox_midi_merger_close(struct cbox_midi_merger *dest, struct cbox_rt *rt)
{
struct cbox_midi_source *ms = cbox_rt_swap_pointers(rt, (void **)&dest->inputs, NULL);
while(ms)
{
struct cbox_midi_source *p = ms;
ms = p->next;
if (p->merger_ptr)
*p->merger_ptr = NULL;
free(p);
}
}
////////////////////////////////////////////////////////////////////////////////////////
void cbox_midi_appsink_init(struct cbox_midi_appsink *appsink, struct cbox_rt *rt, struct cbox_time_mapper *tmap)
{
appsink->rt = rt;
appsink->tmap = tmap;
cbox_midi_buffer_init(&appsink->midibufs[0]);
cbox_midi_buffer_init(&appsink->midibufs[1]);
appsink->current_buffer = 0;
}
void cbox_midi_appsink_supply(struct cbox_midi_appsink *appsink, struct cbox_midi_buffer *buffer, uint32_t time_offset)
{
struct cbox_midi_buffer *sinkbuf = &appsink->midibufs[appsink->current_buffer];
for (uint32_t i = 0; i < buffer->count; i++)
{
const struct cbox_midi_event *event = cbox_midi_buffer_get_event(buffer, i);
if (event)
{
if (!cbox_midi_buffer_can_store_msg(sinkbuf, event->size))
break;
uint32_t abs_time_samples = time_offset + event->time;
uint32_t etime = abs_time_samples;
if (appsink->tmap)
etime = appsink->tmap->map_time(appsink->tmap, etime);
cbox_midi_buffer_copy_event(sinkbuf, event, etime);
}
}
}
#define cbox_midi_appsink_get_input_midi_data__args(ARG)
DEFINE_RT_FUNC(const struct cbox_midi_buffer *, cbox_midi_appsink, appsink, cbox_midi_appsink_get_input_midi_data_)
{
const struct cbox_midi_buffer *ret = NULL;
if (appsink->midibufs[appsink->current_buffer].count)
{
// return the current buffer, switch to the new, empty one
ret = &appsink->midibufs[appsink->current_buffer];
appsink->current_buffer = 1 - appsink->current_buffer;
cbox_midi_buffer_clear(&appsink->midibufs[appsink->current_buffer]);
}
return ret;
}
const struct cbox_midi_buffer *cbox_midi_appsink_get_input_midi_data(struct cbox_midi_appsink *appsink)
{
// This checks the counter from the 'wrong' thread, but that's OK, it's
// just to avoid doing any RT work when input buffer is completely empty.
// Any further access/manipulation is done via RT cmd.
if (!appsink->midibufs[appsink->current_buffer].count)
return NULL;
return cbox_midi_appsink_get_input_midi_data_(appsink);
}
gboolean cbox_midi_appsink_send_to(struct cbox_midi_appsink *appsink, struct cbox_command_target *fb, GError **error)
{
const struct cbox_midi_buffer *midi_in = cbox_midi_appsink_get_input_midi_data(appsink);
// If no feedback, the input events are lost - probably better than if
// they filled up the input buffer needlessly.
if (fb && midi_in)
{
for (uint32_t i = 0; i < midi_in->count; i++)
{
const struct cbox_midi_event *event = cbox_midi_buffer_get_event(midi_in, i);
const uint8_t *data = cbox_midi_event_get_data(event);
uint32_t time = event->time & 0x7FFFFFFF;
uint32_t time_type = event->time >> 31;
if (time_type == 0 && !cbox_execute_on(fb, NULL, "/io/midi/event_time_samples", "i", error, time))
return FALSE;
if (time_type == 1 && !cbox_execute_on(fb, NULL, "/io/midi/event_time_ppqn", "i", error, time))
return FALSE;
// XXXKF doesn't handle SysEx properly yet, only 3-byte values
if (event->size <= 3)
{
if (!cbox_execute_on(fb, NULL, "/io/midi/simple_event", "iii" + (3 - event->size), error, data[0], data[1], data[2]))
return FALSE;
}
else
{
struct cbox_blob blob;
blob.data = (uint8_t *)data;
blob.size = event->size;
if (!cbox_execute_on(fb, NULL, "/io/midi/long_event", "b", error, &blob))
return FALSE;
}
}
}
return TRUE;
}

76
template/calfbox/mididest.h

@ -1,76 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2013 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_MIDIDEST_H
#define CBOX_MIDIDEST_H
#include "midi.h"
#include <glib.h>
struct cbox_command_target;
struct cbox_rt;
struct cbox_midi_source
{
struct cbox_midi_source *next;
struct cbox_midi_buffer *data;
uint32_t bpos;
gboolean streaming;
struct cbox_midi_merger **merger_ptr;
};
struct cbox_midi_merger
{
struct cbox_midi_source *inputs;
struct cbox_midi_buffer *output;
};
void cbox_midi_merger_init(struct cbox_midi_merger *dest, struct cbox_midi_buffer *output);
void cbox_midi_merger_render_to(struct cbox_midi_merger *dest, struct cbox_midi_buffer *output);
static inline void cbox_midi_merger_render(struct cbox_midi_merger *dest)
{
if (dest->output)
cbox_midi_merger_render_to(dest, dest->output);
}
struct cbox_midi_source **cbox_midi_merger_find_source(struct cbox_midi_merger *dest, struct cbox_midi_buffer *buffer);
void cbox_midi_merger_connect(struct cbox_midi_merger *dest, struct cbox_midi_buffer *buffer, struct cbox_rt *rt, struct cbox_midi_merger **dest_ptr);
void cbox_midi_merger_disconnect(struct cbox_midi_merger *dest, struct cbox_midi_buffer *buffer, struct cbox_rt *rt);
void cbox_midi_merger_push(struct cbox_midi_merger *dest, struct cbox_midi_buffer *buffer, struct cbox_rt *rt);
void cbox_midi_merger_close(struct cbox_midi_merger *dest, struct cbox_rt *rt);
struct cbox_time_mapper
{
uint32_t (*map_time)(struct cbox_time_mapper *, uint32_t free_running_counter);
};
#define GET_RT_FROM_cbox_midi_appsink(appsink) ((appsink)->rt)
struct cbox_midi_appsink
{
struct cbox_rt *rt;
struct cbox_time_mapper *tmap;
struct cbox_midi_buffer midibufs[2];
int current_buffer;
};
extern void cbox_midi_appsink_init(struct cbox_midi_appsink *appsink, struct cbox_rt *rt, struct cbox_time_mapper *tmap);
extern void cbox_midi_appsink_supply(struct cbox_midi_appsink *appsink, struct cbox_midi_buffer *buffer, uint32_t time_offset);
extern const struct cbox_midi_buffer *cbox_midi_appsink_get_input_midi_data(struct cbox_midi_appsink *appsink);
extern gboolean cbox_midi_appsink_send_to(struct cbox_midi_appsink *appsink, struct cbox_command_target *fb, GError **error);
#endif

270
template/calfbox/module.c

@ -1,270 +0,0 @@
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2011 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "cmd.h"
#include "config-api.h"
#include "engine.h"
#include "module.h"
#include "rt.h"
#include <assert.h>
#include <glib.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern struct cbox_module_manifest sampler_module;
extern struct cbox_module_manifest fluidsynth_module;
extern struct cbox_module_manifest tonewheel_organ_module;
extern struct cbox_module_manifest stream_player_module;
extern struct cbox_module_manifest tone_control_module;
extern struct cbox_module_manifest delay_module;
extern struct cbox_module_manifest reverb_module;
extern struct cbox_module_manifest parametric_eq_module;
extern struct cbox_module_manifest phaser_module;
extern struct cbox_module_manifest chorus_module;
extern struct cbox_module_manifest fxchain_module;
extern struct cbox_module_manifest jack_input_module;
extern struct cbox_module_manifest feedback_reducer_module;
extern struct cbox_module_manifest compressor_module;
extern struct cbox_module_manifest gate_module;
extern struct cbox_module_manifest distortion_module;
extern struct cbox_module_manifest fuzz_module;
extern struct cbox_module_manifest limiter_module;
struct cbox_module_manifest *cbox_module_list[] = {
&tonewheel_organ_module,
#if USE_FLUIDSYNTH
&fluidsynth_module,
#endif
&stream_player_module,
&tone_control_module,
&delay_module,
&reverb_module,
&parametric_eq_module,
&phaser_module,
&chorus_module,
&sampler_module,
&fxchain_module,
#if USE_JACK
&jack_input_module,
#endif
&feedback_reducer_module,
&compressor_module,
&gate_module,
&distortion_module,
&fuzz_module,
&limiter_module,
NULL
};
CBOX_CLASS_DEFINITION_ROOT(cbox_module)
void cbox_module_manifest_dump(struct cbox_module_manifest *manifest)
{
static const char *ctl_classes[] = { "Switch CC#", "Continuous CC#", "Cont. Param", "Discrete Param", "Enum" };
int i = 0;
printf("Module: %s\n", manifest->name);
printf("Audio I/O: min %d inputs, min %d outputs\n", manifest->min_inputs, manifest->min_outputs);
printf("Live controllers:\n");
printf("Ch# Type Number Name \n");
printf("---- --------------- ------ ------------------------------\n");
for (i = 0; i < manifest->num_live_controllers; i++)
{
struct cbox_module_livecontroller_metadata *lc = &manifest->live_controllers[i];
if (lc->channel == 255)
printf("ALL ");
else
if (!lc->channel)
printf("ANY ");
else
printf("%-4d ", lc->channel);
printf("%15s %-6d %-30s\n", ctl_classes[lc->controller_class], lc->controller, lc->name);
}
}
struct cbox_module_manifest *cbox_module_manifest_get_by_name(const char *name)
{
struct cbox_module_manifest **mptr;
for (mptr = cbox_module_list; *mptr; mptr++)
{
if (!strcmp((*mptr)->name, name))
return *mptr;
}
return NULL;
}
struct cbox_module *cbox_module_manifest_create_module(struct cbox_module_manifest *manifest, const char *cfg_section, struct cbox_document *doc, struct cbox_rt *rt, struct cbox_engine *engine, const char *instance_name, GError **error)
{
g_clear_error(error);
struct cbox_module *module = manifest->create(manifest->user_data, cfg_section, doc, rt, engine, error);
if (!module)
return NULL;
module->instance_name = g_strdup(instance_name);
module->input_samples = malloc(sizeof(float) * CBOX_BLOCK_SIZE * module->inputs);
module->output_samples = malloc(sizeof(float) * CBOX_BLOCK_SIZE * module->outputs);
module->engine_name = manifest->name;
cbox_midi_buffer_init(&module->midi_input);
return module;
}
void cbox_module_init(struct cbox_module *module, struct cbox_document *doc, struct cbox_rt *rt, struct cbox_engine *engine, void *user_data, int inputs, int outputs, cbox_process_cmd cmd_handler, void (*destroy)(struct cbox_module *module))
{
CBOX_OBJECT_HEADER_INIT(module, cbox_module, doc);
module->user_data = user_data;
module->rt = rt;
module->engine = engine;
module->instance_name = NULL;
module->input_samples = NULL;
module->output_samples = NULL;
module->inputs = inputs;
module->outputs = outputs;
module->aux_offset = outputs;
module->bypass = 0;
module->srate = engine->io_env.srate;
module->srate_inv = 1.0 / module->srate;
cbox_command_target_init(&module->cmd_target, cmd_handler, module);
module->process_event = NULL;
module->process_block = NULL;
module->destroy = destroy;
CBOX_OBJECT_REGISTER(module);
}
struct cbox_module *cbox_module_new_from_fx_preset(const char *name, struct cbox_document *doc, struct cbox_rt *rt, struct cbox_engine *engine, GError **error)
{
gchar *section = g_strdup_printf("fxpreset:%s", name);
const char *engine_name;
struct cbox_module_manifest *mptr;
struct cbox_module *effect;
if (!cbox_config_has_section(section))
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "No FX preset called '%s'", name);
goto fxpreset_error;
}
engine_name = cbox_config_get_string(section, "engine");
if (!engine_name)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "FX engine not specified for preset '%s'", name);
goto fxpreset_error;
}
mptr = cbox_module_manifest_get_by_name(engine_name);
if (!mptr)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "FX preset '%s' refers to non-existing engine '%s'", name, engine_name);
goto fxpreset_error;
}
effect = cbox_module_manifest_create_module(mptr, section, doc, rt, engine, name, error);
if (!effect)
{
cbox_force_error(error);
g_prefix_error(error, "Could not instantiate FX preset '%s': ", name);
goto fxpreset_error;
}
g_free(section);
return effect;
fxpreset_error:
g_free(section);
return NULL;
}
gboolean cbox_module_slot_process_cmd(struct cbox_module **psm,
struct cbox_command_target *fb, struct cbox_osc_command *cmd, const char *subcmd,
struct cbox_document *doc, struct cbox_rt *rt, struct cbox_engine *engine, GError **error)
{
struct cbox_module *sm = *psm;
if (!strcmp(subcmd, "/status") && !strcmp(cmd->arg_types, ""))
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
if (!(cbox_execute_on(fb, NULL, "/insert_engine", "s", error, sm ? sm->engine_name : "") &&
cbox_execute_on(fb, NULL, "/insert_preset", "s", error, sm ? sm->instance_name : "") &&
cbox_execute_on(fb, NULL, "/bypass", "i", error, sm ? sm->bypass : 0)))
return FALSE;
return TRUE;
}
if (!strcmp(subcmd, "/insert_preset") && !strcmp(cmd->arg_types, "s"))
{
struct cbox_module *effect = cbox_module_new_from_fx_preset(CBOX_ARG_S(cmd, 0), doc, rt, engine, error);
if (!effect)
return FALSE;
cbox_rt_swap_pointers(rt, (void **)psm, effect);
return TRUE;
}
if (!strcmp(subcmd, "/insert_engine") && !strcmp(cmd->arg_types, "s"))
{
struct cbox_module *effect = NULL;
if (*CBOX_ARG_S(cmd, 0))
{
struct cbox_module_manifest *manifest = cbox_module_manifest_get_by_name(CBOX_ARG_S(cmd, 0));
if (!manifest)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "No effect engine '%s'", CBOX_ARG_S(cmd, 0));
return FALSE;
}
effect = cbox_module_manifest_create_module(manifest, NULL, doc, rt, engine, "unnamed", error);
if (!effect)
return FALSE;
}
cbox_rt_swap_pointers(rt, (void **)psm, effect);
return TRUE;
}
if (!sm)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "No engine on module in path '%s'", cmd->command);
return FALSE;
}
if (!strncmp(subcmd, "/engine/", 8))
{
if (!sm->cmd_target.process_cmd)
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "The engine %s has no command target defined", sm->engine_name);
return FALSE;
}
return cbox_execute_sub(&sm->cmd_target, fb, cmd, subcmd + 7, error);
}
if (!strcmp(subcmd, "/set_bypass") && !strcmp(cmd->arg_types, "i"))
{
sm->bypass = CBOX_ARG_I(cmd, 0);
return TRUE;
}
return cbox_object_default_process_cmd(&sm->cmd_target, fb, cmd, error);
}
void cbox_module_swap_pointers_and_free(struct cbox_module *sm, void **pptr, void *value)
{
free(cbox_rt_swap_pointers(sm->rt, pptr, value));
}
void cbox_module_destroyfunc(struct cbox_objhdr *hdr)
{
struct cbox_module *module = CBOX_H2O(hdr);
g_free(module->instance_name);
free(module->input_samples);
free(module->output_samples);
if (module->destroy)
module->destroy(module);
free(module);
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save