2015-04-04 64 views
1

我有以下问题: 我试图用javascipt等实现音乐应用程序。 我已经剖析了引擎和UI中的模块体系结构。我的问题在于引擎模块。 基本上我有一个主引擎模块停止多个setTimeout实例

var NoteEngine = (function(){ 
    var that = {}, 
     matrices = [], 
     beatCount = 1, 
     globalBPM = 100, 

    init = function(count){ 
     window.AudioContext = window.AudioContext || window.webkitAudioContext; 
     context = new AudioContext(); 

     _registerListener(); 

     beatCount = count; 
     matrices = [ 
      new NoteMatrix("piano", (16 * beatCount), globalBPM), 
      new NoteMatrix("guitar", (16 * beatCount), globalBPM), 
      new NoteMatrix("bass", (16 * beatCount), globalBPM), 
      new NoteMatrix("bell", (16 * beatCount), globalBPM) 
     ]; 
    }, 

    _registerListener = function(){ 

    }; 

    that.init = init; 
    return that; 
})(); 

一类以加载的声音和创建的所有行

function NoteMatrix(instrument, colCount, bpm){ 

    var rows = [], 
     matrixInstrument = instrument, 
     bufferLoader, 
     bufferList; 

    _loadBuffer(); 

    function _loadBuffer(){ 
     var notePaths = _createNoteFilePaths(); 

     bufferLoader = new BufferLoader(
      context, 
      notePaths, 
      _finishedLoading); 
     bufferLoader.load(); 
    } 

    function _createNoteFilePaths(){ 
     var basePath = "res/notes/" + matrixInstrument + "/", 
      scale = ['C6', 'A5', 'G5', 'E5', 'D5', 'C5', 'A4', 'G4', 'E4', 'D4', 'C4', 'A3', 'G3', 'E3', 'D3', 'C3'], 
      result = []; 
     for(var i = 0; i < 16; i++){ 
      result[i] = basePath + scale[i] + ".mp3"; 
     } 
     return result; 
    } 

    function _finishedLoading(buffer){ 
     $("body").trigger("MODULE_FINISHED"); 
     bufferList = buffer; 
     _createMatrix(); 
    } 

    function _createMatrix(){ 
     for(var i = 0; i < 16; i++){ 
      rows[i] = new NoteRow(matrixInstrument, colCount, bpm, i, (i*colCount), (((i+1)*colCount) - 1), bufferList[i]); 
     } 
    } 
} 

和另一亚类中,以管理每个仪器的单排

