Skip to content

对触屏进行了基本适配,支持了 iOS Safari 浏览器,修复了 #19 #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Binary file added hitsounds/combobreak.wav
Binary file not shown.
2 changes: 2 additions & 0 deletions hitsounds/convert.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ ffmpeg -i soft-hitclap.wav soft-hitclap.ogg
ffmpeg -i soft-sliderslide.wav soft-sliderslide.ogg
ffmpeg -i soft-sliderwhistle.wav soft-sliderwhistle.ogg
ffmpeg -i soft-slidertick.wav soft-slidertick.ogg

ffmpeg -i combobreak.ogg combobreak.mp3
250 changes: 174 additions & 76 deletions scripts/downloader.js
Original file line number Diff line number Diff line change
@@ -1,84 +1,182 @@
// beatmap downloader

function startpreview(box) {
let volume = 1;
if (window.gamesettings) {
volume = (window.gamesettings.mastervolume/100) * (window.gamesettings.musicvolume/100);
volume = Math.min(1, Math.max(0, volume));
}
let audios = document.getElementsByTagName("audio");
for (let i=0; i<audios.length; ++i)
audios[i].softstop();
let a = document.createElement("audio");
let s = document.createElement("source");
s.src = "https://cdn.sayobot.cn:25225/preview/" + box.sid + ".mp3";
s.type = "audio/mpeg";
a.appendChild(s);
a.volume = 0;
a.play();
document.body.appendChild(a);
let fadeIn = setInterval(function(){
if (a.volume < volume)
a.volume = Math.min(volume, a.volume + 0.05*volume);
else
clearInterval(fadeIn);
}, 30);
let fadeOut = setInterval(function(){
if (a.currentTime > 9.3) // assume it's 10s long
a.volume = Math.max(0, a.volume - 0.05*volume);
if (a.volume == 0)
clearInterval(fadeOut);
}, 30);
a.softstop = function() {
let fadeOut = setInterval(function(){
a.volume = Math.max(0, a.volume - 0.05*volume);
if (a.volume == 0) {
clearInterval(fadeOut);
a.remove();
(() => {

/**
* Preview Audio
*/
class PreviewAudio {
/**
* Build a PreviewAudio object
* @param {string | number} sid Beatmap's sid
* @param {number} volume Volume of preview audio
*/
constructor(sid, volume = 1) {
const audioContext = new Audio("https://cdn.sayobot.cn:25225/preview/" + sid + ".mp3");
this._sid = sid;
this._volume = volume;
this._audioContext = audioContext;
this._playing = false;
this._ready = false;
this._fadeTimer = 0;
this._playTimer = 0;
audioContext.load();
audioContext.volume = 0;
audioContext.addEventListener('canplay', () => {
this._ready = true
if(this._playing === true){
this.play();
}
}, {once: true})
}
play() {
this._playing = true;
if(this._ready){
this._playing = true
this._audioContext.volume = 0;
this._audioContext.currentTime = 0;
this._audioContext.play();
clearInterval(this._fadeTimer);
clearTimeout(this._playTimer);
this._fadeTimer = setInterval(() => {
if (this._audioContext.volume < this._volume)
this._audioContext.volume = Math.min(this._volume, this._audioContext.volume + 0.05 * this._volume);
else
clearInterval(this._fadeTimer);
clearTimeout(this._playTimer);
}, 30);
this._playTimer = setTimeout(() => {
this._audioContext.volume = this._volume;
clearInterval(this._fadeTimer);
clearTimeout(this._playTimer);
}, 600);
}
}, 10);
}
stop() {
this._playing = false
clearInterval(this._fadeTimer);
clearTimeout(this._playTimer);
this._fadeTimer = setInterval(() => {
this._audioContext.volume = Math.max(0, this._audioContext.volume - 0.05 * this._volume);
if (this._audioContext.volume === 0) {
this._audioContext.pause();
clearInterval(this._fadeTimer);
clearTimeout(this._playTimer);
}
}, 10);
this._playTimer = setTimeout(() => {
this._audioContext.pause();
clearInterval(this._fadeTimer);
clearTimeout(this._playTimer);
}, 200);
}
set volume(value) {
this._volume = value;
}
get volume() {
return this._volume;
}
}
}

function startdownload(box) {
startpreview(box);
if (box.downloading) {
return;
}
let url = "https://txy1.sayobot.cn/beatmaps/download/mini/" + box.sid;
box.downloading = true;
box.classList.add("downloading");
let xhr = new XMLHttpRequest();
xhr.responseType = 'arraybuffer';
xhr.open("GET", url);
// create download progress bar
let container = document.createElement("div");
let title = document.createElement("div");
let bar = document.createElement("progress");
container.className = "download-progress";
title.className = "title";
title.innerText = box.setdata.title;
container.appendChild(title);
container.appendChild(bar);
// insert so that download list from recent to old
let statuslines = document.getElementById("statuslines");
statuslines.insertBefore(container, statuslines.children[3]);
bar.max = 1;
bar.value = 0;
// async part
xhr.onload = function() {
box.oszblob = new Blob([xhr.response]);
bar.className = "finished";
box.classList.remove("downloading");
class PreviewAudioManager {
/**
* Create a preview audio manager
* @param {object} [settings] Preview audio manager settings
* @param {number} [settings.volume] Audio's volume
*/
constructor(settings = {}) {
const {volume} = settings
/**
* @type {PreviewAudio}
*/
this._active = null;
this._volume = volume;
}
/**
* Play preview audio
* @param {string | number} sid Beatmap's sid
*/
play(sid) {
if(this._active){
this._active.stop();
}
this._active = new PreviewAudio(sid, this._volume);
this._active.play()
}
stop() {
if(this._active){
this._active.stop();
}
}
set volume(value) {
if(value > 1){
value = 1;
}
this._volume = value;
if(this._active) {
this._active.volume = value;
}
}
get volume() {
return this._volume;
}
}
xhr.onprogress = function(e) {
bar.value = e.loaded / e.total;

const previewAudioMgr = new PreviewAudioManager()

function startpreview(box) {
let volume = 1;
if (window.gamesettings) {
volume = (window.gamesettings.mastervolume/100) * (window.gamesettings.musicvolume/100);
volume = Math.min(1, Math.max(0, volume));
}
previewAudioMgr.volume = volume
previewAudioMgr.play(box.sid)
}
xhr.onerror = function() {
console.error("download failed");
alert("Beatmap download failed. Please retry later.")
box.downloading = false;
box.classList.remove("downloading");

function startdownload(box) {
startpreview(box);
if (box.downloading) {
return;
}
let url = "https://txy1.sayobot.cn/beatmaps/download/mini/" + box.sid;
box.downloading = true;
box.classList.add("downloading");
let xhr = new XMLHttpRequest();
xhr.responseType = 'arraybuffer';
xhr.open("GET", url);
// create download progress bar
let container = document.createElement("div");
let title = document.createElement("div");
let bar = document.createElement("progress");
container.className = "download-progress";
title.className = "title";
title.innerText = box.setdata.title;
container.appendChild(title);
container.appendChild(bar);
// insert so that download list from recent to old
let statuslines = document.getElementById("statuslines");
statuslines.insertBefore(container, statuslines.children[3]);
bar.max = 1;
bar.value = 0;
// async part
xhr.onload = function() {
box.oszblob = new Blob([xhr.response]);
bar.className = "finished";
box.classList.remove("downloading");
}
xhr.onprogress = function(e) {
bar.value = e.loaded / e.total;
}
xhr.onerror = function() {
console.error("download failed");
alert("Beatmap download failed. Please retry later.")
box.downloading = false;
box.classList.remove("downloading");
}
xhr.send();
}
xhr.send();
}

window.startdownload = startdownload
window.previewAudioMgr = previewAudioMgr
})()
41 changes: 25 additions & 16 deletions scripts/initgame.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,23 +108,32 @@ function(Osu, _, sound, Playback) {
'hitsounds/drum-slidertick.ogg',
'hitsounds/combobreak.ogg',
];
var issafariBrowser = /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);
if(issafariBrowser){
sample = sample.map(path => {
const pathSplited = path.split('.');
pathSplited.pop();
pathSplited.push('wav');
return pathSplited.join('.');
})
}
sounds.whenLoaded = function(){
game.sample[1].hitnormal = sounds['hitsounds/normal-hitnormal.ogg'];
game.sample[1].hitwhistle = sounds['hitsounds/normal-hitwhistle.ogg'];
game.sample[1].hitfinish = sounds['hitsounds/normal-hitfinish.ogg'];
game.sample[1].hitclap = sounds['hitsounds/normal-hitclap.ogg'];
game.sample[1].slidertick = sounds['hitsounds/normal-slidertick.ogg'];
game.sample[2].hitnormal = sounds['hitsounds/soft-hitnormal.ogg'];
game.sample[2].hitwhistle = sounds['hitsounds/soft-hitwhistle.ogg'];
game.sample[2].hitfinish = sounds['hitsounds/soft-hitfinish.ogg'];
game.sample[2].hitclap = sounds['hitsounds/soft-hitclap.ogg'];
game.sample[2].slidertick = sounds['hitsounds/soft-slidertick.ogg'];
game.sample[3].hitnormal = sounds['hitsounds/drum-hitnormal.ogg'];
game.sample[3].hitwhistle = sounds['hitsounds/drum-hitwhistle.ogg'];
game.sample[3].hitfinish = sounds['hitsounds/drum-hitfinish.ogg'];
game.sample[3].hitclap = sounds['hitsounds/drum-hitclap.ogg'];
game.sample[3].slidertick = sounds['hitsounds/drum-slidertick.ogg'];
game.sampleComboBreak = sounds['hitsounds/combobreak.ogg'];
game.sample[1].hitnormal = sounds[sample[0]];
game.sample[1].hitwhistle = sounds[sample[1]];
game.sample[1].hitfinish = sounds[sample[2]];
game.sample[1].hitclap = sounds[sample[3]];
game.sample[1].slidertick = sounds[sample[4]];
game.sample[2].hitnormal = sounds[sample[5]];
game.sample[2].hitwhistle = sounds[sample[6]];
game.sample[2].hitfinish = sounds[sample[7]];
game.sample[2].hitclap = sounds[sample[8]];
game.sample[2].slidertick = sounds[sample[9]];
game.sample[3].hitnormal = sounds[sample[10]];
game.sample[3].hitwhistle = sounds[sample[11]];
game.sample[3].hitfinish = sounds[sample[12]];
game.sample[3].hitclap = sounds[sample[13]];
game.sample[3].slidertick = sounds[sample[14]];
game.sampleComboBreak = sounds[sample[15]];
window.soundReady = true;
document.getElementById("sound-progress").classList.add("finished");
document.body.classList.add("sound-ready");
Expand Down
4 changes: 1 addition & 3 deletions scripts/launchgame.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,7 @@ function launchOSU(osu, beatmapid, version){
game.scene = playback;
playback.onload = function() {
// stop beatmap preview
let audios = document.getElementsByTagName("audio");
for (let i=0; i<audios.length; ++i)
audios[i].softstop();
previewAudioMgr.stop()
}
playback.load(); // load audio

Expand Down
18 changes: 14 additions & 4 deletions scripts/osu-audio.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,23 @@ define([], function() {
return {startoffset:offset_predict_mp3(tags)};
}

const audioContext = new AudioContext();
if (audioContext.state === "suspended") {
document.body.addEventListener("touchstart", event => {
audioContext.resume();
}, {
once: true
});
}

function OsuAudio(filename, buffer, callback) {
var self = this;
this.decoded = null;
this.source = null;
this.started = 0;
this.position = 0;
this.playing = false;
this.audio = new AudioContext();
this.audio = audioContext;
this.gain = this.audio.createGain();
this.gain.connect(this.audio.destination);
this.playbackRate = 1.0;
Expand Down Expand Up @@ -125,9 +134,11 @@ define([], function() {
};

this.play = function play(wait = 0) {
if (self.audio.state == "suspended") {
window.alert("Audio can't play. Please use Chrome or Firefox.")
if (self.audio.state === "suspended") {
console.warn("Audio suspended. Waiting for touchstart.");
self.audio.resume();
}
self.playing = true;
self.source = self.audio.createBufferSource();
self.source.playbackRate.value = self.playbackRate;
self.source.buffer = self.decoded;
Expand All @@ -140,7 +151,6 @@ define([], function() {
else {
self.source.start(0, self.position);
}
self.playing = true;
};

// return value true: success
Expand Down
Loading