diff --git a/app.py b/app.py
index 9714b69..91f45b0 100644
--- a/app.py
+++ b/app.py
@@ -142,7 +142,8 @@ def route_api_songs():
'category': category_out,
'type': song_type,
'offset': song[13],
- 'song_skin': song_skin_out
+ 'song_skin': song_skin_out,
+ 'volume': song[16]
})
return jsonify(songs_out)
diff --git a/public/src/js/about.js b/public/src/js/about.js
index 1c3586d..d01c66d 100644
--- a/public/src/js/about.js
+++ b/public/src/js/about.js
@@ -143,7 +143,7 @@
}
}
- var issueBody = strings.issueTemplate + "\n\n\n\n" + diag
+ var issueBody = strings.about.issueTemplate + "\n\n\n\n" + diag
this.getLink(this.linkEmail).href += "?body=" + encodeURIComponent(issueBody.replace(/\n/g, "
\r\n"))
return diag
diff --git a/public/src/js/controller.js b/public/src/js/controller.js
index d0bc63b..6e2baae 100644
--- a/public/src/js/controller.js
+++ b/public/src/js/controller.js
@@ -21,6 +21,7 @@ class Controller{
assets.songs.forEach(song => {
if(song.id == this.selectedSong.folder){
this.mainAsset = song.sound
+ this.volume = song.volume || 1
}
})
@@ -35,6 +36,9 @@ class Controller{
if(syncWith){
this.syncWith = syncWith
}
+ if(this.multiplayer !== 2){
+ snd.musicGain.setVolumeMul(this.volume)
+ }
this.game.run()
this.view.run()
if(this.multiplayer === 1){
@@ -161,8 +165,26 @@ class Controller{
if(this.multiplayer){
new LoadSong(this.selectedSong, false, true, this.touchEnabled)
}else{
- var taikoGame = new Controller(this.selectedSong, this.songData, this.autoPlayEnabled, false, this.touchEnabled)
- taikoGame.run()
+ new Promise(resolve => {
+ var songObj = assets.songs.find(song => song.id === this.selectedSong.folder)
+ if(songObj.chart){
+ var reader = new FileReader()
+ var promise = pageEvents.load(reader).then(event => {
+ this.songData = event.target.result.replace(/\0/g, "").split("\n")
+ resolve()
+ })
+ if(this.selectedSong.type === "tja"){
+ reader.readAsText(songObj.chart, "sjis")
+ }else{
+ reader.readAsText(songObj.chart)
+ }
+ }else{
+ resolve()
+ }
+ }).then(() => {
+ var taikoGame = new Controller(this.selectedSong, this.songData, this.autoPlayEnabled, false, this.touchEnabled)
+ taikoGame.run()
+ })
}
}
playSound(id, time){
@@ -232,6 +254,7 @@ class Controller{
this.stopMainLoop()
this.keyboard.clean()
this.view.clean()
+ snd.buffer.loadSettings()
if(!this.multiplayer){
debugObj.controller = null
diff --git a/public/src/js/debug.js b/public/src/js/debug.js
index 9f2836c..beeede3 100644
--- a/public/src/js/debug.js
+++ b/public/src/js/debug.js
@@ -16,6 +16,7 @@ class Debug{
this.branchSelectDiv = this.byClass("branch-select")
this.branchSelect = this.branchSelectDiv.getElementsByTagName("select")[0]
this.branchResetBtn = this.branchSelectDiv.getElementsByClassName("reset")[0]
+ this.volumeDiv = this.byClass("music-volume")
this.restartCheckbox = this.byClass("change-restart")
this.autoplayLabel = this.byClass("autoplay-label")
this.autoplayCheckbox = this.byClass("autoplay")
@@ -40,6 +41,10 @@ class Debug{
this.measureNumSlider.onchange(this.measureNumChange.bind(this))
this.measureNumSlider.set(0)
+ this.volumeSlider = new InputSlider(this.volumeDiv, 0, 3, 2)
+ this.volumeSlider.onchange(this.volumeChange.bind(this))
+ this.volumeSlider.set(1)
+
this.moveTo(100, 100)
this.restore()
this.updateStatus()
@@ -110,10 +115,12 @@ class Debug{
if(this.songFolder === selectedSong.folder){
this.offsetChange(this.offsetSlider.get(), true)
this.branchChange(null, true)
+ this.volumeChange(this.volumeSlider.get(), true)
}else{
this.songFolder = selectedSong.folder
this.offsetSlider.set(this.defaultOffset)
this.branchReset(null, true)
+ this.volumeSlider.set(this.controller.volume)
}
var measures = this.controller.parsedSongData.measures.filter((measure, i, array) => {
@@ -176,6 +183,14 @@ class Debug{
this.restartSong()
}
}
+ volumeChange(value, noRestart){
+ if(this.controller){
+ snd.musicGain.setVolumeMul(value)
+ }
+ if(this.restartCheckbox.checked && !noRestart){
+ this.restartSong()
+ }
+ }
restartSong(){
if(this.controller){
this.controller.restartSong()
@@ -234,6 +249,7 @@ class Debug{
delete this.branchSelectDiv
delete this.branchSelect
delete this.branchResetBtn
+ delete this.volumeDiv
delete this.restartCheckbox
delete this.autoplayLabel
delete this.autoplayCheckbox
diff --git a/public/src/js/game.js b/public/src/js/game.js
index ceabf3f..19609a4 100644
--- a/public/src/js/game.js
+++ b/public/src/js/game.js
@@ -30,6 +30,7 @@ class Game{
this.currentTimingPoint = 0
this.branchNames = ["normal", "advanced", "master"]
this.resetSection()
+ this.gameLagSync = !this.controller.touchEnabled && !(/Firefox/.test(navigator.userAgent))
assets.songs.forEach(song => {
if(song.id == selectedSong.folder){
@@ -364,7 +365,7 @@ class Game{
var value = {
score: score,
ms: circle.ms - currentTime,
- dai: typeDai ? keyDai ? 2 : 1 : 0
+ dai: typeDai ? (keyDai ? 2 : 1) : 0
}
if((!keysDon || !typeDon) && (!keysKa || !typeKa)){
value.reverse = true
@@ -536,7 +537,7 @@ class Game{
this.sndTime = this.startDate - snd.buffer.getTime() * 1000
}else if(ms < 0 || ms >= 0 && this.started){
var currentDate = Date.now()
- if(!this.controller.touchEnabled){
+ if(this.gameLagSync){
var sndTime = currentDate - snd.buffer.getTime() * 1000
var lag = sndTime - this.sndTime
if(Math.abs(lag) >= 50){
diff --git a/public/src/js/importsongs.js b/public/src/js/importsongs.js
index 5040c92..93bd9ec 100644
--- a/public/src/js/importsongs.js
+++ b/public/src/js/importsongs.js
@@ -183,7 +183,7 @@
var songObj = {
id: index + 1,
type: "tja",
- chart: data,
+ chart: file,
stars: [],
music: "muted"
}
@@ -258,7 +258,7 @@
var songObj = {
id: index + 1,
type: "osu",
- chart: data,
+ chart: file,
subtitle: osu.metadata.ArtistUnicode || osu.metadata.Artist,
subtitle_lang: osu.metadata.Artist || osu.metadata.ArtistUnicode,
preview: osu.generalInfo.PreviewTime / 1000,
diff --git a/public/src/js/keyboard.js b/public/src/js/keyboard.js
index 5925658..cb9a2ac 100644
--- a/public/src/js/keyboard.js
+++ b/public/src/js/keyboard.js
@@ -196,18 +196,17 @@ class Keyboard{
this.checkKey(keyCode, "sound", () => {
var circles = this.controller.getCircles()
var circle = circles[this.controller.getCurrentCircle()]
- if(
- sound === "don"
- && circle
- && !circle.isPlayed
- && circle.type === "balloon"
- && circle.requiredHits - circle.timesHit <= 1
- ){
- this.controller.playSound("se_balloon")
- }else{
- this.controller.playSound("neiro_1_" + sound)
+ var currentTime = this.keyTime[keyCode]
+ this.keyTime[sound] = currentTime
+ if(circle && !circle.isPlayed){
+ if(circle.type === "balloon"){
+ if(sound === "don" && circle.requiredHits - circle.timesHit <= 1){
+ this.controller.playSound("se_balloon")
+ return
+ }
+ }
}
- this.keyTime[sound] = this.keyTime[keyCode]
+ this.controller.playSound("neiro_1_" + sound)
})
}
getKeys(){
@@ -242,6 +241,9 @@ class Keyboard{
}
}
waitForKeyup(keyCode, type){
+ if(!this.keys[keyCode]){
+ return
+ }
if(type === "score"){
this.waitKeyupScore[keyCode] = true
}else if(type === "sound"){
diff --git a/public/src/js/loader.js b/public/src/js/loader.js
index a171642..47d1ecb 100644
--- a/public/src/js/loader.js
+++ b/public/src/js/loader.js
@@ -118,6 +118,7 @@ class Loader{
0.5
)
snd.sfxLoudGain.setVolume(1.2)
+ snd.buffer.saveSettings()
this.afterJSCount = 0
diff --git a/public/src/js/loadsong.js b/public/src/js/loadsong.js
index 94012fb..0c0b02f 100644
--- a/public/src/js/loadsong.js
+++ b/public/src/js/loadsong.js
@@ -112,7 +112,15 @@ class LoadSong{
}
}))
if(songObj.chart){
- this.songData = songObj.chart
+ var reader = new FileReader()
+ promises.push(pageEvents.load(reader).then(event => {
+ this.songData = event.target.result.replace(/\0/g, "").split("\n")
+ }))
+ if(song.type === "tja"){
+ reader.readAsText(songObj.chart, "sjis")
+ }else{
+ reader.readAsText(songObj.chart)
+ }
}else{
promises.push(loader.ajax(this.getSongPath(song)).then(data => {
this.songData = data.replace(/\0/g, "").split("\n")
diff --git a/public/src/js/mekadon.js b/public/src/js/mekadon.js
index fe63d71..eff1537 100644
--- a/public/src/js/mekadon.js
+++ b/public/src/js/mekadon.js
@@ -69,25 +69,25 @@ class Mekadon{
type = "don"
}
}
- if(type == "daiDon" && playDai){
+ if(type === "daiDon" && playDai){
this.setKey(kbd["don_l"], ms)
this.setKey(kbd["don_r"], ms)
this.lr = false
keyDai = true
- }else if(type == "don" || type == "daiDon" || drumrollNotes && score !== 2){
+ }else if(type === "don" || type === "daiDon" || drumrollNotes && score !== 2){
this.setKey(this.lr ? kbd["don_l"] : kbd["don_r"], ms)
this.lr = !this.lr
- }else if(type == "daiKa" && playDai){
+ }else if(type === "daiKa" && playDai){
this.setKey(kbd["ka_l"], ms)
this.setKey(kbd["ka_r"], ms)
this.lr = false
keyDai = true
- }else if(type == "ka" || type == "daiKa" || drumrollNotes){
+ }else if(type === "ka" || type === "daiKa" || drumrollNotes){
this.setKey(this.lr ? kbd["ka_l"] : kbd["ka_r"], ms)
this.lr = !this.lr
}
if(type === "balloon"){
- if(circle.requiredHits == 1){
+ if(circle.requiredHits === 1){
assets.sounds["se_balloon"].play()
}
this.game.checkBalloon(circle)
diff --git a/public/src/js/parsetja.js b/public/src/js/parsetja.js
index 427bb43..2b10f9b 100644
--- a/public/src/js/parsetja.js
+++ b/public/src/js/parsetja.js
@@ -10,18 +10,20 @@
this.difficulty = difficulty
this.offset = (offset || 0) * -1000
this.soundOffset = 0
- this.noteTypes = [
- {name: false, txt: false},
- {name: "don", txt: strings.note.don},
- {name: "ka", txt: strings.note.ka},
- {name: "daiDon", txt: strings.note.daiDon},
- {name: "daiKa", txt: strings.note.daiKa},
- {name: "drumroll", txt: strings.note.drumroll},
- {name: "daiDrumroll", txt: strings.note.daiDrumroll},
- {name: "balloon", txt: strings.note.balloon},
- {name: false, txt: false},
- {name: "balloon", txt: strings.note.balloon}
- ]
+ this.noteTypes = {
+ "0": {name: false, txt: false},
+ "1": {name: "don", txt: strings.note.don},
+ "2": {name: "ka", txt: strings.note.ka},
+ "3": {name: "daiDon", txt: strings.note.daiDon},
+ "4": {name: "daiKa", txt: strings.note.daiKa},
+ "5": {name: "drumroll", txt: strings.note.drumroll},
+ "6": {name: "daiDrumroll", txt: strings.note.daiDrumroll},
+ "7": {name: "balloon", txt: strings.note.balloon},
+ "8": {name: false, txt: false},
+ "9": {name: "balloon", txt: strings.note.balloon},
+ "A": {name: "daiDon", txt: strings.note.daiDon},
+ "B": {name: "daiKa", txt: strings.note.daiKa}
+ }
this.courseTypes = {
"0": "easy",
"1": "normal",
@@ -141,6 +143,7 @@
var firstNote = true
var circles = []
var circleID = 0
+ var regexAZ = /[A-Z]/
var pushMeasure = () => {
var note = currentMeasure[0]
@@ -321,7 +324,7 @@
}else{
- var string = line.split("")
+ var string = line.toUpperCase().split("")
for(let symbol of string){
@@ -334,7 +337,7 @@
scroll: scroll
})
break
- case "1": case "2": case "3": case "4":
+ case "1": case "2": case "3": case "4": case "A": case "B":
var type = this.noteTypes[symbol]
var circleObj = {
type: type.name,
@@ -413,7 +416,14 @@
currentMeasure = []
break
default:
- error = true
+ if(regexAZ.test(symbol)){
+ currentMeasure.push({
+ bpm: bpm,
+ scroll: scroll
+ })
+ }else{
+ error = true
+ }
break
}
diff --git a/public/src/js/scoresheet.js b/public/src/js/scoresheet.js
index 1402b86..037e7e4 100644
--- a/public/src/js/scoresheet.js
+++ b/public/src/js/scoresheet.js
@@ -856,7 +856,7 @@ class Scoresheet{
this.draw.clean()
this.canvasCache.clean()
assets.sounds["bgm_result"].stop()
- snd.musicGain.fadeIn()
+ snd.buffer.loadSettings()
this.redrawRunning = false
pageEvents.keyRemove(this, "all")
pageEvents.remove(this.canvas, ["mousedown", "touchstart"])
diff --git a/public/src/js/songselect.js b/public/src/js/songselect.js
index 09857f8..3af61af 100644
--- a/public/src/js/songselect.js
+++ b/public/src/js/songselect.js
@@ -107,7 +107,8 @@ class SongSelect{
type: song.type,
offset: song.offset,
songSkin: song.song_skin || {},
- music: song.music
+ music: song.music,
+ volume: song.volume
})
}
this.songs.sort((a, b) => {
@@ -1741,7 +1742,7 @@ class SongSelect{
if(!loadOnly){
this.preview = songObj.preview_sound
this.preview.gain = snd.previewGain
- this.previewLoaded(startLoad, songObj.preview_time)
+ this.previewLoaded(startLoad, songObj.preview_time, currentSong.volume)
}
}else{
songObj = {id: id}
@@ -1767,7 +1768,7 @@ class SongSelect{
if(currentId === this.previewId){
songObj.preview_sound = sound
this.preview = sound
- this.previewLoaded(startLoad, songObj.preview_time)
+ this.previewLoaded(startLoad, songObj.preview_time, currentSong.volume)
var oldPreview = this.previewList.shift()
if(oldPreview){
@@ -1781,11 +1782,12 @@ class SongSelect{
}
}
}
- previewLoaded(startLoad, prvTime){
+ previewLoaded(startLoad, prvTime, volume){
var endLoad = this.getMS()
var difference = endLoad - startLoad
var minDelay = 300
var delay = minDelay - Math.min(minDelay, difference)
+ snd.previewGain.setVolumeMul(volume || 1)
this.preview.playLoop(delay / 1000, false, prvTime)
}
endPreview(){
@@ -1935,7 +1937,7 @@ class SongSelect{
if(!this.bgmEnabled){
snd.musicGain.fadeIn()
setTimeout(() => {
- snd.musicGain.fadeIn()
+ snd.buffer.loadSettings()
}, 500)
}
this.redrawRunning = false
diff --git a/public/src/js/soundbuffer.js b/public/src/js/soundbuffer.js
index f220863..cd179f5 100644
--- a/public/src/js/soundbuffer.js
+++ b/public/src/js/soundbuffer.js
@@ -3,6 +3,7 @@
var AudioContext = window.AudioContext || window.webkitAudioContext
this.context = new AudioContext()
pageEvents.add(window, ["click", "touchend"], this.pageClicked.bind(this))
+ this.gainList = []
}
load(url, local, gain){
if(local){
@@ -27,7 +28,9 @@
})
}
createGain(channel){
- return new SoundGain(this, channel)
+ var gain = new SoundGain(this, channel)
+ this.gainList.push(gain)
+ return gain
}
setCrossfade(gain1, gain2, median){
if(!Array.isArray(gain1)){
@@ -60,6 +63,18 @@
this.context.resume()
}
}
+ saveSettings(){
+ for(var i = 0; i < this.gainList.length; i++){
+ var gain = this.gainList[i]
+ gain.defaultVol = gain.volume
+ }
+ }
+ loadSettings(){
+ for(var i = 0; i < this.gainList.length; i++){
+ var gain = this.gainList[i]
+ gain.setVolume(gain.defaultVol)
+ }
+ }
}
class SoundGain{
constructor(soundBuffer, channel){
@@ -85,6 +100,9 @@ class SoundGain{
this.gainNode.gain.value = amount * amount
this.volume = amount
}
+ setVolumeMul(amount){
+ this.setVolume(Math.sqrt(amount * amount * this.defaultVol))
+ }
setCrossfade(amount){
this.setVolume(Math.sqrt(Math.sin(Math.PI / 2 * amount)))
}
diff --git a/public/src/js/strings.js b/public/src/js/strings.js
index 7d13389..16ddaa8 100644
--- a/public/src/js/strings.js
+++ b/public/src/js/strings.js
@@ -1,7 +1,7 @@
function StringsJa(){
this.id = "ja"
this.name = "日本語"
- this.regex = /^ja$/
+ this.regex = /^ja$|^ja-/
this.font = "TnT, Meiryo, sans-serif"
this.taikoWeb = "たいこウェブ"
diff --git a/public/src/js/view.js b/public/src/js/view.js
index b1733c8..f8fee1f 100644
--- a/public/src/js/view.js
+++ b/public/src/js/view.js
@@ -1438,7 +1438,7 @@
ctx.fill()
ctx.globalAlpha = 1
}
- if(!circle.animating){
+ if(!circle.animating && circle.text){
// Text
var text = circle.text
var textX = circlePos.x
diff --git a/public/src/views/debug.html b/public/src/views/debug.html
index dd37b44..e57addc 100644
--- a/public/src/views/debug.html
+++ b/public/src/views/debug.html
@@ -20,6 +20,10 @@
+