function NoteRow(instrument, loopLength, bpm, row, minID, maxID, buffer){ 

    var noteBuffer = buffer,   // Notenklang in Bufferform 
     gainNode = null,    // Hauptknoten für Ausgabe (auch lautstärke) 
     volume,       // Gesamtlautstärke 
     notes = [],      // Enthält alle Notenzustände in der Schleife (taktübergreifend) 
     rowInstrument = instrument,  // Instrumentname in Stringform (für Abgleiche) 
     timeoutID = null,    // Zuständig für Wiederholung/Stop der Schleife 
     isPlaying = false,    // Status ob Schleife spielt oder nicht 
     current16thNote = 0,   // Aktuelle Position in der Schleife 
     rowBPM = bpm,     // Tempo der Schleife 
     scheduleDelay = 0,    // Verzögerung der Wiederholung der Planschleife (in ms) 
     scheduleAheadTime = 0.1,  // Abdeckung der Planschleife (in s) 
     nextNoteTime = 0.0;    // Startzeit der nächsten Note 

    _init(); 
    _registerListener(); 

    // Initialisiert die Notenreihe 
    function _init(){ 
     gainNode = context.createGain(); 
     volume = 2.5; 
     gainNode.gain.value = volume; 
     for(var i = 0; i < loopLength; i++){ 
      notes[i] = false; 
     } 
    } 

    // Registriert alle Listener für die Notenreihe 
    function _registerListener(){ 
     $("body").on("CELL_CLICKED", _toggleNote); 
     $("body").on("PLAY", _play); 
     $("body").on("STOP", _stop); 
     $("body").on("VOLUME_CHANGE", _changeVolume); 
     $("body").on("BPM_CHANGE", _changeBPM); 
     $("body").on("MUTE", _mute); 
     $("body").on("RESUME_SOUND", _resumeSound); 
     $("body").on("REFRESH_ALL", _refresh); 
    } 

    // Schaltet eine Note um 
    function _toggleNote(event, data){ 
     if(data.instrument == rowInstrument && (data.id >= minID && data.id <= maxID)){ 
      console.log(data); 
      notes[data.id - minID] = !notes[data.id - minID]; 
     } 
    } 

    function _play(){ 
     current16thNote = 0; 
     nextNoteTime = context.currentTime; 
     _startScheduler(); 
    } 

    function _stop(){ 
     clearTimeout(timeoutId); 
    } 

    function _handlePlayback(){ 
     isPlaying = !isPlaying; 

     if(isPlaying) { 
      current16thNote = 0; 
      nextNoteTime = context.currentTime; 
      _startScheduler(); 
     }else{ 
      clearTimeout(timeoutId); 
     } 
    } 

    // Schaltet die Notenreihe stumm 
    function _mute(){ 
     gainNode.gain.value = 0; 
    } 

    // Stellt die ursprüngliche Lautstärke der Notenreihe wieder her 
    function _resumeSound(){ 
     gainNode.gain.value = volume; 
    } 

    // Setzt die Notenreihe zurück 
    function _refresh(){ 
     for(var i = 0; i < notes.length; i++){ 
      notes[i] = false; 
     } 
    } 

    // Ändert die Lautstärke der Notenreihe 
    function _changeVolume(event, data){ 
     volume = data/20; 
     gainNode.gain.value = volume; 
    } 

    // Ändert das Tempo der Notenreihe 
    function _changeBPM(event, data){ 
     rowBPM = data; 
    } 

    // Startet die Playback Schleife, die immer wieder abprüft, 
    // ob im vorgelegten Zeitraum eine Note abgespielt werden soll 
    function _startScheduler(){ 
     while (nextNoteTime < context.currentTime + scheduleAheadTime) { 
      _scheduleNote(current16thNote, nextNoteTime); 
      _nextNote(); 
     } 
     timeoutId = setTimeout(_startScheduler, scheduleDelay); 
    } 

    // Spielt die Note und aktiviert die entsprechende Animation 
    function _scheduleNote(beatPosition, time){ 
     if(notes[beatPosition]){ 
      var voice = context.createBufferSource(); 
      voice.buffer = noteBuffer; 
      voice.connect(gainNode); 
      gainNode.connect(context.destination); 
      voice.start(time); 

      $("#" + (minID + beatPosition)).addClass("animation"); 
      setTimeout(function(){ 
       $("#" + (minID + beatPosition)).removeClass("animation"); 
      }, 100); 
     } 
    } 

    // Verschiebt die Position der Schleife nach vorne 
    // Abhängig vom Tempo legt es auch das Interval zur nächsten Note fest 
    function _nextNote(){ 
     var secondsPerBeat = 60.0/rowBPM; 
     nextNoteTime += 0.25 * secondsPerBeat; 

     current16thNote++; 
     if (current16thNote == loopLength) { 
      current16thNote = 0; 
     } 
    } 
} 

我的问题在于NoteRows。您可能会看到来自NoteRow类的对象使用特定笔记管理特定乐器中的整行。一切正常,除非我无法用clearTimeout停止播放循环。有什么建议? (可能不会改变整个架构)

+1

我们能看到整个动物的某个地方吗? – Flint 2015-04-04 19:53:12

+0

我不认为这很重要,因为在这个问题上,用户界面和引擎不依赖于彼此。在http://132.199.139.24/~krm22840/Note16/index.html – sixeco 2015-04-04 20:28:19

+0

有一个较旧的版本(不幸的是,有任何音乐功能)让我quess,莫? ; P – Igle 2015-04-04 20:45:57

回答

1

将所有超时功能添加到数组中。

当你想阻止他们,只是做这样的:

function stopTrackedTimeouts() 

{ 
    for(var i=0; i<timeouts.length; i++) 
    { 
     clearTimeout(timeouts[i]); 
    } 
    timeouts = []; 
} 

如果你不关心你开始的那些旁边运行的其他超时,您可以通过获取的该标识清除所有超时通过添加空超时最近的超时。

function stopAllTimeouts() 
{ 
    var id = window.setTimeout(null,0); 
    while (id--) 
    { 
     window.clearTimeout(id); 
    } 
} 
+0

非常感谢你,那个工作很漂亮^^ – sixeco 2015-04-04 22:32:38

+0

Bitteschön;)Bitte zwecks der Punkte einem alten Medieninformatiker die Antwort noch als richtig akzeptieren;) – Igle 2015-04-04 22:33:50