سؤال

في الوقت الحقيقي تتحرك الموجي

ألعب حاليًا باستخدام Web Audio API وقمت بإنشاء نطاق باستخدام اللوحة القماشية.

function animate(){
 var a=new Uint8Array(analyser.frequencyBinCount),
     y=new Uint8Array(analyser.frequencyBinCount),b,c,d;
 analyser.getByteTimeDomainData(y);
 analyser.getByteFrequencyData(a);
 b=c=a.length;
 d=w/c;
 ctx.clearRect(0,0,w,h);
 while(b--){
  var bh=a[b]+1;
  ctx.fillStyle='hsla('+(b/c*240)+','+(y[b]/255*100|0)+'%,50%,1)';
  ctx.fillRect(1*b,h-bh,1,bh);
  ctx.fillRect(1*b,y[b],1,1);
 }
 animation=webkitRequestAnimationFrame(animate);
}

سؤال صغير:هل هناك طريقة لعدم الكتابة 2 مرات new Uint8Array(analyser.frequencyBinCount)?

تجريبي

أضف ملف MP3/MP4 وانتظر.(تم اختباره في كروم)

http://jsfiddle.net/pc76H/2/

ولكن هناك العديد من المشاكل.لا يمكنني العثور على الوثائق المناسبة لمرشحات الصوت المختلفة.

وأيضًا إذا نظرت إلى الطيف ستلاحظ أنه بعد 70% أو النطاق لا توجد بيانات.ماذا يعني ذالك؟ربما من 16 كيلو هرتز إلى 20 كيلو هرتز لا يوجد صوت؟أود أن أطبق نصًا على اللوحة القماشية لإظهار هرتز المختلفة.لكن أين؟؟

اكتشفت أن البيانات التي تم إرجاعها هي قوة 32 في الطول مع الحد الأقصى من 2048 والارتفاع دائمًا 256.

لكن السؤال الحقيقي هو...أريد إنشاء شكل موجي متحرك كما هو الحال في الجرار.

لقد فعلت ذلك بالفعل منذ بعض الوقت باستخدام PHP، حيث يقوم بتحويل الملف إلى معدل بت منخفض بدلاً من استخراج البيانات وتحويلها إلى صورة.لقد وجدت السيناريو في مكان ما ولكن لا أتذكر أين..ملحوظة:الاحتياجات عاجِز

<?php
$a=$_GET["f"];
if(file_exists($a)){
    if(file_exists($a.".png")){
        header("Content-Type: image/png");
        echo file_get_contents($a.".png");
    }else{
        $b=3000;$c=300;define("d",3);
        ini_set("max_execution_time","30000");
        function n($g,$h){
            $g=hexdec(bin2hex($g));
            $h=hexdec(bin2hex($h));
            return($g+($h*256));
        };
        $k=substr(md5(time()),0,10);
        copy(realpath($a),"/var/www/".$k."_o.mp3");
        exec("lame /var/www/{$k}_o.mp3 -f -m m -b 16 --resample 8 /var/www/{$k}.mp3 && lame --decode /var/www/{$k}.mp3 /var/www/{$k}.wav");
        //system("lame {$k}_o.mp3 -f -m m -b 16 --resample 8 {$k}.mp3 && lame --decode {$k}.mp3 {$k}.wav");
        @unlink("/var/www/{$k}_o.mp3");
        @unlink("/var/www/{$k}.mp3");
        $l="/var/www/{$k}.wav";
        $m=fopen($l,"r");
        $n[]=fread($m,4);
        $n[]=bin2hex(fread($m,4));
        $n[]=fread($m,4);
        $n[]=fread($m,4);
        $n[]=bin2hex(fread($m,4));
        $n[]=bin2hex(fread($m,2));
        $n[]=bin2hex(fread($m,2));
        $n[]=bin2hex(fread($m,4));
        $n[]=bin2hex(fread($m,4));
        $n[]=bin2hex(fread($m,2));
        $n[]=bin2hex(fread($m,2));
        $n[]=fread($m,4);
        $n[]=bin2hex(fread($m,4));
        $o=hexdec(substr($n[10],0,2));
        $p=$o/8;
        $q=hexdec(substr($n[6],0,2));
        if($q==2){$r=40;}else{$r=80;};
        while(!feof($m)){
            $t=array();
            for($i=0;$i<$p;$i++){
                $t[$i]=fgetc($m);
            };
            switch($p){
                case 1:$s[]=n($t[0],$t[1]);break;
                case 2:if(ord($t[1])&128){$u=0;}else{$u=128;};$u=chr((ord($t[1])&127)+$u);$s[]= floor(n($t[0],$u)/256);break;
            };
            fread($m,$r);
        };
        fclose($m);
        unlink("/var/www/{$k}.wav");
        $x=imagecreatetruecolor(sizeof($s)/d,$c);
        imagealphablending($x,false);
        imagesavealpha($x,true);
        $y=imagecolorallocatealpha($x,255,255,255,127);
        imagefilledrectangle($x,0,0,sizeof($s)/d,$c,$y);
        for($d=0;$d<sizeof($s);$d+=d){
            $v=(int)($s[$d]/255*$c);
            imageline($x,$d/d,0+($c-$v),$d/d,$c-($c-$v),imagecolorallocate($x,255,0,255));
        };
        $z=imagecreatetruecolor($b,$c);
        imagealphablending($z,false);
        imagesavealpha($z,true);
        imagefilledrectangle($z,0,0,$b,$c,$y);
        imagecopyresampled($z,$x,0,0,0,0,$b,$c,sizeof($s)/d,$c);
        imagepng($z,realpath($a).".png");
        header("Content-Type: image/png");
        imagepng($z);
        imagedestroy($z);
    };
}else{
    echo $a;
};

