我在MainStage 3中使用Scripter MidiFX(与LogicPro X相同)使用javascript创建自定义琶音器,因为我需要更多控制,因此使用GetTimingInfo()获取当前节拍是合乎逻辑的正如我在他们的例子中看到的那样,ProcessMIDI()函数触发MIDI音符。不幸的是,这甚至在我的Core i7 MacBook Pro上都占用了CPU,我在实际演出时使用的是带有Core 2 Duo处理器的MacMini。
我能够编写自己的代码来使用新的Date()来计算当前的节拍,然后只使用GetTimingInfo()来获取当按下新音符时的当前节拍,但即使这样也不能保持我喜欢的CPU。
当我不包括" NeedsTimingInfo = true"并且只是硬编码速度一切都很好,但这是很多额外的代码,使用内置函数更有意义。
这是一个简单的音序器示例导致此问题...我做错了什么?即使我使用计数器仅在每第16次调用时运行ProcessMIDI(),也会发生这种情况!
NeedsTimingInfo = true;
var startBeat = -1;
var startPitch = 0;
var lastBeat = -1;
var currentStep = 0;
// melody test
var steps = [
0, 0, 0, 0, 0, 0, 0, 2,
0, 0, 0, 0, 0, 0, 2, 5
];
function HandleMIDI(e) {
if (e instanceof NoteOn) {
if (startBeat > 0) return;
currentStep = 0;
startPitch = e.pitch;
var info = GetTimingInfo();
lastBeat = startBeat = info.blockStartBeat;
doNote(e.pitch);
}
else if (e instanceof NoteOff) {
if (e.pitch == startPitch) {
startBeat = -1;
}
}
else {
e.send();
}
}
function doNote(pitch) {
var adjustment = 0;
if (currentStep < steps.length) {
adjustment = steps[currentStep];
}
var p = pitch + adjustment;
var on = new NoteOn;
on.pitch = p;
on.send();
var off = new NoteOff;
off.pitch = p;
off.sendAfterBeats(0.9);
}
function ProcessMIDI() {
var info = GetTimingInfo();
if (!info.playing) return;
if (startBeat < 0) return;
var beat = info.blockStartBeat;
if (beat - lastBeat >= 1) {
currentStep++;
doNote(startPitch);
lastBeat = beat;
}
}
答案 0 :(得分:0)
您在首选项&gt;音频&gt;高级设置中设置的I / O缓冲区大小是多少?缓冲区大小越小,所需的CPU就越多。我假设您使用MainStage进行实时使用,因此您的设置非常低,可以最大限度地减少延迟。
我尝试使用缓冲区大小为16运行代码,并且MS结束并最大化CPU。 64处理得更好(CPU仪表飙升,但没有任何打嗝播放)。在2009款MacBook Pro 3.06 Core 2 Duo上测试过。
为了让Scripter顺利运行,您可能需要更多延迟。你的代码本身就很可靠。
答案 1 :(得分:0)
MainStage 3.0.3问题随之消失,我可以使用TimeMachine找到它。
我确实创建了一个自定义的Javascript实现,它的时间为3.0.4,这确实有所帮助,但是额外的100行代码(下面)。如果其他人遇到这个问题,我会建议降级。
/**---[lib/TimingInfo.js]---*/
/**
* Constructor accepts the tempo for beat syncing and starts the clock
* to the current time.
*
* @param tempo the tempo of the song (default: 120bpm)
*/
function TimingInfo(tempo) {
this.schedule = [];
this.setTempo(tempo);
this.reset();
}
/**
* Sets the tempo and computes all times associated, assuming a 4/4
* beat structure.
*
* @param tempo the current tempo in beats per minute.
*/
TimingInfo.prototype.setTempo = function(tempo) {
this.tempo = tempo || 120;
this.msecPerBeat = (60 / this.tempo) * 1000;
};
/**
* Resets the beatsync to be relative to the current time.
*/
TimingInfo.prototype.reset = function() {
this.startTime = new Date().getTime();
this.update();
// trigger all scheduled messages immediately. TODO: note off only?
this._sendScheduled(null);
};
/**
* Uses the current time to update what the current beat is and all
* related properties. Any scheduled actions are performed if their
* time has passed.
*/
TimingInfo.prototype.update = function() {
var now = new Date().getTime();
this.elapsedMsec = now - this.startTime;
this.beat = this.elapsedMsec / this.msecPerBeat;
this._sendScheduled(this.beat);
};
/**
* Schedules a midi message to be sent at a specific beat.
* @param e MIDI event to schedule
* @param beat the beat number to send it on
*/
TimingInfo.prototype.sendAtBeat = function(e, beat) {
if (e == null) return;
// insert in-order into schedule
var insertAt = 0;
for (var i = 0; i < this.schedule.length; i++) {
if (this.schedule[i].beat > beat) {
insertAt = i;
break;
}
}
this.schedule.splice(insertAt, 0, {e:e, beat:beat});
};
/**
* Schedules a midi message relative to current beat.
*/
TimingInfo.prototype.sendAfterBeats = function(e, deltaBeats) {
this.sendAtBeat(e, this.beat + deltaBeats);
};
/**
* Sends all messages scheduled on or before a given beat. If not
* supplied all scheduled items are sent.
*
* @param atBeat beat to compare all scheduled events against (default: all)
*/
TimingInfo.prototype._sendScheduled = function(atBeat) {
// send all items on or before the given beat
var sent = 0;
for (var i = 0; i < this.schedule.length; i++) {
if (!atBeat || this.schedule[i].beat <= atBeat) {
this.schedule[i].e.send();
sent++;
}
else {
break;
}
}
// remove sent items
this.schedule.splice(0, sent);
};
var _timing = null;
/**
* Replacement for GetTimingInfo() that calls update() to handling
* any scheduled actions.
*/
function GetNewTimingInfo() {
if (_timing == null) {
_timing = new TimingInfo();
}
_timing.update();
return _timing;
}