| 
<?php
require('midi.class.php');
 
 /****************************************************************************
 Software: Rttl Class
 Version:  0.3
 Date:     2005/04/25
 Author:   Valentin Schmidt
 Contact:  [email protected]
 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
 ?>
 |