?>

السيناريو يعمل...لكنك مقيد بحد أقصى لحجم الصورة يبلغ 4 كيلو بكسل.

لذلك ليس لديك شكل موجي لطيف إذا كان يجب أن يمثل بضعة ميلي ثانية فقط.

ما الذي أحتاجه لتخزين/إنشاء شكل موجي في الوقت الفعلي مثل تطبيق traktors أو برنامج php هذا؟راجع للشغل يحتوي الجرار أيضًا على شكل موجي ملون (لا يوجد برنامج PHP النصي).

يحرر

لقد قمت بإعادة كتابة السيناريو الخاص بك أنه يناسب فكرتي ...إنه سريع نسبيًا.

كما ترون داخل الوظيفة createArray أقوم بدفع الخطوط المختلفة إلى كائن باستخدام المفتاح كإحداثي x.

أنا ببساطة آخذ الرقم الأعلى.

هنا حيث يمكننا اللعب بالألوان.

var ajaxB,AC,B,LC,op,x,y,ARRAY={},W=1024,H=256;
var aMax=Math.max.apply.bind(Math.max, Math);
function error(a){
 console.log(a);
};
function createDrawing(){
 console.log('drawingArray');
 var C=document.createElement('canvas');
 C.width=W;
 C.height=H;
 document.body.appendChild(C);
 var context=C.getContext('2d');
 context.save();
 context.strokeStyle='#121';
 context.globalCompositeOperation='lighter';
 L2=W*1;
 while(L2--){
  context.beginPath();
  context.moveTo(L2,0);
  context.lineTo(L2+1,ARRAY[L2]);
  context.stroke();
 }
 context.restore();
};
function createArray(a){
 console.log('creatingArray');
 B=a;
 LC=B.getChannelData(0);// Float32Array describing left channel
 L=LC.length;  
 op=W/L;
 for(var i=0;i<L;i++){
  x=W*i/L|0;
  y=LC[i]*H/2;
  if(ARRAY[x]){
   ARRAY[x].push(y)
  }else{
   !ARRAY[x-1]||(ARRAY[x-1]=aMax(ARRAY[x-1]));
   // the above line contains an array of values
   // which could be converted to a color 
   // or just simply create a gradient 
   // based on avg max min (frequency???) whatever
   ARRAY[x]=[y]
  }
 };
 createDrawing();
};
function decode(){
 console.log('decodingMusic');
 AC=new webkitAudioContext
 AC.decodeAudioData(this.response,createArray,error);
};
function loadMusic(url){
 console.log('loadingMusic');   
 ajaxB=new XMLHttpRequest;
 ajaxB.open('GET',url);
 ajaxB.responseType='arraybuffer';    
 ajaxB.onload=decode;
 ajaxB.send();
}
loadMusic('AudioOrVideo.mp4');
هل كانت مفيدة؟

المحلول

حسنًا، ما سأفعله هو تحميل الصوت باستخدام XMLHttpRequest، ثم فك تشفيره باستخدام webaudio، ثم عرضه "بعناية" للحصول على الألوان التي تبحث عنها.

لقد قمت للتو بإنشاء نسخة سريعة، ونسخ ولصق من العديد من مشاريعي، وهي تعمل تمامًا، كما ترون في هذه الصورة:

enter image description here

المشكلة هي أنها بطيئة مثل الجحيم.للحصول على سرعة لائقة (أكثر)، سيتعين عليك إجراء بعض العمليات الحسابية لتقليل عدد الخطوط المراد رسمها على اللوحة القماشية، لأنه عند 441000 هرتز، ستحصل بسرعة كبيرة على عدد كبير جدًا من الخطوط التي يجب رسمها.

