mirror of
https://github.com/Floriansylvain/creative_coding_1.git
synced 2026-08-19 19:53:18 +02:00
Initial commit
This commit is contained in:
Vendored
BIN
Binary file not shown.
@@ -0,0 +1,119 @@
|
||||
import EventEmitter from "./EventEmitter.js"
|
||||
import Experience from "../Experience.js"
|
||||
|
||||
export default class AudioAnalyser extends EventEmitter {
|
||||
constructor(audioPath, fftSize = 1024) {
|
||||
super()
|
||||
|
||||
this.experience = new Experience()
|
||||
this.scene = this.experience.scene
|
||||
this.resources = this.experience.resources
|
||||
this.interface = this.experience.interface
|
||||
|
||||
this.averageFrequencies = 0
|
||||
this.averageLowFrequencies = 0
|
||||
this.averageMidFrequencies = 0
|
||||
this.averageHighFrequencies = 0
|
||||
|
||||
this.interface.on("startExperience", () => {
|
||||
this.audioContext = new AudioContext()
|
||||
this.analyser = this.audioContext.createAnalyser()
|
||||
this.analyser.fftSize = fftSize
|
||||
this.frequencyData = new Uint8Array(this.analyser.frequencyBinCount)
|
||||
this.timeData = new Uint8Array(this.analyser.fftSize)
|
||||
|
||||
this.isPlaying = false
|
||||
this.gainNode = this.audioContext.createGain()
|
||||
this.gainNode.gain.value = 0.1
|
||||
|
||||
this.audio = new Audio(audioPath)
|
||||
this.source = this.audioContext.createMediaElementSource(this.audio)
|
||||
this.source.connect(this.analyser)
|
||||
this.source.connect(this.gainNode)
|
||||
this.gainNode.connect(this.audioContext.destination)
|
||||
this.play()
|
||||
})
|
||||
}
|
||||
|
||||
play() {
|
||||
if (this.isPlaying) return
|
||||
|
||||
this.isPlaying = true
|
||||
this.audio.play()
|
||||
}
|
||||
|
||||
pause() {
|
||||
if (!this.isPlaying) return
|
||||
|
||||
this.isPlaying = false
|
||||
this.audio.pause()
|
||||
}
|
||||
|
||||
update() {
|
||||
if (!this.isPlaying) return
|
||||
|
||||
this.analyser.getByteFrequencyData(this.frequencyData)
|
||||
this.analyser.getByteTimeDomainData(this.timeData)
|
||||
|
||||
this.setAverageLowFrequencies()
|
||||
this.setAverageMediumFrequencies()
|
||||
this.setAverageHighFrequencies()
|
||||
this.setAverageFrequencies()
|
||||
}
|
||||
|
||||
setVolume(gain) {
|
||||
this.gainNode.gain.value = gain
|
||||
}
|
||||
|
||||
setAverageFrequencies() {
|
||||
// on add tous les éléments de l'array entre eux
|
||||
const total = this.frequencyData.reduce((acc, cur) => acc + cur)
|
||||
// on fait la moyenne des fréquences
|
||||
const average = total / this.frequencyData.length
|
||||
|
||||
this.averageFrequencies = average / 255
|
||||
}
|
||||
|
||||
setAverageLowFrequencies() {
|
||||
// On divise l'array de toutes les frequences par 3 et on prend la première partie (les fréquences les plus hautes)
|
||||
|
||||
const third = Math.round(this.frequencyData.length / 3)
|
||||
const lowFrequencies = this.frequencyData.slice(0, third)
|
||||
|
||||
// on add tous les éléments de l'array entre eux
|
||||
const total = lowFrequencies.reduce((acc, cur) => acc + cur)
|
||||
// on fait la moyenne des fréquences
|
||||
const average = total / lowFrequencies.length
|
||||
|
||||
this.averageLowFrequencies = average / 255
|
||||
}
|
||||
|
||||
setAverageMediumFrequencies() {
|
||||
// On divise l'array de toutes les frequences par 3 et on prend la deuxieme partie (les fréquences mid)
|
||||
const third = Math.round(this.frequencyData.length / 3)
|
||||
const mediumFrequencies = this.frequencyData.slice(third, third * 2)
|
||||
|
||||
// on add tous les éléments de l'array entre eux
|
||||
const total = mediumFrequencies.reduce((acc, cur) => acc + cur)
|
||||
// on fait la moyenne des fréquences
|
||||
const average = total / mediumFrequencies.length
|
||||
|
||||
this.averageMidFrequencies = average / 255
|
||||
}
|
||||
|
||||
setAverageHighFrequencies() {
|
||||
// On divise l'array de toutes les frequences par 3 et on prend la troiseme partie (les fréquences hautes)
|
||||
const third = Math.round(this.frequencyData.length / 3)
|
||||
const highFrequencies = this.frequencyData.slice(
|
||||
third * 2,
|
||||
this.frequencyData.length - 1
|
||||
)
|
||||
|
||||
// on add tous les éléments de l'array entre eux
|
||||
const total = highFrequencies.reduce((acc, cur) => acc + cur)
|
||||
// on fait la moyenne des fréquences
|
||||
const average = total / highFrequencies.length
|
||||
|
||||
this.averageHighFrequencies = average / 255
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import * as dat from 'lil-gui'
|
||||
|
||||
export default class Debug
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
this.active = window.location.hash === '#debug'
|
||||
|
||||
if(this.active)
|
||||
{
|
||||
this.ui = new dat.GUI()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
export default class EventEmitter
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
this.callbacks = {}
|
||||
this.callbacks.base = {}
|
||||
}
|
||||
|
||||
on(_names, callback)
|
||||
{
|
||||
// Errors
|
||||
if(typeof _names === 'undefined' || _names === '')
|
||||
{
|
||||
console.warn('wrong names')
|
||||
return false
|
||||
}
|
||||
|
||||
if(typeof callback === 'undefined')
|
||||
{
|
||||
console.warn('wrong callback')
|
||||
return false
|
||||
}
|
||||
|
||||
// Resolve names
|
||||
const names = this.resolveNames(_names)
|
||||
|
||||
// Each name
|
||||
names.forEach((_name) =>
|
||||
{
|
||||
// Resolve name
|
||||
const name = this.resolveName(_name)
|
||||
|
||||
// Create namespace if not exist
|
||||
if(!(this.callbacks[ name.namespace ] instanceof Object))
|
||||
this.callbacks[ name.namespace ] = {}
|
||||
|
||||
// Create callback if not exist
|
||||
if(!(this.callbacks[ name.namespace ][ name.value ] instanceof Array))
|
||||
this.callbacks[ name.namespace ][ name.value ] = []
|
||||
|
||||
// Add callback
|
||||
this.callbacks[ name.namespace ][ name.value ].push(callback)
|
||||
})
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
off(_names)
|
||||
{
|
||||
// Errors
|
||||
if(typeof _names === 'undefined' || _names === '')
|
||||
{
|
||||
console.warn('wrong name')
|
||||
return false
|
||||
}
|
||||
|
||||
// Resolve names
|
||||
const names = this.resolveNames(_names)
|
||||
|
||||
// Each name
|
||||
names.forEach((_name) =>
|
||||
{
|
||||
// Resolve name
|
||||
const name = this.resolveName(_name)
|
||||
|
||||
// Remove namespace
|
||||
if(name.namespace !== 'base' && name.value === '')
|
||||
{
|
||||
delete this.callbacks[ name.namespace ]
|
||||
}
|
||||
|
||||
// Remove specific callback in namespace
|
||||
else
|
||||
{
|
||||
// Default
|
||||
if(name.namespace === 'base')
|
||||
{
|
||||
// Try to remove from each namespace
|
||||
for(const namespace in this.callbacks)
|
||||
{
|
||||
if(this.callbacks[ namespace ] instanceof Object && this.callbacks[ namespace ][ name.value ] instanceof Array)
|
||||
{
|
||||
delete this.callbacks[ namespace ][ name.value ]
|
||||
|
||||
// Remove namespace if empty
|
||||
if(Object.keys(this.callbacks[ namespace ]).length === 0)
|
||||
delete this.callbacks[ namespace ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Specified namespace
|
||||
else if(this.callbacks[ name.namespace ] instanceof Object && this.callbacks[ name.namespace ][ name.value ] instanceof Array)
|
||||
{
|
||||
delete this.callbacks[ name.namespace ][ name.value ]
|
||||
|
||||
// Remove namespace if empty
|
||||
if(Object.keys(this.callbacks[ name.namespace ]).length === 0)
|
||||
delete this.callbacks[ name.namespace ]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
trigger(_name, _args)
|
||||
{
|
||||
// Errors
|
||||
if(typeof _name === 'undefined' || _name === '')
|
||||
{
|
||||
console.warn('wrong name')
|
||||
return false
|
||||
}
|
||||
|
||||
let finalResult = null
|
||||
let result = null
|
||||
|
||||
// Default args
|
||||
const args = !(_args instanceof Array) ? [] : _args
|
||||
|
||||
// Resolve names (should on have one event)
|
||||
let name = this.resolveNames(_name)
|
||||
|
||||
// Resolve name
|
||||
name = this.resolveName(name[ 0 ])
|
||||
|
||||
// Default namespace
|
||||
if(name.namespace === 'base')
|
||||
{
|
||||
// Try to find callback in each namespace
|
||||
for(const namespace in this.callbacks)
|
||||
{
|
||||
if(this.callbacks[ namespace ] instanceof Object && this.callbacks[ namespace ][ name.value ] instanceof Array)
|
||||
{
|
||||
this.callbacks[ namespace ][ name.value ].forEach(function(callback)
|
||||
{
|
||||
result = callback.apply(this, args)
|
||||
|
||||
if(typeof finalResult === 'undefined')
|
||||
{
|
||||
finalResult = result
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Specified namespace
|
||||
else if(this.callbacks[ name.namespace ] instanceof Object)
|
||||
{
|
||||
if(name.value === '')
|
||||
{
|
||||
console.warn('wrong name')
|
||||
return this
|
||||
}
|
||||
|
||||
this.callbacks[ name.namespace ][ name.value ].forEach(function(callback)
|
||||
{
|
||||
result = callback.apply(this, args)
|
||||
|
||||
if(typeof finalResult === 'undefined')
|
||||
finalResult = result
|
||||
})
|
||||
}
|
||||
|
||||
return finalResult
|
||||
}
|
||||
|
||||
resolveNames(_names)
|
||||
{
|
||||
let names = _names
|
||||
names = names.replace(/[^a-zA-Z0-9 ,/.]/g, '')
|
||||
names = names.replace(/[,/]+/g, ' ')
|
||||
names = names.split(' ')
|
||||
|
||||
return names
|
||||
}
|
||||
|
||||
resolveName(name)
|
||||
{
|
||||
const newName = {}
|
||||
const parts = name.split('.')
|
||||
|
||||
newName.original = name
|
||||
newName.value = parts[ 0 ]
|
||||
newName.namespace = 'base' // Base namespace
|
||||
|
||||
// Specified namespace
|
||||
if(parts.length > 1 && parts[ 1 ] !== '')
|
||||
{
|
||||
newName.namespace = parts[ 1 ]
|
||||
}
|
||||
|
||||
return newName
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import * as THREE from 'three'
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
|
||||
import EventEmitter from './EventEmitter.js'
|
||||
|
||||
export default class Resources extends EventEmitter
|
||||
{
|
||||
constructor(sources)
|
||||
{
|
||||
super()
|
||||
|
||||
this.sources = sources
|
||||
|
||||
this.items = {}
|
||||
this.toLoad = this.sources.length
|
||||
this.loaded = 0
|
||||
|
||||
this.setLoaders()
|
||||
this.startLoading()
|
||||
}
|
||||
|
||||
setLoaders()
|
||||
{
|
||||
this.loaders = {}
|
||||
this.loaders.audioLoader = new THREE.AudioLoader()
|
||||
this.loaders.gltfLoader = new GLTFLoader()
|
||||
this.loaders.textureLoader = new THREE.TextureLoader()
|
||||
this.loaders.cubeTextureLoader = new THREE.CubeTextureLoader()
|
||||
}
|
||||
|
||||
startLoading()
|
||||
{
|
||||
// Load each source
|
||||
for(const source of this.sources)
|
||||
{
|
||||
if(source.type === 'gltfModel')
|
||||
{
|
||||
this.loaders.gltfLoader.load(
|
||||
source.path,
|
||||
(file) =>
|
||||
{
|
||||
this.sourceLoaded(source, file)
|
||||
}
|
||||
)
|
||||
}
|
||||
else if (source.type === 'audio')
|
||||
{
|
||||
this.loaders.audioLoader.load(
|
||||
source.path,
|
||||
(file) =>
|
||||
{
|
||||
this.sourceLoaded(source, file)
|
||||
}
|
||||
)
|
||||
}
|
||||
else if(source.type === 'texture')
|
||||
{
|
||||
this.loaders.textureLoader.load(
|
||||
source.path,
|
||||
(file) =>
|
||||
{
|
||||
this.sourceLoaded(source, file)
|
||||
}
|
||||
)
|
||||
}
|
||||
else if(source.type === 'cubeTexture')
|
||||
{
|
||||
this.loaders.cubeTextureLoader.load(
|
||||
source.path,
|
||||
(file) =>
|
||||
{
|
||||
this.sourceLoaded(source, file)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceLoaded(source, file)
|
||||
{
|
||||
this.items[source.name] = file
|
||||
|
||||
this.loaded++
|
||||
|
||||
if(this.loaded === this.toLoad)
|
||||
{
|
||||
this.trigger('ready')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import EventEmitter from './EventEmitter.js'
|
||||
|
||||
export default class Sizes extends EventEmitter
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super()
|
||||
|
||||
// Setup
|
||||
this.width = window.innerWidth
|
||||
this.height = window.innerHeight
|
||||
this.pixelRatio = Math.min(window.devicePixelRatio, 2)
|
||||
|
||||
// Resize event
|
||||
window.addEventListener('resize', () =>
|
||||
{
|
||||
this.width = window.innerWidth
|
||||
this.height = window.innerHeight
|
||||
this.pixelRatio = Math.min(window.devicePixelRatio, 2)
|
||||
|
||||
this.trigger('resize')
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import EventEmitter from './EventEmitter.js'
|
||||
|
||||
export default class Time extends EventEmitter
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super()
|
||||
|
||||
// Setup
|
||||
this.start = Date.now()
|
||||
this.current = this.start
|
||||
this.elapsed = 0
|
||||
this.delta = 16
|
||||
|
||||
window.requestAnimationFrame(() =>
|
||||
{
|
||||
this.tick()
|
||||
})
|
||||
}
|
||||
|
||||
tick()
|
||||
{
|
||||
const currentTime = Date.now()
|
||||
this.delta = currentTime - this.current
|
||||
this.current = currentTime
|
||||
this.elapsed = this.current - this.start
|
||||
|
||||
this.trigger('tick')
|
||||
|
||||
window.requestAnimationFrame(() =>
|
||||
{
|
||||
this.tick()
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user