PHP Classes

File: rttl.class.php

Recommend this page to a friend!
  Classes of Fluxus   MIDI Class   rttl.class.php   Download  
File: rttl.class.php
Role: Class source
Content type: text/plain
Description: RTTL extension
Class: MIDI Class
Read, write and manipulate MIDI files and data
Author: By
Last change:
Date: 19 years ago
Size: 5,920 bytes
 

Contents

Class file image Download
<?php
require('midi.class.php');

/****************************************************************************
Software: Rttl Class
Version: 0.3
Date: 2005/04/25
Author: Valentin Schmidt
Contact: fluxus@freenet.de
License: Freeware

Extends Midi Class to support the RTTL ringtone format
****************************************************************************/

class Rttl extends Midi {

var
$notes = array('c','c#','d','d#','e','f','f#','g','g#','a','a#','b');
var
$defaultDur = 4;
var
$defaultScale = 5;
var
$defaultBpm = 63;

/****************************************************************************
* *
* Public methods *
* *
****************************************************************************/

//---------------------------------------------------------------
// returns RTTL string (MIDI2RTTL conversion)
// if $title is specified, this will be the RTTL name (max. 10 characters)
// if tracknumber $tn is specified, the corresponding track will be used
//---------------------------------------------------------------
function getRttl($title='',$tn=-1){
   
    if (
$tn<0) $track = $this->_findFirstContentTrack();
    else
$track = $this->getTrack($tn);
   
$commands = array();
   
$last = 0;
   
$dt = 0;
   
$cnt = count($track);
    for (
$i=0;$i<$cnt;$i++){
       
$line = $track[$i];
       
$msg = explode(' ',$line);
       
       
// try to get title from meta event
       
if ($title==''&&$msg[1]=='Meta'&&$msg[2]=='TrkName') {
           
$title=trim($msg[3]);
            if (
$title{0}=='"') $title=substr($title, 1);
            if (
$title{strlen($title)-1}=='"') $title=substr($title, 0, -1);
        }
           
        if (
$msg[1]=='On' && $msg[4]!='v=0'){
           
$time = $msg[0];
           
           
$pause=$time-$last-$dt;
            if (
$pause>0){
                list(
$dot, $quarters) = $this->_checkDotted($pause/$this->timebase);
               
$dur = max(1,round(4 / $quarters));
               
$commands[] = ($dur!=$this->defaultDur?$dur:'').'p'.$dot;
            }
           
           
// find note duration
           
$dt = 0;
            for (
$j=$i+1;$j<$cnt;$j++){
               
$msgNext = explode(' ',$track[$j]);
                if (
$msgNext[1]=='On'||$msgNext[1]=='Off'){
                   
$dt = $msgNext[0] - $msg[0];
                    break;
                }
            }
           
            eval(
"\$".$msg[3].';');
           
$note = $this->notes[$n % 12];
           
$scale = floor($n/12);
           
            if (
$dt>0){
                list(
$dot, $quarters) = $this->_checkDotted($dt/$this->timebase);
               
$dur = max(1,round(4 / $quarters));
               
//<duration> := "1" | "2" | "4" | "8" | "16" | "32"
               
$commands[] = ($dur!=$this->defaultDur?$dur:'').$note.$dot.($scale!=$this->defaultScale?$scale:'');
               
$last = $time;
            }
        }

    }
// for

   
$title = ($title=='')?'mid2rttl':trim(substr($title, 0, 10));
   
$rttl = "$title:d={$this->defaultDur},o={$this->defaultScale},b=".$this->getBpm().":" . implode(',', $commands);
    return
$rttl;
}

//---------------------------------------------------------------
// import RTTL (RTTL2MIDI conversion)
//---------------------------------------------------------------
function importRttl($rttl){
    list(
$name,$controls,$tones) = explode(':', $rttl);
   
$controls = explode(',', $controls);
   
$tones = explode(',', $tones);
   
    foreach (
$controls as $c) eval('$'.$c.';');
       
   
$this->open();
   
$this->type = 0;
   
$this->timebase = 480;// ???
   
$bpm = isset($b)?$b:$this->defaultBpm;
   
$this->tempo = round(60000000/$bpm);
       
   
$track = array();
   
$track[] = '0 Meta TrkName "'.$name.'"';
   
$track[] = '0 Tempo '.$this->tempo;
   
   
$last = 0;
   
$time = 0;
    foreach (
$tones as $tone){
       
preg_match ( '/^[0-9]*/', $tone, $test);
       
$dur = $test[0];
        if (
$dur == '') $dur = isset($d)?$d:$this->defaultDur;
       
       
preg_match ( '/[a-p](\#*)/', $tone, $test);
       
$note = $test[0];
       
       
preg_match ( '/\./', $tone, $test);
       
$dot = @$test[0];
       
       
preg_match ( '/[0-9]*$/', $tone, $test);
       
$scale = @$test[0];
        if (
$scale=='') $scale = isset($o)?$o:$this->defaultScale;
       
       
$quarters = 4 / $dur;
       
$dt = $quarters * $this->timebase;
        if (
$dot) $dt *= 1.5;

        if (
$last) {
           
$track[] = "$time Off ch=1 n=$last v=100";
           
$last = 0;
        }
        if (
$note!='p') {
           
$note = 12 * $scale + array_search ( $note, $this->notes);
           
$track[] = "$time On ch=1 n=$note v=100";
           
$last = $note;
        }

       
$time += $dt;
    }
// foreach
   
   
if ($last) $track[] = "$time Off ch=1 n=$last v=100";
   
$track[] = "$time Meta TrkEnd";
   
   
$this->tracks = array($track);
}


/****************************************************************************
* *
* Private methods *
* *
****************************************************************************/

//---------------------------------------------------------------
// finds first track containing note on events
//---------------------------------------------------------------
function _findFirstContentTrack(){
    if (
$this->type==0) return $this->tracks[0];
    else {
        foreach (
$this->tracks as $track)
            foreach (
$track as $line){
                list(,
$event) = explode(' ',$line);
                if (
$event=='On') return $track;
            }
    }
    return
false;
}

//---------------------------------------------------------------
// handles dotted notes
//---------------------------------------------------------------
function _checkDotted($quarters){
   
$dotted = array(6, 3, 3/2, 3/4, 3/8, 3/16);
    foreach (
$dotted as $test)
       
// to avoid rounding errors check for +/- 10%
       
if (abs($quarters/$test-1)<0.1) //($this->_compare($quarters,$test))
           
return array('.', $quarters*2/3);
    return array(
'', $quarters);
}
   
}
// END OF CLASS
?>