Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
ale
hydrumkit
Commits
e2da2f9b
Commit
e2da2f9b
authored
Mar 08, 2019
by
ale
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Working version
parent
9c420f32
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
188 additions
and
80 deletions
+188
-80
Makefile.am
Makefile.am
+4
-1
engine/adsr.c
engine/adsr.c
+19
-0
engine/config.h
engine/config.h
+0
-26
engine/drumkit.c
engine/drumkit.c
+22
-2
engine/sampler.c
engine/sampler.c
+10
-2
engine/verify-voice.c
engine/verify-voice.c
+101
-0
engine/voice.c
engine/voice.c
+17
-13
engine/voice.h
engine/voice.h
+3
-1
plugin/hydrumkit.ttl
plugin/hydrumkit.ttl
+1
-1
plugin/plugin.c
plugin/plugin.c
+2
-1
plugin/ui.c
plugin/ui.c
+9
-17
plugin/uris.h
plugin/uris.h
+0
-16
No files found.
Makefile.am
View file @
e2da2f9b
...
...
@@ -10,11 +10,14 @@ libengine_la_SOURCES = \
engine/sampler.c engine/sampler.h
libengine_la_LIBADD
=
$(SNDFILE_LIBS)
$(SAMPLERATE_LIBS)
noinst_PROGRAMS
=
load-drumkit
noinst_PROGRAMS
=
load-drumkit
verify-voice
load_drumkit_SOURCES
=
engine/load-drumkit.c
load_drumkit_LDADD
=
libengine.la
verify_voice_SOURCES
=
engine/verify-voice.c
verify_voice_LDADD
=
libengine.la
if
LV2
lv2plugin_DATA
=
plugin/hydrumkit.ttl plugin/manifest.ttl
...
...
engine/adsr.c
View file @
e2da2f9b
...
...
@@ -11,6 +11,24 @@ static float linear_interpolation_fraction(float a, float b, int num, int den) {
}
void
adsr_trigger
(
struct
adsr
*
adsr
,
int
attack
,
int
decay
,
float
sustain
,
int
release
)
{
// Normalize values.
if
(
attack
<
0
)
attack
=
0
;
if
(
decay
<
0
)
decay
=
0
;
if
(
sustain
<
0
)
sustain
=
0
;
if
(
release
<
256
)
release
=
256
;
if
(
attack
>
100000
)
attack
=
100000
;
if
(
decay
>
100000
)
decay
=
100000
;
if
(
sustain
>
1
.
0
)
sustain
=
1
.
0
;
if
(
release
>
100256
)
release
=
100256
;
adsr
->
attack
=
attack
;
adsr
->
decay
=
decay
;
adsr
->
sustain
=
sustain
;
...
...
@@ -52,6 +70,7 @@ float adsr_get_value(struct adsr *adsr, float step) {
case
ADSR_SUSTAIN
:
value
=
adsr
->
sustain
;
//adsr->ticks += step;
break
;
case
ADSR_RELEASE
:
...
...
engine/config.h
deleted
100644 → 0
View file @
9c420f32
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Name of package */
#define PACKAGE "hydrumkit"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "ale@incal.net"
/* Define to the full name of this package. */
#define PACKAGE_NAME "hydrumkit"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "hydrumkit 0.1"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "hydrumkit"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "0.1"
/* Version number of package */
#define VERSION "0.1"
engine/drumkit.c
View file @
e2da2f9b
...
...
@@ -19,7 +19,7 @@ static void instrument_set_defaults(struct instrument *ins) {
ins
->
envelope_attack
=
0
;
ins
->
envelope_decay
=
0
;
ins
->
envelope_sustain
=
1
;
ins
->
envelope_release
=
1000
;
ins
->
envelope_release
=
1000
0
;
ins
->
mute_group
=
-
1
;
ins
->
note
=
0
;
}
...
...
@@ -377,9 +377,19 @@ struct drumkit *drumkit_new(const char *filename, int target_samplerate) {
return
kit
;
}
static
void
fix_bad_xml
(
xmlNodePtr
cur
,
xmlNsPtr
ns
)
{
for
(;
cur
;
cur
=
cur
->
next
)
{
if
(
cur
->
type
==
XML_ELEMENT_NODE
)
{
xmlSetNs
(
cur
,
ns
);
}
fix_bad_xml
(
cur
->
children
,
ns
);
}
}
int
drumkit_load
(
struct
drumkit
*
kit
,
const
char
*
filename
,
int
target_samplerate
)
{
char
*
basedir
=
NULL
;
xmlDocPtr
doc
=
NULL
;
xmlNodePtr
root_element
=
NULL
;
xmlXPathContextPtr
xpathCtx
=
NULL
;
xmlXPathObjectPtr
xpathObj
=
NULL
;
int
n
,
r
=
1
;
...
...
@@ -394,13 +404,23 @@ int drumkit_load(struct drumkit *kit, const char *filename, int target_samplerat
goto
cleanup
;
}
// Check for malformed XML (missing namespace). We can convince
// libxml2 to parse it anyway by setting the proper namespace on all
// elements.
root_element
=
xmlDocGetRootElement
(
doc
);
if
(
!
strcmp
(
root_element
->
name
,
"drumkit_info"
)
&&
root_element
->
ns
==
NULL
)
{
xmlNsPtr
ns
;
fprintf
(
stderr
,
"spotted old-style (bad) XML
\n
"
);
ns
=
xmlNewNs
(
root_element
,
(
xmlChar
*
)
"http://www.hydrogen-music.org/drumkit"
,
(
xmlChar
*
)
""
);
fix_bad_xml
(
root_element
,
ns
);
}
xpathCtx
=
xmlXPathNewContext
(
doc
);
if
(
xpathCtx
==
NULL
)
{
fprintf
(
stderr
,
"Error: unable to create new XPath context
\n
"
);
r
=
0
;
goto
cleanup
;
}
xmlXPathRegisterNs
(
xpathCtx
,
(
xmlChar
*
)
"dk"
,
(
xmlChar
*
)
"http://www.hydrogen-music.org/drumkit"
);
...
...
engine/sampler.c
View file @
e2da2f9b
...
...
@@ -46,6 +46,13 @@ void sampler_noteon(struct sampler *sampler, int note, int velocity) {
return
;
}
// Kill other notes in the same mute_group.
if
(
ins
->
mute_group
>=
0
)
{
for
(
i
=
0
;
i
<
sampler
->
num_voices
;
i
++
)
{
voice_noteoff_if_mute_group
(
&
sampler
->
voices
[
i
],
ins
->
mute_group
);
}
}
// Find a free voice.
struct
voice
*
voice
=
NULL
;
for
(
i
=
0
;
i
<
sampler
->
num_voices
;
i
++
)
{
...
...
@@ -58,7 +65,7 @@ void sampler_noteon(struct sampler *sampler, int note, int velocity) {
printf
(
"all voices are busy
\n
"
);
return
;
}
// Humanize: modify preamble.
voice_noteon
(
voice
,
ins
,
note
,
velocity
,
0
);
}
...
...
@@ -67,7 +74,7 @@ void sampler_noteoff(struct sampler *sampler, int note) {
int
i
;
for
(
i
=
0
;
i
<
sampler
->
num_voices
;
i
++
)
{
voice_noteoff
(
&
sampler
->
voices
[
i
],
note
);
voice_noteoff
_if_note
(
&
sampler
->
voices
[
i
],
note
);
}
}
...
...
@@ -78,6 +85,7 @@ void sampler_output(struct sampler *sampler, float *out_l, float *out_r, int num
for
(
i
=
0
;
i
<
num_frames
;
i
++
)
{
out_l
[
i
]
=
out_r
[
i
]
=
0
;
}
// Accumulate output from all the voices.
for
(
i
=
0
;
i
<
sampler
->
num_voices
;
i
++
)
{
voice_process
(
&
sampler
->
voices
[
i
],
out_l
,
out_r
,
num_frames
);
...
...
engine/verify-voice.c
0 → 100644
View file @
e2da2f9b
#include <stdio.h>
#include <libxml/parser.h>
#include <sndfile.h>
#include "drumkit.h"
#include "voice.h"
#define SR 96000
void
write_sample
(
const
char
*
filename
,
float
*
data_l
,
float
*
data_r
,
int
num_frames
)
{
SF_INFO
info
=
{
0
};
SNDFILE
*
sndfile
;
float
*
buf
;
int
i
;
buf
=
(
float
*
)
malloc
(
2
*
sizeof
(
float
)
*
num_frames
);
for
(
i
=
0
;
i
<
num_frames
;
i
++
)
{
buf
[
i
*
2
]
=
data_l
[
i
];
buf
[
i
*
2
+
1
]
=
data_r
[
i
];
}
info
.
samplerate
=
SR
;
info
.
channels
=
2
;
info
.
format
=
SF_FORMAT_WAV
|
SF_FORMAT_PCM_16
;
sndfile
=
sf_open
(
filename
,
SFM_WRITE
,
&
info
);
sf_writef_float
(
sndfile
,
buf
,
num_frames
);
sf_close
(
sndfile
);
free
(
buf
);
}
int
main
(
int
argc
,
char
**
argv
)
{
int
status
=
0
;
struct
drumkit
kit
=
{
0
};
struct
voice
voice
;
struct
instrument
*
ins
;
struct
layer
*
layer
;
float
*
out_l
,
*
out_r
;
int
total_samples
;
int
lead_samples
=
100
;
int
note_samples
=
100000
;
int
note
=
36
;
int
velocity
=
100
;
int
i
;
if
(
argc
!=
2
)
{
return
2
;
}
/*
* this initialize the library and check potential ABI mismatches
* between the version it was compiled for and the actual shared
* library used.
*/
LIBXML_TEST_VERSION
if
(
!
drumkit_load
(
&
kit
,
argv
[
1
],
SR
))
{
status
=
1
;
goto
cleanup
;
}
ins
=
drumkit_find_instrument_by_note
(
&
kit
,
note
);
if
(
!
ins
)
{
printf
(
"no instrument for note %d
\n
"
,
note
);
status
=
1
;
goto
cleanup
;
}
voice_init
(
&
voice
,
SR
);
total_samples
=
lead_samples
+
note_samples
;
out_l
=
(
float
*
)
malloc
(
sizeof
(
float
)
*
total_samples
);
out_r
=
(
float
*
)
malloc
(
sizeof
(
float
)
*
total_samples
);
for
(
i
=
0
;
i
<
total_samples
;
i
++
)
{
out_l
[
i
]
=
out_r
[
i
]
=
0
;
}
// Some silence first.
voice_process
(
&
voice
,
out_l
,
out_r
,
lead_samples
);
// Then a note (kick).
voice_noteon
(
&
voice
,
ins
,
note
,
velocity
,
0
);
voice_process
(
&
voice
,
out_l
+
lead_samples
,
out_r
+
lead_samples
,
note_samples
);
// Dump the layer used by the voice.
layer
=
instrument_find_layer_by_velocity
(
ins
,
velocity
);
write_sample
(
"layer.wav"
,
layer
->
sample
.
data_l
,
layer
->
sample
.
data_r
,
layer
->
sample
.
info
.
frames
);
// Dump the output.
write_sample
(
"out.wav"
,
out_l
,
out_r
,
total_samples
);
cleanup:
free
(
out_l
);
free
(
out_r
);
drumkit_free
(
&
kit
);
/*
* Cleanup function for the XML library.
*/
xmlCleanupParser
();
return
status
;
}
engine/voice.c
View file @
e2da2f9b
...
...
@@ -5,7 +5,8 @@
#include "voice.h"
static
float
velocity_to_gain
(
int
velocity
)
{
return
(
float
)
velocity
/
127
.
0
;
float
f
=
(
float
)
velocity
/
128
.
0
;
return
f
*
f
;
}
void
voice_init
(
struct
voice
*
voice
,
int
samplerate
)
{
...
...
@@ -27,6 +28,7 @@ int voice_noteon(struct voice *voice, struct instrument *ins, int note, int velo
voice
->
pan_l
=
ins
->
pan_l
;
voice
->
pan_r
=
ins
->
pan_r
;
voice
->
gain
=
ins
->
volume
*
ins
->
gain
*
layer
->
gain
*
velocity_to_gain
(
velocity
);
voice
->
mute_group
=
ins
->
mute_group
;
adsr_trigger
(
&
voice
->
adsr
,
(
int
)
ins
->
envelope_attack
,
(
int
)
ins
->
envelope_decay
,
...
...
@@ -45,11 +47,17 @@ int voice_noteon(struct voice *voice, struct instrument *ins, int note, int velo
return
1
;
}
int
voice_noteoff
(
struct
voice
*
voice
,
int
note
)
{
int
voice_noteoff
_if_note
(
struct
voice
*
voice
,
int
note
)
{
if
((
voice
->
playing
||
voice
->
preamble_countdown
)
&&
voice
->
note
==
note
)
{
adsr_release
(
&
voice
->
adsr
);
voice
->
playing
=
0
;
voice
->
ticks
=
0
;
return
1
;
}
return
0
;
}
int
voice_noteoff_if_mute_group
(
struct
voice
*
voice
,
int
mute_group
)
{
if
((
voice
->
playing
||
voice
->
preamble_countdown
)
&&
voice
->
mute_group
==
mute_group
)
{
adsr_release
(
&
voice
->
adsr
);
return
1
;
}
return
0
;
...
...
@@ -58,26 +66,22 @@ int voice_noteoff(struct voice *voice, int note) {
void
voice_process
(
struct
voice
*
voice
,
float
*
out_l
,
float
*
out_r
,
int
num_frames
)
{
// Accumulate the sample to the output buffer.
while
(
num_frames
--
)
{
if
(
voice
->
in_preamble
)
{
voice
->
preamble_countdown
--
;
if
(
voice
->
preamble_countdown
<=
0
)
{
voice
->
in_preamble
=
0
;
voice
->
playing
=
1
;
voice
->
ticks
=
0
;
}
}
if
(
voice
->
playing
)
{
float
gain
=
voice
->
gain
*
adsr_get_value
(
&
voice
->
adsr
,
1
);
// Stop playing when the envelope is done.
if
(
voice
->
adsr
.
state
==
ADSR_IDLE
)
{
voice
->
playing
=
0
;
continue
;
}
// Stop playing when the sample is done.
if
(
voice
->
ticks
>
voice
->
cur_sample
->
info
.
frames
)
{
// Stop playing when the envelope is done, or the sample is
// done, whichever comes first.
if
((
voice
->
adsr
.
state
==
ADSR_IDLE
)
||
(
voice
->
ticks
>=
voice
->
cur_sample
->
info
.
frames
))
{
voice
->
playing
=
0
;
continue
;
}
...
...
engine/voice.h
View file @
e2da2f9b
...
...
@@ -11,6 +11,7 @@ struct voice {
int
in_preamble
;
int
preamble_countdown
;
int
note
;
int
mute_group
;
int
ticks
;
float
pan_l
,
pan_r
,
gain
;
...
...
@@ -20,7 +21,8 @@ struct voice {
void
voice_init
(
struct
voice
*
,
int
);
int
voice_noteon
(
struct
voice
*
,
struct
instrument
*
,
int
,
int
,
int
);
int
voice_noteoff
(
struct
voice
*
,
int
);
int
voice_noteoff_if_note
(
struct
voice
*
,
int
);
int
voice_noteoff_if_mute_group
(
struct
voice
*
,
int
);
void
voice_process
(
struct
voice
*
,
float
*
,
float
*
,
int
);
static
inline
int
voice_is_playing
(
struct
voice
*
voice
)
{
...
...
plugin/hydrumkit.ttl
View file @
e2da2f9b
...
...
@@ -19,7 +19,7 @@
<http://lv2.incal.net/plugins/hydrumkit>
a
lv2:
Plugin
;
doap:
name
"
Exampler
"
;
doap:
name
"
HyDrumKit
"
;
doap:
license
<http://opensource.org/licenses/isc>
;
lv2:
project
<http://lv2plug.in/ns/lv2>
;
lv2:
requiredFeature
state:
loadDefaultState
,
...
...
plugin/plugin.c
View file @
e2da2f9b
...
...
@@ -184,11 +184,12 @@ static void handle_event(struct sampler_plugin *plugin, LV2_Atom_Event *ev) {
case
LV2_MIDI_MSG_NOTE_ON
:
note
=
(
int
)
msg
[
1
];
velocity
=
(
int
)
msg
[
2
];
sampler_noteoff
(
plugin
->
sampler
,
note
);
sampler_noteon
(
plugin
->
sampler
,
note
,
velocity
);
break
;
case
LV2_MIDI_MSG_NOTE_OFF
:
note
=
(
int
)
msg
[
1
];
sampler_noteoff
(
plugin
->
sampler
,
note
);
//
sampler_noteoff(plugin->sampler, note);
break
;
default:
// Make -Wall happy.
break
;
...
...
plugin/ui.c
View file @
e2da2f9b
/*
LV2 Sampler Example Plugin UI
Copyright 2011-2016 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "uris.h"
...
...
@@ -92,6 +76,7 @@ static LV2UI_Handle instantiate(const LV2UI_Descriptor *descriptor,
struct
plugin_ui
*
ui
=
(
struct
plugin_ui
*
)
calloc
(
1
,
sizeof
(
struct
plugin_ui
));
const
char
*
missing
;
char
*
home
;
LV2_Atom
*
msg
;
LV2_Atom_Forge_Frame
frame
;
GtkFileFilter
*
filter
;
...
...
@@ -128,8 +113,15 @@ static LV2UI_Handle instantiate(const LV2UI_Descriptor *descriptor,
ui
->
file_button
=
gtk_file_chooser_button_new
(
"Load Drumkit"
,
GTK_FILE_CHOOSER_ACTION_OPEN
);
gtk_file_chooser_set_filter
(
GTK_FILE_CHOOSER
(
ui
->
file_button
),
filter
);
gtk_file_chooser_add_shortcut_folder
(
GTK_FILE_CHOOSER
(
ui
->
file_button
),
"/usr/share/hydrogen/data/drumkits"
,
NULL
);
gtk_file_chooser_add_shortcut_folder
(
GTK_FILE_CHOOSER
(
ui
->
file_button
),
"~/.hydrogen/data/drumkits"
,
NULL
);
home
=
getenv
(
"HOME"
);
if
(
home
)
{
char
*
homebuf
=
(
char
*
)
malloc
(
strlen
(
home
)
+
48
);
sprintf
(
homebuf
,
"%s/.hydrogen/data/drumkits"
,
home
);
gtk_file_chooser_add_shortcut_folder
(
GTK_FILE_CHOOSER
(
ui
->
file_button
),
homebuf
,
NULL
);
free
(
homebuf
);
}
gtk_container_set_border_width
(
GTK_CONTAINER
(
ui
->
box
),
4
);
gtk_box_pack_start
(
GTK_BOX
(
ui
->
box
),
ui
->
button_box
,
TRUE
,
TRUE
,
0
);
...
...
plugin/uris.h
View file @
e2da2f9b
/*
LV2 Sampler Example Plugin
Copyright 2011-2016 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __uris_H
#define __uris_H
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment