Location: PHPKode > scripts > MIDI Class > rttl.class.php
<?php
require('midi.class.php');

/****************************************************************************
Software: Rttl Class
Version:  0.3
Date:     2005/04/25
Author:   Valentin Schmidt
Contact:  hide@address.com
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
?>
Return current item: MIDI Class