我如何捕捉什么按钮被按下的序列,何时

How do I capture a sequence of what button was pressed and when?

本文关键字:何时 何捕捉 什么 按钮      更新时间:2023-09-26

我发现很难理解javascript是如何工作的,特别是当我自己写代码的时候,所以我请一个朋友帮助我,并提供了这样的东西。

var curtime = new Date();
delaytime = curtime.getTime() - previoustime.getTime();
previoustime.setTime( curtime.getTime());
temparray = new Array;
temparray.push( name );
temparray.push( delaytime );
recording.push( temparray);

,但我似乎不能掌握的概念,它如何链接到我的按钮,并保存到一个数组。我希望能够使用这些记录的信息,然后准确地播放用户输入的内容,但是一次一步。

如果有人能帮助我进入下一个阶段,我会非常感激,因为我对javascript迷路了。

有趣的问题。考虑这样一个事实:对于任何给定的事件,每个元素可以触发多个事件处理程序。这是什么意思?你可以同时将(a)一个"真正"工作的功能和(b)一个记账功能附加到一个按钮上。(不过,不能保证调用它们的顺序——它们不需要按照添加的顺序调用——这可能已经改变了,我已经有6个月没看了)

另外,由于我使用. addeventlistener附加了事件处理程序,因此this关键字引用了首先触发事件的html元素。-这就是为什么我可以附加一个单一的'通用'功能到所有按钮提取任何必要的信息,从他们。

因此,您只需要将这两个函数附加到您想要记录信息的任何元素。这里有一个简单的例子。希望能有所帮助。

<!doctype html>
<html>
<head>
<script>
function onBtn1(evt)
{
    alert('you pressed button 1');
}
function onBtn2(evt)
{
    alert('btn2');
}
function onBtn3(evt)
{
    alert('pressed btn 3');
}
function onShowRecordsBtn(evt)
{
    var i, n = eventList.length;
    var tgt = byId('outputTgt');
    var msg = '';
    for (i=0; i<n; i++)
    {
        // all entries except the first one must be preceded with a new-line
        if (i != 0)
            msg += "<br>";
        // show the id and time of each clicked button
        msg += "ID: " + eventList[i].elemId + " - Time: " + eventList[i].time;
    }
    tgt.innerHTML = msg;
}

// declare an empty array to hold the list of events.
var eventList = [];
function saveBtnPressInfo(evt)
{
    var curRecord = { time: new Date(), elemId: this.id};
// same as preceding line of code
//  var curRecord = { time: null, elemId: null};
//  curRecord.time = new Date();
//  curRecord.elemId = this.id;
    eventList.push(curRecord);
}
window.addEventListener('load', onPageLoaded, false);
function byId(e){return document.getElementById(e);}
function onPageLoaded(evt)
{
    // add the (unique) event handlers to the buttons
    byId('btn1').addEventListener('click', onBtn1, false);
    byId('btn2').addEventListener('click', onBtn2, false);
    byId('btn3').addEventListener('click', onBtn3, false);
    // add the event to the showEvents 'button' - I made it an inut element so that it doesn't get
    // found when we get a list of all <button> elements on the page. (I don't want to know when the user asked for button-press stats)
    byId('showRecordsBtn').addEventListener('click', onShowRecordsBtn, false);
    // add the record-keeping function to each of the buttons
    var btnList = document.getElementsByTagName('button');
    var i, n = btnList.length;
    for (i=0; i<n; i++)
    {
        btnList[i].addEventListener('click', saveBtnPressInfo, false);
    }
}
</script>
<style>
</style>
</head>
<body>
    <button id='btn1'>Button 1</button>
    <button id='btn2'>Button 2</button>
    <button id='btn3'>Button 3</button>
    <hr>
    <input id='showRecordsBtn' type='button' value='Show btn-click activity'/>
    <div id='outputTgt'></div>
</body>
</html>
编辑:

下面是一些使用(乐器)合成器的代码,如在Voxel Bukkake中找到的。在这段代码中,我只是简单地播放音符,以响应乐器样本上的点击。从内存中,您可以使用. noteon的参数来指定从发出呼叫到应该发出提示之间的毫秒数。

<!DOCTYPE html>
<html>
<head>
<script>
function byId(e){return document.getElementById(e);}
function newEl(tag){return document.createElement(tag);}
function newTxt(txt){return document.createTextNode(txt);}
function toggleClass(element, newStr)
{
    index=element.className.indexOf(newStr);
    if ( index == -1)
        element.className += ' '+newStr;
    else
    {
        if (index != 0)
            newStr = ' '+newStr;
        element.className = element.className.replace(newStr, '');
    }
}
function forEachNode(nodeList, func)
{
    var i, n = nodeList.length;
    for (i=0; i<n; i++)
    {
        func(nodeList[i], i, nodeList);
    }
}

var current_time = 0;
function Instrument(attack, delay, sustain, release, sustainTime, cutoff, resonance, lfoFreq, lfoAmp, detuneSquare, detuneSaw, squareVol, sawVol, noiseVol)
{
    // volume envelope
    this.A = attack;
    this.D = delay;
    this.S = sustain;
    this.R = release;
    this.sustainTime = sustainTime;
    this.cutoff = cutoff;
    this.resonance = resonance;
    this.lfo_freq = lfoFreq;
    this.lfo_amp = lfoAmp;
    this.square_detune = detuneSquare;
    this.saw_detune = detuneSaw;
    this.square_vol = squareVol;
    this.saw_vol = sawVol;
    this.noise_vol = noiseVol;
}
function Voice(pitch, pos, ins, vol, active)
{
    this.pitch = pitch;
    this.pos = pos;     // position in samples from the beginning
    this.ins = ins;     // instrument
    this.vol = vol;
    this.xn = [0,0,0];//[1.0,1.0,1.0];
    this.yn = [0,0,0];//[1.0,1.0,1.0];
    this.active = 0;    // 0 = inactive, (not 0) = active
}
function synth(v, len, mix_buf)
{
    current_time = 100;
    var ins = v.ins;
    //var pitch_sine  = v->pitch * ins->sine_detune;
    var pitch_square = v.pitch * ins.square_detune;
    var pitch_saw    = v.pitch * ins.saw_detune;
    var vol, res, t;
    var i;
    var invSAMPLE_RATE = 1 / 44100;
    var periodo_square = 1.0/pitch_square;
    v.pos = 0;
    for (i=0; i<len; i++)
    {
        res=0;
        t = (v.pos+i)*invSAMPLE_RATE;
//      t >>= 0;
        // First add the oscillators
        // Sine
        //res = ins->sine_vol * msin(DOSPI*pitch_sine*t);

        // Square
        if ( (t % periodo_square) > (periodo_square/2.0))
            res += ins.square_vol;
        else
            res -= ins.square_vol;
        // Saw
        res += ins.saw_vol * ( ( (t*pitch_saw)% 2.0) - 1.0);
        // Noise
        res += ins.noise_vol * (2.0*whitenoise()-1.0) ;
        // We now apply the ADSR
        vol = getAmp(ins, t);
        res *= vol;
        // We estimate the value of applying cutoff LFO
        var cutoff, lfo_freq;
        if (ins.lfo_freq < 0)
        {
            lfo_freq = -ins.lfo_freq;
            t = current_time;
        }
        else
        {
            lfo_freq = ins.lfo_freq;
        }
        var DOSPI = 6.2831853071795862;
        cutoff= ins.cutoff + ins.lfo_amp * Math.cos(DOSPI * lfo_freq * t);
        var r = ins.resonance;
        // Calculate filter coefficients
        var c, c2,a1,a2,b1,b2;
        //We extract some calculations that are redundant in HP and LP
        var PI_samplerate = 0.000071237928652829774;
        var param_tan = PI_samplerate * cutoff;
        if (cutoff > 0.0) // Low-pass
        {
            c = 1.0 / Math.tan(param_tan);
            c2 = c*c;
            a1 = 1.0 / ( 1.0 + r * c + c2);
            a2 = 2.0 * a1;
            b1 = 2.0 * ( 1.0 - c2) * a1;
        }
        else // High-pass
        {
            c = Math.tan(-param_tan);
            c2 = c*c;
            a1 = 1.0 / ( 1.0 + r * c + c2);
            a2 = -2*a1;
            b1 = 2.0 * ( c2 - 1.0) * a1;
        }
        b2 = ( 1.0 - r * c + c2) * a1;
        v.yn[0] = (a1*res) + (a2*v.xn[1]) + (a1*v.xn[2]) - (b1*v.yn[1]) - (b2*v.yn[2]);
        v.xn[2]=v.xn[1];
        v.xn[1]=res;
        v.yn[2]=v.yn[1];
        v.yn[1]=v.yn[0];
        // From here already filtering res
        mix_buf[i] += v.yn[0] * v.vol;
    }
    v.pos+=len;
    if (vol > 0.0)
        return 1;
    return 0;
}
// Returns the value of time pos ADSR
// Linear interpolation
// function getAmp(instrument, pos)
function getAmp(i, pos)
{
    var A = i.A/100 + 0.00001;
    if (pos <= A)
        return (pos/A);
    pos -= A;
    var D = i.D / 100;
    var S = i.S / 100;
    if (pos <= D)
        return (1.0 - (pos * (1 - S)) / D);
    pos -= D;
    var sustain_time = i.sustainTime/100;
    if (pos <= sustain_time)
        return S;
    pos -= sustain_time;
    var R = i.R/100;
    if (pos < R)
        return S - S * (pos/R);
    else
        return 0;
}
function whitenoise()
{ 
    return Math.random();
}

////============================================================
window.addEventListener('load', mInit, false);
var context;
function mInit()
{
    context = new webkitAudioContext();
    var hihat = new Instrument(  1,5,15,50,0, -12000,1.1,  1.500,8000, 1.0,0.5, 0.5,0.3,   1.2);
     var drum = new Instrument( 1,15,40,5,0,     20, 1.0, 1.0, 200, 1.5,1.0, 1.0,0.5,   2.4);
      var low = new Instrument( 1,15,40,5,0,    800,1.0, -0.500,-600, 1.0,1.0,0.4,0.7,   0.0);
    var organ = new Instrument(50,30,45,100,20,  -1150,1.0, -8.333,-950, 0.501,1.0, 0.5,0.7, 0.0);
     var lead = new Instrument( 0,10,50,40,20,    900,1.0,  1.500, 900, 0.5,1.0, 0.8,0.4,  0.0);

    var simon = new Instrument(10,10,50,75,70,    800,0.25,  1.500,700, 0.8,0.8, 0.5,0.5,  0.0);
    //function Insrument(attack, delay, sustain, release, sustainTime,   cutoff, resonance,   lfoFreq, lfoAmp, detuneSquare, detuneSaw, squareVol, sawVol, noiseVol)
    var start = new Date();
    addPlayableGraph(hihat);
//  addPlayableGraph(drum);
//  addPlayableGraph(low);
    addPlayableGraph(organ);
    addPlayableGraph(lead);
    addPlayableGraph(simon);
    var end = new Date();
    var diff = end-start;
    start = newTxt('Calculation Time: ' + diff + 'ms');
    document.body.appendChild(start);

    var coords = newEl('div');
    coords.setAttribute('id', 'coords');
    document.body.appendChild(coords);
}
function addPlayableGraph(instrument)
{
    var note = 43;
    var pitch = 440.0 * Math.pow(2.0, (note-45.0)/12.0);
    var pos = 0;
    var vol = 0.4;
    var active = 1.0;
    var voice = new Voice(pitch, pos, instrument, vol, active);
    var buffer = [];
    var i, n=4410 * (20);
    for (i=0; i<n; i++)
        buffer[i] = 0.0;
    voice.active = synth(voice, n, buffer);
    var canvas = newEl('canvas');
    canvas.height = 96;
    canvas.width = 1024;
    document.body.appendChild(canvas);
    drawFloatArray(buffer, canvas);
    canvas.mBuffer = buffer;
    canvas.onclick = function() { playSound(this.mBuffer, 44100, 100); };
    canvas.onmousemove = 
    function(e)
    {
        e = e || event;
        var str = 'Pos: ' + (e.clientX/canvas.width)*2000 + ',' + e.clientY;
        byId('coords').innerText = str;
    }
    return canvas;                  
}
function drawFloatArray(samples, canvas)
{
    var i, n = samples.length;
    var dur = (n / 44100 * 1000)>>0;
    canvas.title = 'Duration: ' +  dur / 1000.0 + 's';
    var width=canvas.width,height=canvas.height;
    var ctx = canvas.getContext('2d');
    ctx.strokeStyle = 'yellow';
    ctx.fillStyle = '#303030';
    ctx.fillRect(0,0,width,height);
    ctx.moveTo(0,height/2);
    ctx.beginPath();
    for (i=0; i<n; i++)
    {
        x = (i*width) / n;
        y = (samples[i]*height/2)+height/2;
        ctx.lineTo(x, y);
    }
    ctx.stroke();
    ctx.closePath();
}
function playSound(buffer, freq, vol)   // buffer, 44100, 0-100
{
    var mBuffer = context.createBuffer(1, buffer.length, freq);
    var dataBuffer = mBuffer.getChannelData(0);
    var soundBuffer = buffer;
    var i, n = buffer.length;
    for (i=0;i<n;i++)
        dataBuffer[i] = soundBuffer[i];

    var node = context.createBufferSource();
    node.buffer = mBuffer;
    node.gain.value = 0.5 * vol/100.0;
    node.connect(context.destination);
    node.noteOn(0);
}
</script>
<style>
</style>
</head>
<body>
</body>
</html>