// AUDIO CONTEXT
window.AudioContext = window.AudioContext || window.webkitAudioContext ;

if (!AudioContext) alert('This site cannot be run in your Browser. Try a recent Chrome or Firefox. ');

var audioContext = new AudioContext();
var currentBuffer  = null;

// CANVAS
var canvasWidth = 512,  canvasHeight = 120 ;
var newCanvas   = createCanvas (canvasWidth, canvasHeight);
var context     = null;

window.onload = appendCanvas;
function appendCanvas() { document.body.appendChild(newCanvas);
                          context = newCanvas.getContext('2d'); }

// MUSIC LOADER + DECODE
function loadMusic(url) {   
    var req = new XMLHttpRequest();
    req.open( "GET", url, true );
    req.responseType = "arraybuffer";    
    req.onreadystatechange = function (e) {
          if (req.readyState == 4) {
             if(req.status == 200)
                  audioContext.decodeAudioData(req.response, 
                    function(buffer) {
                             currentBuffer = buffer;
                             displayBuffer(buffer);
                    }, onDecodeError);
             else
                  alert('error during the load.Wrong url or cross origin issue');
          }
    } ;
    req.send();
}

function onDecodeError() {  alert('error while decoding your file.');  }

// MUSIC DISPLAY
function displayBuffer(buff /* is an AudioBuffer */) {
   var leftChannel = buff.getChannelData(0); // Float32Array describing left channel     
   var lineOpacity = canvasWidth / leftChannel.length  ;      
   context.save();
   context.fillStyle = '#222' ;
   context.fillRect(0,0,canvasWidth,canvasHeight );
   context.strokeStyle = '#121';
   context.globalCompositeOperation = 'lighter';
   context.translate(0,canvasHeight / 2);
   context.globalAlpha = 0.06 ; // lineOpacity ;
   for (var i=0; i<  leftChannel.length; i++) {
       // on which line do we get ?
       var x = Math.floor ( canvasWidth * i / leftChannel.length ) ;
       var y = leftChannel[i] * canvasHeight / 2 ;
       context.beginPath();
       context.moveTo( x  , 0 );
       context.lineTo( x+1, y );
       context.stroke();
   }
   context.restore();
   console.log('done');
}

function createCanvas ( w, h ) {
    var newCanvas = document.createElement('canvas');
    newCanvas.width  = w;     newCanvas.height = h;
    return newCanvas;
};


loadMusic('could_be_better.mp3');

يحرر :المشكلة هنا هي أن لدينا الكثير من البيانات التي يجب رسمها.خذ 3 دقائق بصيغة mp3، سيكون لديك 3*60*44100 = حوالي 8.000.000 خط للرسم.على شاشة بدقة 1024 بكسل، على سبيل المثال، تنتج 8.000 خط لكل بكسل...
في الكود أعلاه، تقوم اللوحة القماشية بـ "إعادة التشكيل"، عن طريق رسم خطوط ذات عتامة منخفضة وفي وضع التركيب "الأخف" (على سبيل المثال.سيتم إضافة r،g،b للبكسل).
لتسريع الأمور، يجب عليك إعادة أخذ العينات بنفسك، ولكن للحصول على بعض الألوان، لا يقتصر الأمر على مجرد أخذ عينات منخفضة، بل سيتعين عليك التعامل مع مجموعة (ضمن مصفوفة الأداء على الأرجح) من "الجرافات"، واحد لكل بكسل أفقي (على سبيل المثال، 1024)، وفي كل مجموعة تقوم بحساب ضغط الصوت المتراكم، والتباين، والحد الأدنى، والحد الأقصى، وبعد ذلك، في وقت العرض، عليك أن تقرر كيفية عرض ذلك مع الألوان.
على سبيل المثال :
القيم بين 0 إيجابيMin واضحة جدًا.(أي عينة أقل من تلك النقطة).
القيم بين إيجابيMin وpositiveAverage - التباين أغمق،
القيم بين المتوسط ​​الموجب - التباين والمتوسط ​​الموجب + التباين أكثر قتامة،
والقيم بينpositiveAverage+variance وpositiveMax أخف.
(نفس الشيء بالنسبة للقيم السلبية) التي تجعل 5 ألوان لكل دلو ، وما زالت بعض العمل ، لكي تترمز وللحساب المتصفح.
لا أعرف ما إذا كان الأداء يمكن أن يصبح لائقًا مع هذا، ولكن أخشى أنه لا يمكن الوصول إلى دقة الإحصائيات والترميز اللوني للبرنامج الذي ذكرته عبر المتصفح (من الواضح أنه ليس في الوقت الفعلي)، وأنك سيتعين علينا تقديم بعض التنازلات.

