aiexperiments-ai-duet/static/app/ai/AI.js
2016-11-11 13:52:19 -05:00

108 lines
2.9 KiB
JavaScript

/**
* Copyright 2016 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {Midi} from 'MidiConvert/src/Midi'
import Tone from 'Tone/core/Tone'
import MidiConvert from 'MidiConvert/src/MidiConvert'
import events from 'events'
window.generator = 'pop'
class AI extends events.EventEmitter{
constructor(){
super()
this._newTrack()
this._sendTimeout = -1
this._heldNotes = {}
this._lastPhrase = -1
/*setInterval(() => {
//wait a max of 10 seconds before sending an event
if (Date.now() - this._phraseStart > 5000){
for (let note in this._heldNotes){
this._track.noteOff(note, Tone.now())
delete this._heldNotes[note]
}
this.send()
}
}, 200)*/
this._aiEndTime = 0
}
_newTrack(){
this._midi = new Midi()
this._track = this._midi.track()
}
send(){
//trim the track to the first note
if (this._track.length){
let request = this._midi.slice(this._midi.startTime)
this._newTrack()
let endTime = request.duration
//shorten the request if it's too long
if (endTime > 10){
request = request.slice(request.duration - 15)
endTime = request.duration
}
let additional = endTime
additional = Math.min(additional, 8)
additional = Math.max(additional, 1)
request.load(`/predict?duration=${endTime + additional}&generator=${generator}`, JSON.stringify(request.toArray()), 'POST').then((response) => {
response.slice(endTime / 2).tracks[1].notes.forEach((note) => {
const now = Tone.now()
if (note.noteOn + now > this._aiEndTime){
this._aiEndTime = note.noteOn + now
this.emit('keyDown', note.midi, note.noteOn + now)
note.duration = note.duration * 0.9
this.emit('keyUp', note.midi, note.noteOff + now)
}
})
})
this._lastPhrase = -1
}
}
keyDown(note){
if (this._track.length === 0 && this._lastPhrase === -1){
this._lastPhrase = Date.now()
}
this._track.noteOn(note, Tone.now())
clearTimeout(this._sendTimeout)
this._heldNotes[note] = true
}
keyUp(note){
this._track.noteOff(note, Tone.now())
delete this._heldNotes[note]
// send something if there are no events for a moment
if (Object.keys(this._heldNotes).length === 0){
if (this._lastPhrase !== -1 && Date.now() - this._lastPhrase > 5000){
//do it immediately
this.send()
} else {
this._sendTimeout = setTimeout(this.send.bind(this), 600)
}
}
}
}
export {AI}