最后,您可以查看http://www.iquilezles.org/apps/soundtoy/找到一种方法,该方法使用"简单"的数学方程来定义仪器。但是要特别注意——寻找允许单个公式(乐器)产生不同音高的声音的代码(如果你需要的话)

您可能只需要使用。noteon参数来播放您已经拥有的mp3。不记得我是否像这样播放过加载的声音,或者只是生成的东西。

很多有趣的浏览器生成的内容,也就是

可以采用两种基本的播放方法。您可以计算出每个音符之间的延迟,然后逐个播放每个音符,等待每个音符之间的间隔,然后使用noteOn(0)播放下一个音符。这将消耗最少的内存,但将阻止同时启动多个音符。

另一种方法是确定从播放开始到每个单独音符的时间,然后在声音输出开始之前将它们全部提示。你需要更多的内存,但我觉得这是一种更直观的方法。你也可以同时发出一堆音符,就像你需要为一个和弦,例如。

我对这段代码采用了第二种方法。你需要提供自己的声音样本(6个),并且必须通过localhost运行它,而不仅仅是从文件夹中双击它。我想这是因为我使用了AJAX来加载示例。

样本来自"chiptune"。Xm",如下代码所示:https://forum.tuts4you.com/files/file/184-snd-keygen-template-code-walker/(需要注册)你可以用一堆(amiga)中的任何一种提取样本"mod播放器"-这首歌大约2m18秒长,磁盘上只有25kb,因为它使用8khz或11khz的8bit单声道样本-还没有设法定义一些声音足够接近他们的算法,所以我只是使用我从中提取的was。

与这个问题最相关的功能应该在playSong2()中找到。这将获得歌曲中每个0.12秒的步骤中每个乐器的当前音符。它对音符进行重新采样,使其更长或更短,以便获得所需的不同音高,然后将数据发送出去,以便与调用noteOn一起播放。不管怎样,我现在很忙,希望我能帮到你一点忙。:)

玩得开心!

<!DOCTYPE html>
<html>
<head>
<script>
function byId(e){return document.getElementById(e);}
function newEl(tag){return document.createElement(tag);}
function newTxt(txt){return document.createTextNode(txt);}
function toggleClass(element, newStr)
{
    index=element.className.indexOf(newStr);
    if ( index == -1)
        element.className += ' '+newStr;
    else
    {
        if (index != 0)
            newStr = ' '+newStr;
        element.className = element.className.replace(newStr, '');
    }
}
function forEachNode(nodeList, func)
{
    var i, n = nodeList.length;
    for (i=0; i<n; i++)
    {
        func(nodeList[i], i, nodeList);
    }
}
window.addEventListener('load', mInit, false);
var guitar1, tmpContext;
var instruments = [];
function mInit()
{
    instruments.push(new sampledSound('audio/st88gbass.wav'));
    instruments.push(new sampledSound('audio/st03church.wav'));
    instruments.push(new sampledSound('audio/st88snare13.wav'));
    instruments.push(new sampledSound('audio/st03bastrumma.wav'));
    instruments.push(new sampledSound('audio/st03bassdrum6.wav'));
    instruments.push(new sampledSound('audio/st03guitar7.wav'));

//  instruments.forEach( function(elem){elem.canvas.addEventListener('click', mClick2, false);} );
/*  
    var rawSnd = new rawSound('audio/salida.raw.bin');
*/
    tmpContext = new webkitAudioContext();
}
function getFreq(noteNum)
{
    var pitch = 440.0 * Math.pow(2.0, (noteNum-45.0)/12.0);
    return pitch;
}
function mClick2()
{
//  function playSamples(floatArray, startTime)
//  function reSample(srcArray, origNote, newNote)
    var origNote = 36, newNote = 35;
    var newSamples;
//var samples = this.mBuffer.getChannelData(0); 
    var curTime = tmpContext.currentTime;
    newSamples = reSample(this.sampledSound.mBuffer.getChannelData(0), origNote, newNote);
    playSamples(newSamples, curTime + 0.3);
}

