2015-04-04 91 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