Beefy Boxes and Bandwidth Generously Provided by pair Networks Bob
more useful options
 
PerlMonks

Midi Playlength calculator-II

by zentara (Chancellor)
 | Log in | Create a new user | The Monastery Gates | Super Search | 
 | Seekers of Perl Wisdom | Meditations | PerlMonks Discussion | 
 | Obfuscation | Reviews | Cool Uses For Perl | Perl News | Q&A | Tutorials | 
 | Poetry | Recent Threads | Newest Nodes | Donate | What's New | 

on Dec 11, 2004 at 12:01 UTC ( #414099=snippet: print w/ replies, xml ) Need Help??

Description: A few weeks ago, I made a feeble attempt to calculate midi playlengths in Midi Playlength calculator. It didn't take into account differing midi tempos. So I asked on the perl.midi maillist, and one of the midi gurus Jean Pierre Vidal worked up a solution. Please advise me if you find any midis which this script dosn't give correct times, or if you have code tweaks.
#!/usr/bin/perl
use strict;
use MIDI;

# by Jean-Pierre Vidal on the perl.midi maillist 
# jeanpierre.vidal@free.fr 

my $filename = shift;
die "unknown file $filename\n"   unless -e $filename;
die "usage : perl $0 midifile\n" unless defined $filename;

my $opus = new MIDI::Opus( { 'from_file' => $filename } );

#$opus->dump({'dump_tracks' => 1}); 

# ticks per quarter note 
my $tpqn = $opus->ticks();

my @tracks = $opus->tracks();

# convert tracks to score 
my @score = ();
for my $tr (@tracks) {
    my @events = $tr->events;
    my ( $score_r, $ticks ) = MIDI::Score::events_r_to_score_r( \@even
+ts );
    @score = ( @score, @$score_r );
}

my $score_r = MIDI::Score::sort_score_r( \@score );

#MIDI::Score::dump_score( $score_r ); 

my $duration    = 0;
my $tempo       = .5; #default for midi's with no set_tempo as per spe
+cs 
my $tempo_start = 0;
my $last_time   = 0;
for my $note (@$score_r) {
   if($$note[0] eq 'set_tempo'){print $$note[0],"\n"}

   if ( $$note[0] eq 'set_tempo' ) {

        # if this 'tempo change' is not the last 'note', 
        # we will calculate another $last_time later 
        $last_time = 0;

        # 
        $duration += ( $$note[1] - $tempo_start ) / $tpqn * $tempo;

        # tempo in seconds per quarter note 
        $tempo       = $$note[2] / 1_000_000;
        $tempo_start = $$note[1];
    }
    elsif ( $$note[0] eq 'note' ) {

        # try to get the largest note after last tempo change 
        my $l_t = ( $$note[1] - $tempo_start ) + $$note[2];
        $last_time = $l_t if $l_t > $last_time;
    }
}

$duration += $last_time / $tpqn * $tempo;

my $dmn = int( $duration / 60 );
my $dms = $duration - $dmn * 60;
printf "%d mn %.1f s\n", $dmn, $dms;
__END__ 

Comment on Midi Playlength calculator-II
Download Code
Re: Midi Playlength calculator-II
by saskaqueer (Friar) on Dec 11, 2004 at 23:52 UTC
    @score = ( @score, @$score_r );

    Not that there's anything wrong with this line, it's just more readable to do the following (check out the push manpage for more info).

    push( @score, @$score_r );
[reply]
[d/l]
[select]
Re: Midi Playlength calculator-II
by chanio (Priest) on Jan 07, 2005 at 04:18 UTC
    Good, zentara !

    I was trying a harder aproach by studying the great JAVA SOUND API source code with their midi masterpiece developed by masters in sound. I was helping myself with the JAVA 1.4.2 sound-dev-guide PDF . It was a slow work as I was planning to translate some JAVA classes into perl.

    As you said that you were going to study some C code, I thought that some JAVA code might also help you.

    Besides, the JAVA 1.4.2 sound-dev-guide PDF is a very good introduction to how MIDIS, synthetizers, sequencers and mixers work together. And there are very little descriptions of their JAVA implementation. So, it is a very useful doc.

    Thank you for this script!

    (Update) I am yet building my LINUX Rack to be at least as my Windows one. I am having trouble with my midis. I'll try SDL and your nice script.

    I am also interested in the other aspect of midi code: to command other machines and lights. I found something about this at http://midiox.com/.

[reply]
      That's a nice pdf. It tempts me to dig out my Java books. :-) Perl needs docs like that. I never would have gotten my SDL sound sampler-mixer going, if I didn't stumble across ActiveState's html doc for SDL::Mixer. Maybe when they hand out money for Perl projects, it should go toowards this kind of documentation.

      I'm not really a human, but I play one on earth. flash japh
[reply]

Back to Snippets Section

Login:
Password
remember me
What's my password?
Create A New User

Node Status
node history
Node Type: snippet [id://414099]
help
Community Ads
Chatterbox
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users
Others about the Monastery: (10)
GrandFather
jdporter
atcroft
herveus
thezip
Eyck
ssandv
gnosti
wanradt
im2
As of 2009-11-21 04:06 GMT
Sections
The Monastery Gates
Seekers of Perl Wisdom
Meditations
PerlMonks Discussion
Categorized Q&A
Tutorials
Obfuscated Code
Perl Poetry
Cool Uses for Perl
Perl News
Information
PerlMonks FAQ
Guide to the Monastery
What's New at PerlMonks
Voting/Experience System
Tutorials
Reviews
Library
Perl FAQs
Other Info Sources
Find Nodes
Nodes You Wrote
Super Search
List Nodes By Users
Newest Nodes
Recently Active Threads
Selected Best Nodes
Best Nodes
Worst Nodes
Saints in our Book
Leftovers
The St. Larry Wall Shrine
Offering Plate
Awards
Craft
Snippets Section
Code Catacombs
Quests
Editor Requests
Buy PerlMonks Gear
PerlMonks Merchandise
Planet Perl
Perlsphere
Use Perl
Perl.com
Perl 5 Wiki
Perl Jobs
Perl Mongers
Perl Directory
Perl documentation
CPAN
Random Node
Voting Booth

Future historians will find that the material characteristic of the current era is...

Aluminium
Plastic
Oil
Water
Carbon dioxide
Copper
Iron
Silicon
Salt
Uranium
Hydrogen
Other

Results (726 votes), past polls