function mClick()
{
    var origNote = 36;
    var newNote = 37;
    var k = getFreq(origNote) / getFreq(newNote); //c4Hz / a3Hz;
    var srcBuffer = this.sampledSound.mBuffer;
    var srcSamples = srcBuffer.getChannelData(0);
//  alert('continue to play note D4 - ' + k + ' * the # of samples');
    var srcX, srcY, srcWidth, dstX, dstWidth, dstY;
    var srcX, srcDx;
    var dstSamples = new Float32Array();
    dstWidth = (srcSamples.length * k) >> 0;
    srcWidth = srcSamples.length;
    for (dstX=0; dstX<dstWidth; dstX++)
    {
        srcX = ((dstX / dstWidth) * srcWidth) >> 0;
        srcY = srcSamples[srcX];
        dstSamples[dstX] = srcY;
    }
//  alert("Source samples (" + c4Hz + 'hz): ' + srcSamples.length + ''n'
//       +"Dest samples (" + d4Hz + 'hz): ' + dstSamples.length);

    tmpBuffer = tmpContext.createBuffer(1, dstWidth, 44100);
    var datBuf = tmpBuffer.getChannelData(0);
    var inBuf = dstSamples;
    var i, n = dstWidth;
//  datBuf = inBuf;
    for (i=0; i<n; i++)
        datBuf[i] = inBuf[i];
    var node = tmpContext.createBufferSource();
    node.buffer = tmpBuffer;
    var volume = 100;
    node.gain.value = 0.5 * volume/100.0;
    node.connect(tmpContext.destination);
    var startTime=tmpContext.currentTime;//+0.100;
    node.noteOn(startTime + 0.30);
}

var patterns =
        // all patterns use the organ track
        [
            //      0,          0,      5,      6,      6,          2,          2,          1,          1,          6,      6,          2,          2,          1,      1
            [0,1,2,3], [0,1,2,3], [1,2,3,4], [1,2,3,5], [1,2,3,5], [1,2,3,6], [1,2,3,6], [1,2,3,7], [1,2,3,7],  [1,2,3,5], [1,2,3,5], [1,2,3,6], [1,2,3,6], [1,2,3,7], [1,2,3,7],
            //      6
            [1,2,3,5], [1,2,3,4]
        ]
    // 0,0,5,6,6,2,2,1,1,6,6,2,2,1,1,6,5,3,