تحرير 2 :
حاولت الحصول على بعض الألوان من الإحصائيات لكنها فشلت تمامًا.تخميني الآن هو أن الأشخاص في جهاز التتبع يغيرون اللون أيضًا حسب التردد....بعض العمل هنا....

على أي حال، فقط للسجل، يتبع رمز الاختلاف المتوسط/المتوسط.
(كان التباين منخفضًا جدًا، وكان علي استخدام متوسط ​​التباين).

enter image description here

// MUSIC DISPLAY
function displayBuffer2(buff /* is an AudioBuffer */) {
   var leftChannel = buff.getChannelData(0); // Float32Array describing left channel       
   // we 'resample' with cumul, count, variance
   // Offset 0 : PositiveCumul  1: PositiveCount  2: PositiveVariance
   //        3 : NegativeCumul  4: NegativeCount  5: NegativeVariance
   // that makes 6 data per bucket
   var resampled = new Float64Array(canvasWidth * 6 );
   var i=0, j=0, buckIndex = 0;
   var min=1e3, max=-1e3;
   var thisValue=0, res=0;
   var sampleCount = leftChannel.length;
   // first pass for mean
   for (i=0; i<sampleCount; i++) {
        // in which bucket do we fall ?
        buckIndex = 0 | ( canvasWidth * i / sampleCount );
        buckIndex *= 6;
        // positive or negative ?
        thisValue = leftChannel[i];
        if (thisValue>0) {
            resampled[buckIndex    ] += thisValue;
            resampled[buckIndex + 1] +=1;               
        } else if (thisValue<0) {
            resampled[buckIndex + 3] += thisValue;
            resampled[buckIndex + 4] +=1;                           
        }
        if (thisValue<min) min=thisValue;
        if (thisValue>max) max = thisValue;
   }
   // compute mean now
   for (i=0, j=0; i<canvasWidth; i++, j+=6) {
       if (resampled[j+1] != 0) {
             resampled[j] /= resampled[j+1]; ;
       }
       if (resampled[j+4]!= 0) {
             resampled[j+3] /= resampled[j+4];
       }
   }
   // second pass for mean variation  ( variance is too low)
   for (i=0; i<leftChannel.length; i++) {
        // in which bucket do we fall ?
        buckIndex = 0 | (canvasWidth * i / leftChannel.length );
        buckIndex *= 6;
        // positive or negative ?
        thisValue = leftChannel[i];
        if (thisValue>0) {
            resampled[buckIndex + 2] += Math.abs( resampled[buckIndex] - thisValue );               
        } else  if (thisValue<0) {
            resampled[buckIndex + 5] += Math.abs( resampled[buckIndex + 3] - thisValue );                           
        }
   }
   // compute mean variation/variance now
   for (i=0, j=0; i<canvasWidth; i++, j+=6) {
        if (resampled[j+1]) resampled[j+2] /= resampled[j+1];
        if (resampled[j+4]) resampled[j+5] /= resampled[j+4];   
   }
   context.save();
   context.fillStyle = '#000' ;
   context.fillRect(0,0,canvasWidth,canvasHeight );
   context.translate(0.5,canvasHeight / 2);   
  context.scale(1, 200);

   for (var i=0; i< canvasWidth; i++) {
        j=i*6;
       // draw from positiveAvg - variance to negativeAvg - variance 
       context.strokeStyle = '#F00';
       context.beginPath();
       context.moveTo( i  , (resampled[j] - resampled[j+2] ));
       context.lineTo( i  , (resampled[j +3] + resampled[j+5] ) );
       context.stroke();
       // draw from positiveAvg - variance to positiveAvg + variance 
       context.strokeStyle = '#FFF';
       context.beginPath();
       context.moveTo( i  , (resampled[j] - resampled[j+2] ));
       context.lineTo( i  , (resampled[j] + resampled[j+2] ) );
       context.stroke();
       // draw from negativeAvg + variance to negativeAvg - variance 
       // context.strokeStyle = '#FFF';
       context.beginPath();
       context.moveTo( i  , (resampled[j+3] + resampled[j+5] ));
       context.lineTo( i  , (resampled[j+3] - resampled[j+5] ) );
       context.stroke();
   }
   context.restore();
   console.log('done 231 iyi');
}

نصائح أخرى

giveacodicetagpre.

مرحبا تواجه أيضا مشكلة تحميل الوقت.فقط لقد سيطرت على أنه من خلال تقليل عدد الأسطر يريد الاستفادة من وضع استدعاء دعوة لوظيفة قماش صغيرة.انظر التعليمة البرمجية التالية للرجوع اليها.

giveacodicetagpre.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top