NAME
MIDI::Trans - Perl extension for quick and easy text->midi conversion.
SYNOPSIS
use
MIDI::Trans;
my
$TranObj
= MIDI::Trans->new( {
'Delimiter'
=>
'\s+'
,
'Note'
=> \
¬e
,
'Volume'
=>
sub
{
return
(127); },
'Duration'
=> \
&somesub
,
'Tempo'
=>
sub
{ ... }
} );
if
(
$TransObj
->trans( {
'File'
=>
'text.txt'
,
'Outfile'
=>
'out.mid'
})) {
(
"success\n"
);
}
else
{
my
$error
=
$TransObj
->error();
die
(
"ERR: $error\n"
);
}
sub
note {
# do something
# return a value between 0 and 127
# or string 'rest' (sans quotes) for
# a rest event
}
sub
duration {
# return some number of quarter notes
}
DESCRIPTION
MIDI::Trans serves as a quick development foundation for text to midi conversion algorithms utilizing MIDI::Simple for output. Using MIDI::Trans, you create callbacks for generating note, volume, duration and tempo values. As your corpus is read, these callbacks are utilized to generate your midi score by MIDI::Trans. MIDI::Trans is modelled after the text conversion aspects of TransMid (http://www.digitalkoma.com/church/projects/transmid/), but designed to be more useful to a wider range of tasks, with less overhead.
If you're in a big hurry, and haven't any need for great control over the process, simply read the 'Plug and Play Usage' and 'CallBacks' sections below to get a jump, and your converter implemented in a just a few minutes, with just a few statements.
A corpus can be defined as either a string, or text file. MIDI::Trans will then split that corpus into elements based on an element delimiter, provided via argument, and determine some attributes of the corpus based on other data, which can be supplied by the developer. The corpus is then processed, element by element through the use of CallBacks you specify. The normal flow of development looks like this:
Define Parameters For Conversion
Define Functions To Generate Note, Duration, Volume, Tempo
from parameters and element
values
.
Specify and process corpus
Create score
Write Output
... this section not yet complete...
EXPORT
None by default.
PLUG AND PLAY USAGE
A MIDI::Trans converter can be written in as few as three statements:
use
MIDI::Trans;
my
$TransObj
= MIDI::Trans->new( {
'Tempo'
=> 140,
'VolumeCallBack'
=>
sub
{
return
(127); },
'NoteCallBack'
=>
sub
{
$cnt
++;
return
$cnt
% 4 ? 88 :
'rest'
; },
'DurationCallBack'
=>
sub
{
return
(16); },
});
$TransObj
->trans({
'File'
=>
'./test.txt'
,
'Outfile'
=>
'test.mid'
});
Obviously, this isn''t very functional and the more compact we make our code, the less functionality there is available to us.
However, if your conversion process doesn''t rely too heavily on controlling the the act of conversion its self, this single method will do everything you need for the process of conversion.
Let's discuss what we've done here:
The new() method is called, which initializes the parameters
for
the converter. The object returned makes its self
available to the callbacks, assuming that you
''
ve created the
variable referencing the object in the same namespace as, or at
least scoped as visible to, the callbacks
''
function definition.
The trans() method acts as a wrapper
around
the step by step
process of converting the document. It doesn
''
t give you the
ability to control some of the information gathering aspects,
nor does it let you handle more than one corpus
with
a single
object, but what it lacks in functionality, it makes up
for
in
ease.
THE TRANS METHOD
trans HASHREF
Has one argument, which is required: either a reference to, or
an anonymous hash. This hash contains information required to
perform the conversion. If any
values
have already been
defined
via the new() method, they
do
not have to be re-
defined
here.
Some names are short-hand
for
the configuration
keys
of new(),
marked
with
an asterisk (*), they are otherwise the same.
trans() spawns a new instance of MIDI::Trans, this object
must be used
for
attribute and configuration methods
for
the operation being performed
with
trans(). That is to
trans_obj() method (see below) to
return
the object operating.
Returns true (1) on success or sets the error() message then
returns
undef
otherwise.
The following
keys
are valid
for
the hash:
'File'
The file path to
read
as the corpus. This
key is required.
'Outfile'
The file to save MIDI output to.
Default value is
'./out.midi'
'Delimiter'
The element delimiter in the corpus.
Default value is
'\s+'
'Tempo'
The tempo to
use
for
the score,
you can specify either
'Tempo'
or
'TempoCallBack'
keys
, but one
must be specified. Will
override
the value of
'TempoCallBack'
.
'TempoCallBack'
Subroutine reference, or anonymous
sub
block that will
return
a tempo
value. See CallBacks section below.
'Volume'
*
Subroutine reference, or anonymous
sub
block that will
return
a valid
volume value.
'Note'
*
Subroutine reference, or anonymous
sub
block that will
return
a valid
note value.
'Duration'
*
Subroutine reference, or anonymous
sub
block that will
return
a valid
duration value.
USAGE:
if
(
$TransObj
->trans( {
'File'
=>
'./test.txt'
,
'Volume'
=>
sub
{ ... },
'Note'
=>
sub
{ ... },
'Duration'
=> \
&some_sub
,
'Tempo'
=> 120 } )
) {
# do something
}
else
{
my
$errmsg
=
$TransObj
->error();
die
(
"$errmsg\n"
);
}
OR:
my
%hash
= (
'File'
=>
'./test.txt'
,
'Volume'
=>
sub
{ ... },
'Note'
=>
sub
{ ... },
'Duration'
=> \
&some_sub
,
'Tempo'
=> 120
);
if
(
$TransObj
->trans(\
%hash
) ) { ... }
Both methods are equivalent.
See the CallBacks section, below,
for
more information
about the CallBacks.
THE TRANS_OBJ METHOD
Given that you need to have an active MIDI::Trans object to use the attribute and information methods, and that trans() creates a new MIDI::Trans object, the trans_obj() method has been provided to you for accessing the usually-needed methods.
trans_obj
Returns the blessed object being utilized by the
trans() method, all methods are available to this
object, but
with
data specific to the current
trans() object.
USAGE:
if
(
$TransObj
->trans( {
'TempoCallBack'
=> \
&tempo
, ... } ) ) {
...
}
sub
tempo {
# a callback called from trans()
my
$cur_obj
=
$TransObj
->trans_obj();
my
$num_sent
=
$cur_obj
->sentences();
...
}
CALLBACKS
If MIDI::Trans is like the skeleton for your conversion application, then the CallBacks you define act as the nervous system. The real logic lies in the combination of information and statistics generated by the corpus, your use of configurable options, and the callbacks you define.
PASSING CALLBACKS AS ARGUMENTS
CallBacks must be passed as either references or anonymous sub blocks. The following forms are all valid: (examples use the callback configuration methods)
$TransObj
->volume_callback(
sub
{ ... } );
--
sub
some_sub {
...
}
$TransObj
->volume_callback(\
&some_sub
);
--
$hashRef
->{
'key'
} =
sub
{ ... };
$TransObj
->volume_callback(
$hashRef
->{
'key'
});
--
my
$sub
=
sub
{
...
};
$TransObj
->volume_callback(
$sub
);
CALLBACK DESCRIPTION
Most CallBacks are passed two arguments:
The Current Element
The Current Position
The Tempo CallBack is passed no arguments.
Each CallBack is expected to return a spefic type and range of data as a return value. Each type is discussed here. Please note that these are just examples and in no way reflect the complexity or interaction available to you.
Volume CallBacks
Volume CallBacks
return
a numeric value to
represent the absolute volume of the
current element in a range of 0-127.
Volume CallBacks are called once
every element,
after
Note CallBacks.
Example:
sub
VolCallBack {
my
$elem
=
shift
;
my
$enum
=
shift
;
# in this callback, volume is
# determined by measuring the
# length of the input, then
# comparing that against a
# constant value, and using that
# comparison as a multiplier against
# our maximum volume level.
my
$lpct
=
length
(
$elem
) / 24;
$lpct
= 1
if
(
$lpct
> 1);
# here, we use the round() method supplied
# by MIDI::Trans
my
$value
=
$TransObj
->round(127 *
$lpct
);
return
(
$value
);
}
Note CallBacks
Note CallBacks
return
a
scalar
value to
represent a note or rest event. The value
of the event is either a number, in the case
of a note, or a string -
'rest'
, in the case
of a rest event. For a note event, you
must specify the absolute value of the
note as an integer in the range of 0-127.
For a rest event, simply
return
a string
with
the value
'rest'
.
Note CallBacks are called once every element.
They are processed
before
Volume and Duration.
Example:
sub
NoteCallBack {
my
$elem
=
shift
;
my
$enum
=
shift
;
my
$return
;
# here, if the corpus contains
# an element with the string 'Eighty-
# Eight', then a note value of 88
# will be returned, rest otherwise.
if
(
$elem
=~ /Eighty-Eight/) {
$return
= 88;
}
else
{
$return
=
'rest'
;
}
return
(
$return
);
}
Duration CallBacks
Duration CallBacks
return
a numeric value
to represent the duration of the current event,
in quarter notes. So the actual duration of
the event, in seconds, is determined by the value of
the qn_len() configuration method and the tempo
returned by your Tempo CallBack.
This method is called once every element,
after
all
others.
Example:
sub
DurCallBack {
my
$elem
=
shift
;
my
$enum
=
shift
;
return
(
length
(
$elem
));
}
Tempo CallBacks
Tempo CallBacks
return
a numeric value
to represent the number of quarter notes
per minute to be used in the score. The
actual
'tempo'
supplied to MIDI::Simple is
the result of the following equation:
round(
$base_ms
/
$tempo
);
Where round() is the included round()
method,
$base_ms
is the value of the
configuration attribute base_milliseconds(),
and
$tempo
is the tempo returned by your
Tempo CallBack.
Tempo is called once per processing
a corpus,
before
all other CallBacks.
Please note, that there are
no
arguments
to this CallBack, as it is executed BEFORE
any elements are processed.
Example:
sub
TempoCallBack {
my
$num_sents
=
$TransObj
->sentences();
my
$num_words
=
$TransObj
->words();
# this CallBack utilizes Attribute
# Retrieval methods to determine
# num of words and sentences in the
# corpus, then uses these values
# to form a percentage of a constant
# maximum tempo.
my
$w_to_s_pct
=
$num_sents
/
$num_words
;
my
$max_tempo
= 200;
my
$tempo
=
$TransObj
->round(
$max_tempo
*
$w_to_s_pct
);
return
(
$tempo
);
}
CORPUS ATTRIBUTES
Several Attributes of your corpus may be gleaned when read. This is controlled by the 'AllAttributes' configuration value, set by either new() or the configuration method all_attributes(). Currently, those attributes are :
# of Sentences *
# of Words *
# of Elements
(Those marked by an asterisk can be
turned off to reduce memory consumption)
The Sentence Delimiter can be defined as a configuration value. The word boundary may not.
ATTRIBUTE RETRIEVAL METHODS
The following methods retrive attributes
about the corpus being processed. They
can only be used inside of your CallBacks,
they are not available elsewhere.
sentences()
Returns the number of sentences
in the corpus.
words()
Returns the number of words in
the corpus.
elements()
Returns the number of total elements
in the corpus.
METHODS
new HASHREF
Creates a new instance of the class. Returns a blessed object
on success,
undef
on error. One argument is allowed, a hash
reference or anonymous hash, which contains configuration
information
for
the object.
The following
keys
are allowable in the hash, and their
values
:
'Raise_Error'
Boolean,
die
() on any error
with
message
0 = false (
default
), 1 = true
'ElementDelimiter'
Default delimiter used to seperate elements from
the corpus. Should be a valid regular expression
as would fit in (?:).
Default value is
'\s+'
'SentenceDelimiter'
Default delimiter
for
end of sentence. Follows
same rules as ElementDelimiter.
Default value is
'\.|\?|\!'
'NoteCallBack'
Default callback
for
obtaining note
values
.
Should be a reference to, or anonymous,
sub
routine. See the section regarding CallBacks
above.
Default value is
undef
'VolumeCallBack'
Default CallBack
for
obtaining volume
values
.
'DurationCallBack'
Default CallBack
for
obtaining duration
values
.
'TempoCallBack'
Default CallBack
for
obtaining tempo
values
.
'Channel'
Default Channel
for
MIDI output.
Default value is
'1'
'qn_len'
Default number of ticks per quarter note.
It is safe to leave this unmodified.
See MIDI::Simple
for
more information.
Default value is
'96'
'AllAttributes'
Boolean, whether or not all attributes of
the corpus should be measured
when
reading
it. Can be used to lessen memory usage.
See the Attributes section below
for
more
information.
0 = False, 1 = True (
default
)
'BaseMilliseconds'
The base number of ms in a minute. This
is used
for
timing and tempo purposes.
It is safe to leave this value unmodified.
Default value is
'60000000'
USAGE:
my
$TransObj
= MIDI::Trans->new( {
'VolumeCallBack'
=> \
&vol
,
'AllAttributes'
=> 0
});
OR:
my
%attrs
= (
'AllAttributes'
=> 1,
'VolumeCallBack'
=> \
&vol
);
my
$TranObj
= MIDI::Trans->new(\
%attrs
);
error()
Returns the
last
set error message, or
undef
if
no
error
message
has
been set.
USAGE:
my
$errmsg
=
$TransObj
->error();
reset_error()
Removes the current error message. Causes error() to
return
undef
. Always returns true (1).
USAGE:
$TransObj
->reset_error();
trans HASHREF
information, see the section entitled Plug and Play Usage
above.
trans_obj
See the section entitled Plug and Play Usage above.
read_corpus HASHREF
Reads, parses, and collects attributes about a
given
corpus
(your input data). The corpus may be specified either as a
file to
read
, or a string to parse. Returns true (1) on sucess,
and sets the error message then returns
undef
on error.
More than one corpus may be
open
at a
given
time
.
A single argument must be specified, which is either a hash
reference or an anonymous hash. The hash contains information
about the corpus. Three
keys
are possible:
'Name'
The
'handy'
name, or name you wish to
specify
for
the corpus. This is useful
when
opening more than one corpus that
is a string type.
If the corpus type is a string, the
name will
default
to
'String'
, otherwise
the name will
default
to the file name.
'File'
When this key is provided, it specifies
that the corpus type is a file. This
key will
override
the
'String'
key,
even
if
the value is
undef
-- resulting
in an error. The value
for
this key
should be the path to the file you
want to parse.
'String'
When this key is provided, it specifies
that the corpus type is a string. This
key is overriden by the
'File'
key. The
string should be passed as the value.
USAGE:
if
(
$TransObj
->read_corpus({
'File'
=>
'./corpus.txt'
}) ) {
...
}
else
{
my
$error
=
$TransObj
->error();
die
(
"$error\n"
);
}
OR
my
%corp_dat
= (
'File'
=>
'./corpus.txt'
,
'Name'
=>
'Corpus1'
);
if
(
$TransObj
->read_corpus(\
%corp_dat
) ) { ... }
NOTE:
The corpus
when
read
, is stored in a list of
available corpuses(ii?). This list is ordered,
in the order they were
read
, numerically. This
is the preferred method
for
identifying a corpus
to other methods, but most also
accept
a Name
value to identify the corpus, which may be
easier to track. The numbering begins at 0.
TODO: Convert all methods to a naming convention.
process HASHREF
Actually performs processing on a
given
corpus. Runs
all of the callbacks, as needed, either on a per-corpus
or per-element basis. Generates the data that will be
used to create a MIDI score later. Only a single corpus
may be specified. Returns true (1)
if
successful and
sets the error message then returns
undef
otherwise.
A single argument must be specified, which is either a hash
reference or an anonymous hash. The hash contains information
identifying the corpus. There are two
keys
possible:
'Name'
The name as
given
the corpus -- see read_corpus
above. Overrides the
'Num'
key. The value should
be the name of the corpus.
'Num'
The number of the corpus. See the NOTE section
of read_corpus, above. Is overriden by the
'Name'
key.
USAGE:
if
(
$TransObj
->process( {
'Name'
=>
'Corpus1'
}) ) {
..
}
else
{
my
$errmsg
=
$TransObj
->error();
die
(
"$errmsg\n"
);
}
OR:
my
%corp_dat
= (
'Num'
=> 1 );
if
(
$TransObj
->process(\
%corp_dat
) ) { ... }
create_score NUM
Creates a score from the data generated by process(),
suitable
for
writing to a file (see write_file() below).
If the corpus hasn
't been parsed, or the processing hasn'
t
occured yet, and error will occur. Returns the
MIDI::Simple object from the score on success and
sets the error message then returns
undef
on failure.
One argument, the identifying number of the corpus
must be specified. (See the NOTE section of read_corpus()
above)
USAGE:
my
$scoreObj
;
if
(
$scoreObj
=
$TransObj
->create_score(0) ) {
...
}
else
{
my
$errmsg
=
$TransObj
->error();
die
(
"$errmsg\n"
);
}
write_file SCORE_OBJECT
Writes a score to a file,
given
the score object
returned from create_score. Returns true (1) on
success and sets the error message then returns
undef
on failure.
USAGE:
if
(
$TransObj
->write_file(
$scoreObj
) ) {
...
}
else
{
my
$errmsg
=
$TransObj
->error();
die
(
"$errmsg\n"
);
}
round DECIMAL
Returns the nearest rounded integer
given
decimal or integer input.
USAGE:
# returns 2
my
$x
=
$TransObj
->round(1.5);
# returns 1
my
$x
=
$TransObj
->round(1.38573927541);
CALLBACK CONFIGURATION METHODS
These methods allow you to configure the CallBacks
you to retrieve a reference to the CallBack in
question. All methods
accept
an argument of either
a subroutine reference or anonymous subroutine block.
All methods
return
their subref.
volume_callback()
Sets / Returns the callback
for
volume
USAGE:
my
$vol_cb
=
$TransObj
->volume_callback(\
&somesub
);
note_callback()
Sets / Returns the callback
for
notes
USAGE:
my
$note_cb
=
$TransObj
->note_callback(\
&somesub
);
duration_callback()
Sets / Returns the callback
for
duration
USAGE:
my
$dur_cb
=
$TransObj
->duration_callback(\
&somesub
);
tempo_callback()
Sets / Returns the callback
for
tempo
USAGE:
my
$tempo_cb
=
$TransObj
->tempo_callback(\
&somesub
);
INFORMATIONAL AND CONFIGURATION METHODS
These methods, in conjunction
with
methods such as
round() (described under the main METHODS heading),
are useful
for
modifying the way MIDI::Trans is
operating, as well as assisting your callbacks in
performing their operation, and retrieving operating
values
. All of these (as well as others) may be
utilized in your CallBacks. Be careful, however of
calling process() within a CallBack, as this may
result in an infinite loop.
current_elem()
Returns the current element from the list of
elements in the corpus. This would typically
be used by your callbacks
for
determining what
to generate.
USAGE:
my
$element
=
$TransObj
->current_elem();
current_pos()
Returns the position of the current element
in the document, starting at zero. That is,
on the 50th element of the corpus, current_pos()
would
return
'49'
.
USAGE:
my
$pos
=
$TransObj
->current_pos();
raise_error()
Sets, or returns the current value of the
'Raise_Error'
attribute.
USAGE:
my
$RE
=
$TransObj
->raise_error(1);
delimiter()
Sets, or returns the current value of the
'Delimiter'
attribute.
USAGE:
my
$Del
=
$TransObj
->delimiter(1);
sentence_delimiter()
Sets, or returns the current value of the
'SentenceDelimiter'
attribute.
USAGE:
my
$SD
=
$TransObj
->sentence_delimiter(
'\!\?'
);
all_attributes()
Sets, or returns the current value of the
'AllAttributes'
attribute.
USAGE:
my
$AA
=
$TransObj
->all_attributes(1);
channel()
Sets, or returns the current value of the
'Channel'
attribute.
USAGE:
my
$Chan
=
$TransObj
->channel(1);
qn_len()
Sets, or returns the current value of the
'qn_len'
attribute.
USAGE:
my
$QL
=
$TransObj
->qn_len(1);
tempo()
Sets, or returns the current value of the
'Tempo'
attribute. This is usually set
by your tempo CallBack, but can also
be set
with
a
default
value using the new()
override
tempo, but this may have little,
if
any, effect on create_events().
USAGE:
my
$Del
=
$TransObj
->delimiter(1);
AUTHOR
C. Church <lt>dolljunkie@digitalkoma.com<gt>
SEE ALSO
perl.