var tracks = 
        [
                // 1 - organ track
                [ 
                    [31,0x82],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],
                    [ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[31,0x82],[ 0,0x00],[ 0,0x00],[ 0,0x00],
                    [ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],
                    [31,0x82],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],
                    [29,0x82],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],
                    [ 0,0x00],[ 0,0x00],[ 0,0x00],[29,0x82],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],
                    [ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],
                    [29,0x82],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00],[ 0,0x00]
                ],

                // 2 - bass drum
                [ 
                    [38,1],[0,0],[0,0],[0,0],[36,1],[0,0],[38,1],[0,0],
                    [0,0],[0,0],[36,1],[0,0],[38,1],[0,0],[41,1],[0,0],
                    [0,0],[0,0],[41,1],[0,0],[0,0],[0,0],[41,1],[0,0],
                    [40,1],[0,0],[38,1],[0,0],[36,1],[0,0],[38,1],[0,0],
                    [38,1],[0,0],[0,0],[0,0],[36,1],[0,0],[38,1],[0,0],
                    [0,0],[0,0],[36,1],[0,0],[38,1],[0,0],[41,1],[0,0],
                    [0,0],[0,0],[41,1],[0,0],[0,0],[0,0],[41,1],[0,0],
                    [40,1],[0,0],[38,1],[0,0],[36,1],[0,0],[38,1],[0,0]
                ],
                // 3 - bastruma and basdrumb 
                [ 
                    [43,4],[0,0],[47,5],[0,0],[41,3],[0,0],[47,5],[0,0],
                    [43,4],[0,0],[47,5],[0,0],[41,3],[0,0],[47,5],[0,0],
                    [43,4],[0,0],[47,5],[0,0],[41,3],[0,0],[47,5],[0,0],
                    [43,4],[0,0],[47,5],[0,0],[41,3],[0,0],[47,5],[0,0],
                    [43,4],[0,0],[47,5],[0,0],[41,3],[0,0],[47,5],[0,0],
                    [43,4],[0,0],[47,5],[0,0],[41,3],[0,0],[47,5],[0,0],
                    [43,4],[0,0],[47,5],[0,0],[41,3],[0,0],[47,5],[0,0],
                    [43,4],[0,0],[47,5],[0,0],[41,3],[41,3],[41,3],[41,3]
                ],
                // 4 - guitar7
                [ 
                    [43,0x06],[0,0],[38,0x86],[0,0],[41,0x86],[0,0],[47,0x46],[0,0],
                    [43,0x46],[0,0],[38,0x46],[0,0],[41,0x46],[0,0],[47,0x46],[0,0],
                    [43,0x46],[0,0],[47,0x46],[0,0],[41,0x46],[0,0],[47,0x46],[0,0],
                    [41,0x06],[0,0],[41,0x46],[0,0],[40,0x46],[0,0],[40,0x46],[0,0],
                    [38,0x06],[0,0],[33,0x86],[0,0],[38,0x46],[0,0],[33,0x46],[0,0],
                    [38,0x46],[0,0],[33,0x46],[0,0],[38,0x46],[0,0],[33,0x46],[0,0],
                    [38,0x46],[0,0],[33,0x46],[0,0],[38,0x46],[0,0],[33,0x46],[0,0],
                    [38,0x26],[0,0],[33,0x26],[0,0],[38,0x26],[0,0],[33,0x26],[0,0]
                ],
                // 5 - guitar7
                [ 
                    [43,0x06],[0,0],[38,0x86],[0,0],[43,0x46],[0,0],[38,0x46],[0,0],
                    [43,0x46],[0,0],[38,0x46],[0,0],[43,0x46],[0,0],[38,0x46],[0,0],
                    [43,0x06],[0,0],[38,0x86],[0,0],[43,0x46],[0,0],[38,0x46],[0,0],
                    [41,0x06],[0,0],[41,0x86],[0,0],[41,0x46],[0,0],[41,0x46],[0,0],
                    [41,0x06],[0,0],[45,0x86],[0,0],[41,0x46],[0,0],[45,0x46],[0,0],
                    [41,0x46],[0,0],[45,0x46],[0,0],[41,0x46],[0,0],[45,0x46],[0,0],
                    [38,0x06],[0,0],[33,0x86],[0,0],[38,0x06],[0,0],[45,0x86],[0,0],
                    [38,0x46],[0,0],[45,0x46],[0,0],[38,0x06],[0,0],[45,0x46],[0,0]
                ],
                //
                // 6 - guitar7
                [ 
                    [38,0x06],[0,0],[33,0x86],[0,0],[36,0x06],[0,0],[38,0x06],[0,0],
                    [33,0x86],[0,0],[36,0x06],[0,0],[38,0x06],[0,0],[41,0x06],[0,0],
                    [36,0x86],[0,0],[41,0x06],[0,0],[36,0x86],[0,0],[41,0x06],[0,0],
                    [40,0x06],[0,0],[38,0x06],[0,0],[36,0x06],[0,0],[38,0x06],[0,0],
                    [38,0x06],[0,0],[33,0x86],[0,0],[36,0x06],[0,0],[38,0x06],[0,0],
                    [33,0x86],[0,0],[36,0x06],[0,0],[38,0x06],[0,0],[41,0x06],[0,0],
                    [36,0x86],[0,0],[41,0x06],[0,0],[36,0x86],[0,0],[41,0x06],[0,0],
                    [40,0x06],[0,0],[38,0x06],[0,0],[36,0x06],[0,0],[38,0x06],[0,0]
                ],
                //
                // 6 - guitar7
                [ 
                    [43,0x06],[0,0],[43,0x86],[0,0],[38,0x46],[0,0],[43,0x46],[0,0],
                    [43,0x06],[0,0],[43,0x86],[0,0],[43,0x06],[0,0],[38,0x06],[0,0],
                    [43,0x86],[0,0],[38,0x46],[0,0],[43,0x46],[0,0],[38,0x06],[0,0],
                    [41,0x06],[0,0],[43,0x06],[0,0],[43,0x86],[0,0],[41,0x06],[0,0],
                    [41,0x86],[0,0],[45,0x46],[0,0],[41,0x46],[0,0],[41,0x06],[0,0],
                    [40,0x06],[0,0],[38,0x06],[0,0],[43,0x46],[0,0],[41,0x06],[0,0],
                    [41,0x86],[0,0],[45,0x46],[0,0],[41,0x46],[0,0],[45,0x46],[0,0],
                    [41,0x46],[0,0],[45,0x26],[0,0],[41,0x26],[0,0],[45,0x26],[0,0]
                ]
                //
        ];
var rowTime = 0.12;

