Skip to content

Instantly share code, notes, and snippets.

@licson
Last active April 6, 2022 23:47
Show Gist options
  • Select an option

  • Save licson/4417186 to your computer and use it in GitHub Desktop.

Select an option

Save licson/4417186 to your computer and use it in GitHub Desktop.
<?php
class FourierTransform {
public $bufferSize;
public $sampleRate;
public $bandwidth;
public $spectrum = array();
public $real = array();
public $imag = array();
public $peakBand = 0;
public $peak = 0;
public function __construct($bufferSize,$sampleRate){
$this->bufferSize = $bufferSize;
$this->sampleRate = $sampleRate;
$this->bandwidth = 2 / $bufferSize * $sampleRate / 2;
}
public function getBandFrequency($index){
return $this->bandwidth * $index + $this->bandwidth / 2;
}
public function calculateSpectrum(){
$bSi = 2 / $this->bufferSize;
for($i = 0,$N = $this->bufferSize/2; $i < $N; $i++){
$rval = $this->real[$i];
$ival = $this->imag[$i];
$mag = $bSi * sqrt($rval * $rval + $ival * $ival);
if($mag > $this->peak){
$this->peakBand = $i;
$this->peak = $mag;
}
$this->spectrum[$i] = $mag;
}
}
}
class FFT extends FourierTransform {
public $reverseTable = array();
public $sinTable = array();
public $cosTable = array();
public function __construct($bufferSize,$sampleRate){
parent::__construct($bufferSize,$sampleRate);
$limit = 1;
$bit = $bufferSize >> 1;
while($limit < $bufferSize){
for($i = 0; $i < $limit; $i++){
$this->reverseTable[$i + $limit] = $this->reverseTable[$i] + $bit;
}
$limit = $limit << 1;
$bit = $bit >> 1;
}
for($i = 0; $i < $bufferSize; $i++){
$this->sinTable[$i] = sin(-M_PI / $i);
$this->cosTable[$i] = cos(-M_PI / $i);
}
}
public function foward($buffer){
$k = floor(log($this->bufferSize,2));
if(pow(2,$k) !== $this->bufferSize) throw new Exception('Invalid buffer size, must be a power of 2.');
if($this->bufferSize !== count($buffer)) throw new Exception('Supplied buffer is not the same size as defined FFT.');
$halfSize = 1;
for($i = 0; $i < $this->bufferSize; $i++){
$this->real[$i] = $buffer[$this->reverseTable[$i]];
$this->imag[$i] = 0;
}
while($halfSize < $this->bufferSize){
$phaseShiftReal = $this->cosTable[$halfSize];
$phaseShiftImag = $this->sinTable[$halfSize];
$currentPhaseShiftReal = 1;
$currentPhaseShiftImag = 0;
for($fftStep = 0; $fftStep < $halfSize; $fftStep++){
while($fftStep < $this->bufferSize){
$off = $fftStep + $halfSize;
$tr = ($currentPhaseShiftReal * $this->real[$off]) - ($currentPhaseShiftImag * $this->imag[$off]);
$ti = ($currentPhaseShiftReal * $this->imag[$off]) + ($currentPhaseShiftImag * $this->real[$off]);
$this->real[$off] = $this->real[$fftStep] - $tr;
$this->imag[$off] = $this->imag[$fftStep] - $ti;
$this->real[$fftStep] += $tr;
$this->imag[$fftStep] += $ti;
$fftStep += $halfSize << 1;
}
$tmpReal = $currentPhaseShiftReal;
$currentPhaseShiftReal = ($tmpReal * $phaseShiftReal) - ($currentPhaseShiftImag * $phaseShiftImag);
$currentPhaseShiftImag = ($tmpReal * $phaseShiftImag) + ($currentPhaseShiftImag * $phaseShiftReal);
}
$halfSize = $halfSize << 1;
}
$this->calculateSpectrum();
}
}
?>
<?php
@set_time_limit(0);
require('fft.php');
$fft = new FFT(1024,44100);
$im = imagecreatetruecolor(200,200);
function genBuffer(){
$buf = array();
for($i = 0; $i < 1024; $i++){
$buf[$i] = ((($i>>7|$i|$i>>6)*10+4*($i&$i>>13|$i>>6))&255);
}
return $buf;
}
for($i = 0; $i < 100; $i++){
$fft->foward(genBuffer());
foreach($fft->spectrum as $k=>$n){
imagefilledrectangle($im,$i*imagesx($im)/100,$k*imagesy($im)/count($fft->spectrum),imagesx($im)/100,imagesy($im)/count($fft->spectrum),imagecolorallocate($im,$n*255,$n*255,$n*255));
}
}
header('Content-type: image/png');
imagepng($im);
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment