Compare commits

...

9 Commits

Author SHA1 Message Date
harmse
31098054e6 fix typos and formatting on splash page 2018-10-26 11:24:35 -04:00
harmse
5391f3f028 update midi keyboard to fix octave issue 2018-10-24 10:43:49 -04:00
harmse
cb63c392ae removing about page, privacy and terms, and external links 2018-10-23 12:02:06 -04:00
harmse
cb21cce287 add about page back, but without video and with more text 2018-09-28 16:04:17 -04:00
harmse
49324d2dc5 update style of splash page 2018-09-28 13:35:52 -04:00
harmse
25c26cda56 switch german/english on splash page 2018-09-28 13:33:56 -04:00
harmse
0afc8f69f6 update so that keyboard and midi both trigger 2018-08-08 14:06:27 -04:00
harmse
896d778dee update loader 2018-08-08 13:16:29 -04:00
harmse
0033ff4a5c updates for heinz-nixdorf installation 2018-08-06 17:43:00 -04:00
10 changed files with 289 additions and 138 deletions

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 292.7 119.8" style="enable-background:new 0 0 292.7 119.8;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FBBC05;}
</style>
<g>
<polyline class="st0" points="131,92 131,65.9 124.7,65.9 124.7,30.4 110.2,30.4 110.2,92 "/>
<polyline class="st0" points="155.9,92 155.9,65.9 149.7,65.9 149.7,30.4 141.4,30.4 141.4,65.9 135.1,65.9 135.1,92 "/>
<polyline class="st0" points="255.8,92 255.8,65.9 249.6,65.9 249.6,30.4 241.3,30.4 241.3,65.9 235,65.9 235,92 "/>
<polyline class="st0" points="180.9,92 180.9,65.9 180.9,30.4 174.6,30.4 166.3,30.4 166.3,65.9 160.1,65.9 160.1,92 "/>
<polyline class="st0" points="205.9,92 205.9,65.9 199.6,65.9 199.6,30.4 185.1,30.4 185.1,92 "/>
<polyline class="st0" points="230.8,92 230.8,65.9 224.6,65.9 224.6,30.4 216.3,30.4 216.3,65.9 210,65.9 210,92 "/>
<polyline class="st0" points="280.8,92 280.8,65.9 280.8,30.4 274.5,30.4 266.2,30.4 266.2,65.9 260,65.9 260,92 "/>
<polyline class="st0" points="81.1,92 81.1,65.9 74.9,65.9 74.9,30.4 66.6,30.4 66.6,65.9 60.3,65.9 60.3,92 "/>
<polyline class="st0" points="31.2,92 31.2,65.9 24.9,65.9 24.9,30.4 10.4,30.4 10.4,92 "/>
<polyline class="st0" points="56.1,92 56.1,65.9 49.9,65.9 49.9,30.4 41.6,30.4 41.6,65.9 35.3,65.9 35.3,92 "/>
<polyline class="st0" points="106.1,92 106.1,65.9 106.1,30.4 99.8,30.4 91.5,30.4 91.5,65.9 85.3,65.9 85.3,92 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -23,6 +23,7 @@
"events": "^1.1.0",
"exports-loader": "^0.6.3",
"file-loader": "^0.9.0",
"idle-timeout": "^1.0.0",
"jsmidgen": "^0.1.5",
"midi-file-parser": "^1.0.0",
"midiconvert": "0.4.1",

View File

@ -22,33 +22,49 @@ import {Splash} from 'interface/Splash'
import {About} from 'interface/About'
import {Tutorial} from 'ai/Tutorial'
import 'babel-polyfill'
import IdleTimeout from 'idle-timeout'
/////////////// SPLASH ///////////////////
const about = new About(document.body)
/////////////// SPLASH ///////////////////
// const about = new About(document.body)
const splash = new Splash(document.body)
splash.on('click', () => {
keyboard.activate()
tutorial.start()
about.showButton()
})
splash.on('about', () => {
about.open(true)
})
about.on('close', () => {
if (!splash.loaded || splash.isOpen()){
splash.show()
} else {
keyboard.activate()
}
})
about.on('open', () => {
keyboard.deactivate()
if (splash.isOpen()){
splash.hide()
}
// about.showButton()
})
// splash.on('about', () => {
// about.open(true)
// })
// about.on('close', () => {
// if (!splash.loaded || splash.isOpen()){
// splash.show()
// keyboard._active = true
// } else {
//
// keyboard.activate()
// }
// })
// about.on('open', () => {
// keyboard.deactivate()
// if (splash.isOpen()){
// splash.hide()
// }
// })
//////////////// IDLE TIMER ///////////////
const idleTimeout = new IdleTimeout(
() => {
keyboard.deactivate();
// about.close();
splash.show();
keyboard._active = true;
},
{
element: document,
timeout: 60000,
loop: false
}
);
/////////////// PIANO ///////////////////
@ -63,6 +79,7 @@ const sound = new Sound()
sound.load()
keyboard.on('keyDown', (note) => {
idleTimeout.reset()
sound.keyDown(note)
ai.keyDown(note)
glow.user()
@ -112,4 +129,4 @@ tutorial.on('aiKeyDown', (note, time) => {
tutorial.on('aiKeyUp', (note, time) => {
ai.keyUp(note, time)
})
})

View File

@ -23,12 +23,28 @@ const tfLink = 'https://www.tensorflow.org/'
const toneLink = 'https://github.com/Tonejs/Tone.js'
const sourceCode = 'https://github.com/googlecreativelab/aiexperiments-ai-duet'
const blurbCopy = `Built by Yotam Mann with friends on the Magenta and Creative Lab teams at Google.
It uses <a target='_blank' href='${tfLink}'>TensorFlow</a>,
<a target='_blank' href='${toneLink}'>Tone.js</a> and tools
from the <a target='_blank' href='${magentaLink}'>Magenta project</a>.
The open-source code is <a target='_blank' href='${sourceCode}'>available here</a>.
Click the keyboard, use your computer keys, or even plug in a MIDI keyboard.`
const germanAboutCopy = `AI Duet nutzt maschinelles Lernen, um zu entscheiden,
wie es auf die Noten reagiert, die du spielst. Dafür wurde
das neuronale Netz mit einer Vielzahl an Melodien trainiert.
das neuronale Netz mit einer Vielzahl an Melodien trainiert.
Noten and Takten. Regeln dafür, wie Noten oder Akkorde
verarbeitet werden sollen, wurden dem System nicht gegeben.`
const englishAboutCopy = `AI Duet uses machine learning in order to decide on
how it responds to the notes you play. To do so,
a neural network was trained with lots of melodies.
Over time, the system learned about relationships
between notes and timing. No rules predefine how
notes or chords should be treated.`
const germanMadeByCopy = `Programmierung und Konzept: Yotam Mann und Googles
Creative Lab. Neuronales Netz: Googles Magenta project.
Der gesamte Quellcode ist Open Source: g.co/aiexperiments`
const englishMadeByCopy = `Programming and Concept: Yotam Mann and Googles
Creative Lab. Neural net: Googles Magenta project.
All the code is open source: g.co/aiexperiments`
export class About extends events.EventEmitter{
constructor(container){
@ -59,13 +75,13 @@ export class About extends events.EventEmitter{
const title = document.createElement('div')
title.id = 'title'
title.textContent = 'A.I. Duet'
// content.appendChild(title)
content.appendChild(title)
const video = document.createElement('div')
video.id = 'video'
//vid YT0k99hCY5I
//vid YT0k99hCY5I
video.innerHTML = `<iframe id='youtube-iframe' src="https://www.youtube.com/embed/0ZE1bfPtvZo?modestbranding=0&showinfo=0&enablejsapi=1" frameborder="0" allowfullscreen></iframe>`
content.appendChild(video)
// content.appendChild(video)
this._ytplayer = null
@ -84,21 +100,38 @@ export class About extends events.EventEmitter{
})
})
const blurb = document.createElement('div')
blurb.id = 'blurb'
content.appendChild(blurb)
blurb.innerHTML = blurbCopy
const germanAbout = document.createElement('div')
germanAbout.id = 'germanAbout'
content.appendChild(germanAbout)
germanAbout.innerHTML = germanAboutCopy
const englishAbout = document.createElement('div')
englishAbout.id = 'englishAbout'
content.appendChild(englishAbout)
englishAbout.innerHTML = englishAboutCopy
const germanMadeBy = document.createElement('div')
germanMadeBy.id = 'germanMadeBy'
content.appendChild(germanMadeBy)
germanMadeBy.innerHTML = germanMadeByCopy
const englishMadeBy = document.createElement('div')
englishMadeBy.id = 'englishMadeBy'
content.appendChild(englishMadeBy)
englishMadeBy.innerHTML = englishMadeByCopy
}
close(){
this._toggleButton.classList.remove('close')
this._toggleButton.classList.add('open')
this._container.classList.remove('visible')
if (this._ytplayer && this._ytplayer.stopVideo){
this._ytplayer.stopVideo()
}
// if (this._ytplayer && this._ytplayer.stopVideo){
// this._ytplayer.stopVideo()
// }
this.emit('close')
if (window.ga){
ga('send', 'event', 'AI-Duet', 'Click', 'About - Close')
@ -108,25 +141,25 @@ export class About extends events.EventEmitter{
this._toggleButton.classList.add('close')
this._toggleButton.classList.remove('open')
this._playButton.classList.add('visible')
// this._playButton.classList.add('visible')
this._container.classList.add('visible')
this.emit('open')
if (window.ga){
ga('send', 'event', 'AI-Duet', 'Click', 'About - Open')
}
if (play){
this._playVideo()
}
// if (play){
// this._playVideo()
// }
}
// waits until the player is ready to play the video,
// otherwise goes back into waiting loop
_playVideo(retries=0){
if (this._ytplayer && this._ytplayer.playVideo){
this._ytplayer.playVideo()
} else if (retries < 10 && this.isOpen()){
setTimeout(() => this._playVideo(retries+1), 200);
}
}
// _playVideo(retries=0){
// if (this._ytplayer && this._ytplayer.playVideo){
// this._ytplayer.playVideo()
// } else if (retries < 10 && this.isOpen()){
// setTimeout(() => this._playVideo(retries+1), 200);
// }
// }
isOpen(){
return this._container.classList.contains('visible')
}

View File

@ -47,16 +47,9 @@ export default class Loader extends EventEmitter{
this.loaded = false
Buffer.on('load', () => {
this.loaded = true
fillText.innerHTML = '<div id="piano"></div> <div id="play">PLAY</div>'
loader.classList.add('clickable')
loader.addEventListener('click', () => {
this.emit('click')
})
loader.classList.add("loaded")
fillText.innerHTML = '<div id="piano">'
})
Buffer.on('progress', (prog) => {

View File

@ -38,9 +38,13 @@ class Splash extends events.EventEmitter{
titleContainer.appendChild(title)
const subTitle = document.createElement('div')
const germanSubTitle = document.createElement('div')
subTitle.id = 'subTitle'
germanSubTitle.id = 'germanSubTitle'
titleContainer.appendChild(germanSubTitle)
titleContainer.appendChild(subTitle)
subTitle.textContent = 'A piano that responds to you.'
germanSubTitle.textContent = ' Ein Klavier, das auf deine Eingaben antwortet.'
this._clicked = false
const loader = this._loader = new Loader(titleContainer)
@ -51,12 +55,21 @@ class Splash extends events.EventEmitter{
})
const howItWorks = document.createElement('div')
const germanHowItWorks = document.createElement('div')
howItWorks.id = 'howItWorks'
germanHowItWorks.id = 'germanHowItWorks'
titleContainer.appendChild(germanHowItWorks)
titleContainer.appendChild(howItWorks)
howItWorks.textContent = 'How it works'
howItWorks.addEventListener('click', () => {
this.emit('about')
})
howItWorks.innerHTML = 'This experiment lets you play a duet with a computer using machine learning.<br>Just play some notes and the computer will respond to your melody.<br>Over time, the system learns about the relationships<br>between notes and timing to play better duets.'
germanHowItWorks.innerHTML = 'Mithilfe von maschinellem Lernen kannst du bei diesem Projekt<br>mit dem Computer im Duett spielen. Wenn du eine Melodie anstimmst,<br>wird der Algorithmus auf diese Noten reagieren. Im Laufe der Zeit erlernt<br>das System Bezüge zwischen Noten und Takten und verbessert seine Ergebnisse.<br><br>'
// const aboutPageLink = document.createElement('div')
// aboutPageLink.id = 'aboutPageLink'
// titleContainer.appendChild(aboutPageLink)
// aboutPageLink.textContent = 'How it works'
// aboutPageLink.addEventListener('click', () => {
// this.emit('about')
// })
const badges = document.createElement('div')
badges.id = 'badges'
@ -64,7 +77,7 @@ class Splash extends events.EventEmitter{
const aiExperiments = document.createElement('a')
aiExperiments.id = 'aiExperiments'
aiExperiments.href = 'https://aiexperiments.withgoogle.com'
// aiExperiments.href = 'https://aiexperiments.withgoogle.com'
aiExperiments.target = '_blank'
aiExperiments.classList.add('badge')
badges.appendChild(aiExperiments)
@ -85,7 +98,7 @@ class Splash extends events.EventEmitter{
badges.appendChild(break1)
const magenta = document.createElement('a')
magenta.href = 'https://magenta.tensorflow.org/'
// magenta.href = 'https://magenta.tensorflow.org/'
magenta.target = '_blank'
magenta.id = 'magentaLink'
magenta.classList.add('badge')
@ -93,10 +106,11 @@ class Splash extends events.EventEmitter{
magenta.innerHTML = imgHtml + '<div id="text">Built using <span>Magenta</span></div>'
badges.appendChild(magenta)
const privacyAndTerms = document.createElement('div')
privacyAndTerms.id = 'privacyAndTerms'
privacyAndTerms.innerHTML = '<a target="_blank" href="https://www.google.com/intl/en/policies/privacy/">Privacy</a><span>&</span><a target="_blank" href="https://www.google.com/intl/en/policies/terms/">Terms</a>'
splash.appendChild(privacyAndTerms)
// const privacyAndTerms = document.createElement('div')
// privacyAndTerms.id = 'privacyAndTerms'
// // privacyAndTerms.innerHTML = '<a target="_blank" href="https://www.google.com/intl/en/policies/privacy/">Privacy</a><span>&</span><a target="_blank" href="https://www.google.com/intl/en/policies/terms/">Terms</a>'
// privacyAndTerms.innerHTML = '<a target="_blank">Privacy</a><span>&</span><a target="_blank">Terms</a>'
// splash.appendChild(privacyAndTerms)
}

View File

@ -28,7 +28,7 @@ class Keyboard extends events.EventEmitter{
this._container = container
this._active = false
this._active = true;
/**
* The audio key keyboard
@ -76,9 +76,9 @@ class Keyboard extends events.EventEmitter{
//the midi input
this._midi = new Midi()
this._midi.on('keyDown', (note) => {
this.keyDown(note)
this._emitKeyDown(note)
})
this.keyDown(note);
this._emitKeyDown(note);
});
this._midi.on('keyUp', (note) => {
this.keyUp(note)
this._emitKeyUp(note)
@ -111,6 +111,9 @@ class Keyboard extends events.EventEmitter{
if (!this._active){
return
}
const splash = document.getElementById("splash");
splash.classList.add('disappear');
container.classList.add('focus');
if (!this._currentKeys[note]){
this._currentKeys[note] = 0
}

View File

@ -48,14 +48,14 @@ class Midi extends events.EventEmitter{
})
inputDevice.addListener('noteon', 'all', (event) => {
try {
this.emit('keyDown', event.note.number)
this.emit('keyDown', event.note.number + 12)
} catch(e){
console.warn(e)
}
})
inputDevice.addListener('noteoff', 'all', (event) => {
try {
this.emit('keyUp', event.note.number)
this.emit('keyUp', event.note.number + 12)
} catch(e){
console.warn(e)
}

View File

@ -91,7 +91,7 @@
font-family: $font-family;
font-size: 40px;
line-height: 30px;
margin: 20px 0px 30px 0px;
margin: 130px 0px 50px 0px;
position: relative;
}
@ -143,17 +143,38 @@
}
}
#blurb {
#germanAbout {
position: relative;
text-transform: none;
margin-top: 50px;
font-size: 14px;
font-size: 18px;
line-height: 25px;
}
a {
color: $orange;
}
#englishAbout {
position: relative;
text-transform: none;
margin-top: 10px;
font-size: 18px;
line-height: 25px;
font-style: italic;
}
#germanMadeBy {
position: relative;
text-transform: none;
margin-top: 50px;
font-size: 18px;
line-height: 25px;
}
#englishMadeBy {
position: relative;
text-transform: none;
margin-top: 10px;
font-size: 18px;
line-height: 25px;
font-style: italic;
}
}

View File

@ -42,7 +42,7 @@ $topMargin: 35px;
font-weight: 300;
}
#subTitle, #howItWorks {
#germanSubTitle, #germanHowItWorks {
margin-top: $topMargin;
letter-spacing: 0.8px;
line-height: 30px;
@ -53,25 +53,66 @@ $topMargin: 35px;
text-align: center;
font-weight: 300;
}
#subTitle {
margin-top: 0px;
letter-spacing: 0.8px;
line-height: 30px;
font-size: 15px;
width: 100%;
margin-left: auto;
margin-right: auto;
text-align: center;
font-weight: 300;
font-style: italic;
}
#howItWorks {
#germanHowItWorks {
$size : 20px;
$margin: 30px;
color: $orange;
width: 100&;
display: inline-block;
text-align: center;
/*margin-left: $margin;*/
}
#howItWorks {
$size : 20px;
$margin: 0px;
color: $orange;
width: 100%;
display: inline-block;
/*margin-left: $margin;*/
letter-spacing: 0.8px;
line-height: 30px;
font-size: 15px;
/*margin-right: auto;*/
text-align: center;
font-weight: 300;
font-style: italic;
}
#aboutPageLink {
$size : 20px;
$margin: 30px;
margin-top: $topMargin;
color: $orange;
width: auto;
display: inline-block;
margin-left: $margin;
&:before {
position: absolute;
width: $size;
height: $size;
margin-left: -$margin;
margin-top: $size / 4;
content : '';
background-image: url(../images/yellow_play_triangle.svg);
}
/*&:before {*/
/*position: absolute;*/
/*width: $size;*/
/*height: $size;*/
/*margin-left: -$margin;*/
/*margin-top: $size / 4;*/
/*content : '';*/
/*background-image: url(../images/yellow_play_triangle.svg);*/
/*}*/
cursor: pointer;
@ -82,8 +123,8 @@ $topMargin: 35px;
}
}
$loaderWidth: 200px;
$loaderHeight: 60px;
$loaderWidth: 398px;
$loaderHeight: 118px;
#loader {
position: relative;
@ -96,25 +137,6 @@ $topMargin: 35px;
margin-right: auto;
text-transform: uppercase;
&.clickable {
cursor: pointer;
transition: transform 0.1s;
&:hover {
transform: scale(1.1);
}
#fillText:active {
color: black!important;
background-color: $orange;
#piano {
filter: brightness(0);
}
}
}
#loaderText {
position: absolute;
width: 100%;
@ -126,7 +148,7 @@ $topMargin: 35px;
#fill {
position: absolute;
height: 100%;
width: 0%;
width: 100%;
overflow: hidden;
background-color: black;
@ -135,7 +157,6 @@ $topMargin: 35px;
width: $loaderWidth;
height: 100%;
color: $orange;
$imgWidth: 40px;
$margin : 52px;
@ -145,17 +166,26 @@ $topMargin: 35px;
}
#play {
margin-left: 150px;
right: $margin;
position: relative;
/*display: inline-block;*/
}
#germanPlay {
margin-left: 120px;
right: $margin;
position: absolute;
padding-top: 30px;
/*display: inline-block;*/
}
#piano {
left: $margin;
width: $imgWidth;
width: 100%;
height: 100%;
background-image : url(../images/keyboard_icon.svg);
background-image : url(../images/keyboard_icon_CMedit.svg);
background-position: center center;
background-repeat: no-repeat;
}
}
}
@ -165,6 +195,24 @@ $topMargin: 35px;
text-align: center;
font-weight: normal;
}
&.loaded {
margin-top: $topMargin;
border: none;
width: 400px;
height: 120px;
background-color: transparent;
#loaderText {
background-color: transparent;
}
#fillText {
background-color: transparent;
}
#fill {
background-color: transparent;
}
}
}
}
@ -223,12 +271,12 @@ $topMargin: 35px;
#aiExperiments {
background-image: url(../images/badgeAI_master.svg);
&:hover {
opacity: 1;
&:active {
opacity: 0.3;
}
}
/*&:hover {*/
/*opacity: 1;*/
/*&:active {*/
/*opacity: 0.3;*/
/*}*/
/*}*/
}
#googleFriends {
@ -245,9 +293,9 @@ $topMargin: 35px;
margin-right: 0px;
color: white;
&:hover {
opacity: 1;
}
/*&:hover {*/
/*opacity: 1;*/
/*}*/
@media (max-width: $smallScreen) {
font-size: 7px;
@ -290,10 +338,10 @@ $topMargin: 35px;
span {
color: $orange;
text-decoration: underline;
cursor: pointer;
&:hover:active {
color: white;
}
/*cursor: pointer;*/
/*&:hover:active {*/
/*color: white;*/
/*}*/
}
}
@ -352,15 +400,15 @@ $topMargin: 35px;
a {
text-decoration: none;
cursor: pointer;
/*cursor: pointer;*/
&:hover {
opacity: 1;
/*&:hover {*/
/*opacity: 1;*/
&:active {
opacity: 0.3;
}
}
/*&:active {*/
/*opacity: 0.3;*/
/*}*/
/*}*/
}
}
}