function playSong()
{
    var numTracks = tracks.length;
    var numRows = tracks[0].length;
    var curRow, curTrack, curNote;
    var startTime = tmpContext.currentTime + 1.0;
    var newSamples;
    for (curTrack=0; curTrack<numTracks; curTrack++)
    {
        for (curRow=0; curRow<numRows; curRow++)
        {
            curNote = tracks[curTrack][curRow];
            if (curNote[0] != 0)
            {
                newSamples = new Float32Array();
                newSamples = reSample( instruments[curNote[1]-1].mBuffer.getChannelData(0), 36, curNote[0]);
                playSamples(newSamples, curRow * rowTime + startTime);
            }
        }
    }
    alert('numTracks: ' + numTracks + ' - numRows: ' + numRows);
}

//patterns
function playSong2()
{
    var nPatterns = patterns.length;
    var curPattern, patternIndex, nTracks, nRows, songRow, startTime, newSamples;
    var rowTime = 0.12;
    var startTime = tmpContext.currentTime + 1.0;
    var curVol, curInstr;
    for (patternIndex=0; patternIndex<nPatterns; patternIndex++)
    {
        curPattern = patterns[patternIndex];
        nTracks = curPattern.length;
        songRow = patternIndex * 64;
        console.log(curPattern);
        for (trackIndex=0; trackIndex<nTracks; trackIndex++)
        {
            if (curPattern[trackIndex] != 0)
            {
                curTrack = tracks[ curPattern[trackIndex] - 1 ];
                nRows = curTrack.length;
                for (rowIndex=0; rowIndex<nRows; rowIndex++)
                {
                    curNote = curTrack[rowIndex];
                    if (curNote[0] != 0)
                    {
    //                  var nt = newTxt('play note');
    //                  document.body.appendChild(nt);
                        curVol = curNote[1] >> 4;
                        curInstr = (curNote[1] & 0xF) - 1;
                        newSamples = new Float32Array();
                        newSamples = reSample( instruments[curInstr].mBuffer.getChannelData(0), 36, curNote[0]);
                        if (curVol == 0)
                            playSamples(newSamples, ((songRow+rowIndex) * rowTime) + startTime);
                        else
                            playSamples(newSamples, ((songRow+rowIndex) * rowTime) + startTime, (curVol * 100) / 0x0f );
                    }
                }
            }
        }
    }
}
// volume is optional, range is 0..100. If not specified, 100 is used;
function playSamples(floatArray, startTime, volume)
{
    var tmpBuffer = tmpContext.createBuffer(1, floatArray.length, 44100);
    var datBuf = tmpBuffer.getChannelData(0);
    var inBuf = floatArray;
    var i, n = inBuf.length;
//  datBuf = inBuf;
    for (i=0; i<n; i++)
        datBuf[i] = inBuf[i];
    var node = tmpContext.createBufferSource();
    node.buffer = tmpBuffer;
    if (volume === undefined)
        var volume = 100;
    node.gain.value = 0.5 * volume/100.0;
    node.connect(tmpContext.destination);
//  var startTime=tmpContext.currentTime;//+0.100;
    node.noteOn(startTime);
}
function reSample(srcArray, origNote, newNote)
{
    var k = getFreq(origNote) / getFreq(newNote);
    var srcWidth = srcArray.length;
    var dstWidth = (srcWidth * k) >> 0;
    var newSamples = new Float32Array(dstWidth);
    var dstX, srcX, srcY;
    for (dstX=0; dstX<dstWidth; dstX++)
    {
        srcX = ((dstX / dstWidth) * srcWidth) >> 0;
        srcY = srcArray[srcX];
        newSamples[dstX] = srcY;
    }
    return newSamples;
}
/* ---------------------------------------------------------------------------------------------- */
function rawSound(sndSampleUrl, canvas)
{
    this.mContext = new webkitAudioContext();
    this.request = new XMLHttpRequest();
    this.request.open('GET', sndSampleUrl, true);
    this.request.responseType = 'arraybuffer';
    this.mBuffer = [];
    var canvas = newEl('canvas'); //byId('output');
    canvas.width = 500;
    canvas.height = 100;
    canvas.sampledSound = this;
    document.body.appendChild(canvas);
    canvas.onclick = function(){ this.sampledSound.play(); };
    // Decode asynchronously
    var me = this;
    this.request.onload = 
    function(e)
    {
        me.mBuffer = new Int16Array(this.response);
        tmpBuffer = new Int16Array(this.response);
        me.convertedBuffer = [];
        var i, n = tmpBuffer.length;
        for (i=0; i<n; i++)
        {
            me.convertedBuffer[i] = tmpBuffer[i] / 32768;
        }
        me.mBuffer = me.mContext.createBuffer(1, n, 44100);
    //  var msg = newTxt('Retrieved ' + sndSampleUrl + '(' + me.request.response.byteLength + ' bytes)');
    //  document.body.appendChild(msg);
    //  document.body.appendChild(newEl('br'));
    //  var msg = newTxt('Samples: ' + tmpBuffer.length + ', Secs: ' + ( (((tmpBuffer.length/44100)*1000)>>0)/1000));
    //  document.body.appendChild(msg);
        drawFloatArray(me.convertedBuffer, canvas);
        //me.mContext.decodeAudioData(me.request.response, function(buffer) {me.mBuffer = buffer;me.drawSound(canvas);}, onErrorFn);
//      alert('Retrieved ' + sndSampleUrl + '(' + me.request.response.byteLength + ' bytes)' );
    }
    this.request.send();
}
rawSound.prototype.play = function()
{
    var dataBuffer = this.mBuffer.getChannelData(0);
    var soundBuffer = this.convertedBuffer;
    var i, n = soundBuffer.length;
    for (i=0; i<n; i++)
        dataBuffer[i] = soundBuffer[i];
    var node = this.mContext.createBufferSource();
    node.buffer = this.mBuffer;
    node.gain.value = 0.5 * this.mVolume/100.0;
    node.connect(this.mContext.destination);
    node.noteOn(0);
}

