Files
noisedash/src/components/noise.js
2021-08-25 04:05:50 -07:00

341 lines
12 KiB
JavaScript

import { Filter, LFO, Noise, Players, Transport, Tremolo } from 'tone'
export default {
name: 'Noise',
data: () => ({
isTimerValid: false,
selectedProfile: {},
profileItems: [],
profileDialog: false,
profileName: '',
isProfileValid: false,
playDisabled: false,
isTimerEnabled: false,
hours: 0,
minutes: 0,
seconds: 30,
duration: 30,
timeRemaining: 0,
noiseColor: 'pink',
noiseColorItems: ['pink', 'white', 'brown'],
volume: -10,
isFilterEnabled: false,
filterCutoff: 20000,
filterType: 'lowpass',
filterTypeItems: ['lowpass', 'highpass', 'bandpass', 'lowshelf', 'highshelf', 'notch', 'allpass', 'peaking'],
isLFOFilterCutoffEnabled: false,
lfoFilterCutoffFrequency: 0.5,
lfoFilterCutoffMin: 0,
lfoFilterCutoffMax: 20000,
lfoFilterCutoffRange: [100, 5000],
isTremoloEnabled: false,
tremoloFrequency: 0.5,
tremoloDepth: 0.5,
allSamples: [],
loadedSamples: [],
selectedSample: null,
uploadSampleDialog: false,
addSampleDialog: false,
checkedSamples: [],
sampleName: '',
file: null,
isSampleUploadValid: false,
rules: {
lt (n) {
return value => (!isNaN(parseInt(value, 10)) && value < n) || 'Must be less than ' + n
},
gt (n) {
return value => (!isNaN(parseInt(value, 10)) && value > n) || 'Must be greater than ' + n
},
required () {
return value => !!value || 'Required'
}
}
}),
computed: {
unloadedSamples: function () {
const samples = []
this.allSamples.forEach(s1 => {
const result = this.loadedSamples.find(s2 => s2.id === s1.id)
if (!result) {
samples.push(s1)
}
})
return samples
}
},
created () {
this.noise = new Noise()
this.filter = new Filter()
this.tremolo = new Tremolo()
this.lfo = new LFO()
this.players = new Players()
this.populateProfileItems()
this.getSamples()
},
methods: {
play () {
this.playDisabled = true
Transport.cancel()
// TODO: This conditional logic can be improved
if (!this.isFilterEnabled && !this.isTremoloEnabled) {
this.noise = new Noise({ volume: this.volume, type: this.noiseColor }).toDestination()
} else if (!this.isFilterEnabled && this.isTremoloEnabled) {
this.tremolo = new Tremolo({ frequency: this.tremoloFrequency, depth: this.tremoloDepth }).toDestination().start()
this.noise = new Noise({ volume: this.volume, type: this.noiseColor }).connect(this.tremolo)
} else if (this.isFilterEnabled && !this.isTremoloEnabled) {
this.filter = new Filter(this.filterCutoff, this.filterType).toDestination()
this.noise = new Noise({ volume: this.volume, type: this.noiseColor }).connect(this.filter)
} else {
this.tremolo = new Tremolo({ frequency: this.tremoloFrequency, depth: this.tremoloDepth }).toDestination().start()
this.filter = new Filter(this.filterCutoff, this.filterType).connect(this.tremolo)
this.noise = new Noise({ volume: this.volume, type: this.noiseColor }).connect(this.filter)
}
if (this.isLFOFilterCutoffEnabled) {
this.lfo = new LFO({ frequency: this.lfoFilterCutoffFrequency, min: this.lfoFilterCutoffRange[0], max: this.lfoFilterCutoffRange[1] })
this.lfo.connect(this.filter.frequency).start()
}
if (this.isTimerEnabled) {
this.duration = parseInt((this.hours * 3600)) + parseInt((this.minutes * 60)) + parseInt(this.seconds)
this.noise.sync().start(0).stop(this.duration)
Transport.loopEnd = this.duration
this.timeRemaining = this.duration
this.transportInterval = setInterval(() => this.stop(), this.duration * 1000 + 100)
this.timeRemainingInterval = setInterval(() => this.startTimer(), 1000)
this.loadedSamples.forEach(s => {
this.players.player(s.id).unsync().sync().start(0).stop(this.duration)
})
} else {
this.noise.sync().start(0)
this.loadedSamples.forEach(s => {
this.players.player(s.id).unsync().sync().start(0)
})
}
Transport.start()
},
stop () {
clearInterval(this.transportInterval)
Transport.stop()
this.playDisabled = false
clearInterval(this.timeRemainingInterval)
this.timeRemaining = 0
this.duration = 0
},
startTimer () {
this.timeRemaining -= 1
},
updateVolume () {
this.noise.volume.value = this.volume
},
updateNoiseColor () {
this.noise.type = this.noiseColor
},
updateFilterType () {
this.filter.type = this.filterType
},
updateFilterCutoff () {
this.filter.set({ frequency: this.filterCutoff })
},
updateLFOFilterCutoffFrequency () {
this.lfo.set({ frequency: this.lfoFilterCutoffFrequency })
},
updateLFOFilterCutoffRange () {
this.lfo.set({ min: this.lfoFilterCutoffRange[0], max: this.lfoFilterCutoffRange[1] })
},
updateTremoloFrequency () {
this.tremolo.set({ frequency: this.tremoloFrequency })
},
updateTremoloDepth () {
this.tremolo.set({ depth: this.tremoloDepth })
},
updateAudioChain () {
this.noise.disconnect()
// TODO: This conditional logic can be improved
if (!this.isFilterEnabled && !this.isTremoloEnabled) {
this.noise.toDestination()
} else if (!this.isFilterEnabled && this.isTremoloEnabled) {
this.tremolo = new Tremolo({ frequency: this.tremoloFrequency, depth: this.tremoloDepth }).toDestination().start()
this.noise.connect(this.tremolo)
} else if (this.isFilterEnabled && !this.isLFOFilterCutoffEnabled && !this.isTremoloEnabled) {
this.filter = new Filter(this.filterCutoff, this.filterType).toDestination()
this.noise.connect(this.filter)
this.lfo.disconnect()
this.lfo.stop()
} else if (this.isFilterEnabled && this.isLFOFilterCutoffEnabled && !this.isTremoloEnabled) {
this.filter = new Filter(this.filterCutoff, this.filterType).toDestination()
this.noise.connect(this.filter)
this.lfo = new LFO({ frequency: this.lfoFilterCutoffFrequency, min: this.lfoFilterCutoffRange[0], max: this.lfoFilterCutoffRange[1] })
this.lfo.connect(this.filter.frequency).start()
} else {
this.tremolo = new Tremolo({ frequency: this.tremoloFrequency, depth: this.tremoloDepth }).toDestination().start()
this.filter = new Filter(this.filterCutoff, this.filterType).connect(this.tremolo)
this.noise.connect(this.filter)
}
},
populateProfileItems () {
this.$http.get('/profiles')
.then(response => {
if (response.status === 200) {
if (response.data.profiles.length === 0) {
this.addDefaultProfile()
} else {
this.profileItems = response.data.profiles
this.selectedProfile = this.profileItems[0]
}
}
})
.catch((error) => {
console.error(error.response)
})
},
addDefaultProfile () {
this.$http.post('/profiles/default')
.then(response => {
if (response.status === 200) {
this.selectedProfile = { id: response.data.id, text: 'Default' }
}
})
.catch((error) => {
console.error(error.response)
})
},
saveProfile () {
this.$http.post('/profiles', {
name: this.profileName,
isTimerEnabled: this.isTimerEnabled,
duration: this.duration,
volume: this.volume,
noiseColor: this.noiseColor,
isFilterEnabled: this.isFilterEnabled,
filterType: this.filterType,
filterCutoff: this.filterCutoff,
isLFOFilterCutoffEnabled: this.isLFOFilterCutoffEnabled,
lfoFilterCutoffFrequency: this.lfoFilterCutoffFrequency,
lfoFilterCutoffLow: this.lfoFilterCutoffRange[0],
lfoFilterCutoffHigh: this.lfoFilterCutoffRange[1],
isTremoloEnabled: this.isTremoloEnabled,
tremoloFrequency: this.tremoloFrequency,
tremoloDepth: this.tremoloDepth,
samples: this.loadedSamples
}).then(response => {
const id = response.data.id
if (response.status === 200) {
this.profileDialog = false
this.populateProfileItems()
this.$http.get('/profiles')
.then(response => {
if (response.status === 200) {
this.profileItems = response.data.profiles
this.selectedProfile = { id: id, text: this.profileName }
}
})
.catch((error) => {
console.error(error.response)
})
}
})
.catch((error) => {
console.error(error.response)
})
},
loadProfile () {
this.$http.get('/profiles/'.concat(this.selectedProfile.id))
.then(response => {
if (response.status === 200) {
const profile = response.data.profile
this.isTimerEnabled = profile.isTimerEnabled
this.duration = profile.duration
this.volume = profile.volume
this.noiseColor = profile.noiseColor
this.isFilterEnabled = profile.isFilterEnabled
this.filterType = profile.filterType
this.filterCutoff = profile.filterCutoff
this.isLFOFilterCutoffEnabled = profile.isLFOFilterCutoffEnabled
this.lfoFilterCutoffFrequency = profile.lfoFilterCutoffFrequency
this.lfoFilterCutoffRange[0] = profile.lfoFilterCutoffLow
this.lfoFilterCutoffRange[1] = profile.lfoFilterCutoffHigh
this.isTremoloEnabled = profile.isTremoloEnabled
this.tremoloFrequency = profile.tremoloFrequency
this.tremoloDepth = profile.tremoloDepth
this.loadedSamples = profile.samples
}
})
.catch((error) => {
console.error(error.response)
})
},
deleteProfile () {
this.$http.delete('/profiles/'.concat(this.selectedProfile.id))
.then(response => {
if (response.status === 200) {
this.populateProfileItems()
}
})
.catch((error) => {
console.error(error.response)
})
},
getSamples () {
this.$http.get('/samples')
.then(response => {
if (response.status === 200) {
this.allSamples = response.data.samples
this.allSamples.forEach(s => {
if (!this.players.has(s.id)) {
this.players.add(s.id, '/samples/' + s.name).toDestination()
}
})
}
})
.catch((error) => {
console.error(error)
})
},
uploadSample () {
const formData = new FormData()
formData.append('name', this.sampleName)
formData.append('sample', this.selectedSample)
this.$http.post('/samples', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(response => {
if (response.status === 200) {
this.getSamples()
}
})
.catch((error) => {
console.error(error.response)
})
this.uploadSampleDialog = false
},
addSample () {
this.checkedSamples.forEach(i => {
const load = this.allSamples.find(e => e.id === i)
this.loadedSamples.push(load)
})
this.addSampleDialog = false
},
updateSampleVolume (id, index) {
this.players.player(id).volume.value = this.loadedSamples[index].volume
}
}
}