2015-01-20 12 views
6

Vorrei generare un tono sinusoidale in php. Ma costruendo il mio wav ho bisogno di dare i valori in byte. Non so come fare:Genera wav in PHP

Ecco il codice che ho:

$freqOfTone = 440; 
$sampleRate = 44100; 
$samplesCount = 80000; 

$amplitude = 0.25 * 32768; 
$w = 2 * pi() * $freqOfTone/$sampleRate; 

//$dataArray = new 


$text = "RIFF" 
."80036" 
."WAVE" 
."fmt " 
."16" 
."1" 
."1" 
."44100" 
."44100" 
."1" 
."8" 
."data" 
."80000"; 

for ($n = 0; $n < $samplesCount; $n++) 
{ 
    $text .= (int)($amplitude * sin($n * $w)); 
} 


$myfile = fopen("sine.wav", "w") or die("Unable to open file!"); 

fwrite($myfile, $text); 

fclose($myfile); 
+2

Scrivi i dati in "testo". Un file wave è "binario". –

+2

Che cosa @CommuSoft sta cercando di dire è che devi scrivere i valori dei byte, non il contenuto del testo. Ad esempio, invece di scrivere ''44100'', devi scrivere i byte' 0xAC44'. –

+0

@ Ismael Miguel - Allora perché non usa il valore byte per 80036? – lopata

risposta

5

Il problema è che l'algoritmo scrive i numeri come testo. Considerando che un file .wav codifica il file binario dati.

È possibile utilizzare ad esempio pack per raggruppare i dati.

$freqOfTone = 440; 
$sampleRate = 44100; 
$samplesCount = 80000; 

$amplitude = 0.25 * 32768; 
$w = 2 * pi() * $freqOfTone/$sampleRate; 

$samples = array(); 
for ($n = 0; $n < $samplesCount; $n++) { 
    $samples[] = (int)($amplitude * sin($n * $w)); 
} 

$srate = 44100; //sample rate 
$bps = 16; //bits per sample 
$Bps = $bps/8; //bytes per sample /// I EDITED 

$str = call_user_func_array("pack", 
    array_merge(array("VVVVVvvVVvvVVv*"), 
     array(//header 
      0x46464952, //RIFF 
      160038,  //File size 
      0x45564157, //WAVE 
      0x20746d66, //"fmt " (chunk) 
      16, //chunk size 
      1, //compression 
      1, //nchannels 
      $srate, //sample rate 
      $Bps*$srate, //bytes/second 
      $Bps, //block align 
      $bps, //bits/sample 
      0x61746164, //"data" 
      160000 //chunk size 
     ), 
     $samples //data 
    ) 
); 
$myfile = fopen("sine.wav", "wb") or die("Unable to open file!"); 
fwrite($myfile, $str); 
fclose($myfile); 

Questo produce file.

Si noti che non è possibile riutilizzare l'intestazione precedente. Alcuni aspetti erano hardcoded che differiscono (come la dimensione del file, il numero di canali, il bitrate, ecc.). Ma se si legge documentation, si può facilmente modificare l'intestazione di conseguenza.

+3

Non dimenticare di cambiare anche 'fopen (" sine.wav "," w ")' in 'fopen (" sine.wav "," w + b ")' (si noti l'ultimo parametro). Ciò evita che Windows traduca '\ r \ n' (CRLF) in' \ r' (CR). –

+0

@IsmaelMiguel: In realtà può essere semplicemente 'fopen (" sine.wav "," wb ")', il '+' non è necessario. –

+0

@RocketHazmat Non è necessario, ma è sempre sicuro utilizzarlo. Giusto per garantire che il file verrà troncato. –