function drawFloatArray(samples, canvas)
{
    var i, n = samples.length;
    var dur = (n / 44100 * 1000)>>0;
    canvas.title = 'Duration: ' +  dur / 1000.0 + 's';
    var width=canvas.width,height=canvas.height;
    var ctx = canvas.getContext('2d');
    ctx.strokeStyle = 'yellow';
    ctx.fillStyle = '#303030';
    ctx.fillRect(0,0,width,height);
    ctx.moveTo(0,height/2);
    ctx.beginPath();
    for (i=0; i<n; i++)
    {
        x = (i*width) / n;
        y = (samples[i]*height/2)+height/2;
        ctx.lineTo(x, y);
    }
    ctx.stroke();
    ctx.closePath();
}
function sampledSound(sndSampleUrl, canvas)
{
  this.request = new XMLHttpRequest();
  this.request.open('GET', sndSampleUrl, true);
  this.request.responseType = 'arraybuffer';
  this.mBuffer = [];
  this.mContext = new webkitAudioContext();
  this.loaded = false;
  var canvas = newEl('canvas'); //byId('output');
  canvas.width = 500;
  canvas.height = 100;
  canvas.sampledSound = this;
  this.canvas = canvas;
  document.body.appendChild(canvas);
  canvas.onclick = function(){ this.sampledSound.play(); };
  // Decode asynchronously
  var me = this;
  this.request.onload = function(){me.mContext.decodeAudioData(me.request.response, function(buffer) {me.mBuffer = buffer;me.drawSound(canvas);me.loaded=true;}, onErrorFn);}
  this.request.send();
}
sampledSound.prototype.play = function()
{
    var source = this.mContext.createBufferSource();
    source.buffer = this.mBuffer; //bufferList[soundIndex];
    source.connect(this.mContext.destination);
    source.noteOn(0);
}
sampledSound.prototype.drawSound = function(canvas)
{
//  var msg = 'Canvas size: ' + canvas.width + 'x' + canvas.height + 'px';
//  msg += "'n - " + this.mBuffer.duration + ' seconds';
//  alert(msg);
    var dur = (this.mBuffer.duration * 1000)>>0;
    canvas.title = 'Duration: ' +  dur / 1000.0 + 's';
    canvas.width = (dur/1000 * 512)>>0;
    canvas.style.width = (dur/1000 * 512)>>0 + 'px';

    var width=canvas.width, height=canvas.height;
    var x,y, i, n = this.mBuffer.length;
    var ctx = canvas.getContext('2d');
    var samples = this.mBuffer.getChannelData(0);
    ctx.strokeStyle = 'yellow';
    ctx.fillStyle = '#303030';
    ctx.fillRect(0,0,width,height);
    ctx.moveTo(0,height/2);
    ctx.beginPath();
    for (i=0; i<n; i++)
    {
        x = (i*width)/n;
        y = (samples[i]*height/2)+height/2;
        ctx.lineTo(x, y);
    }
    ctx.stroke();
    ctx.closePath();
}
function onErrorFn()
{
    alert('f#@ker');
}
</script>
<style>
    canvas
    {
/*      width: 250px; */
        height: 100px;
        padding: 4px;
    }
</style>
</head>
<body>
    <button onclick='playSong2();'>playSong</button>
</body>
</html>