reorginization and new sound format
This commit is contained in:
parent
7c46e70304
commit
6788c54ad6
12 changed files with 595 additions and 186 deletions
|
@ -113,6 +113,7 @@ return gulp
|
|||
"src/**/*.webp",
|
||||
"src/**/*.gif",
|
||||
"src/**/*.svg",
|
||||
"src/**/*.jasf",
|
||||
],{encoding:false})
|
||||
.pipe(plumber()) // Prevent pipe breaking caused by errors
|
||||
.pipe(gulp.dest("dist"));
|
||||
|
|
37
src/webpage/audio/audio.md
Normal file
37
src/webpage/audio/audio.md
Normal file
|
@ -0,0 +1,37 @@
|
|||
# Jank Audio format
|
||||
This is a markdown file that will try to describe the jank client audio format in sufficient detail so people will know how this weird custom format works into the future.
|
||||
This is a byte-aligned format, which uses the sequence jasf in asci as a magic number at the start.
|
||||
|
||||
the next 8 bits will decide how many voices this file has/will provide, if the value is 255 you'll instead have a 16 bit number that follows for how many voices there are, this *should* be unused, but I wouldn't be totally surprised if it did get used.
|
||||
|
||||
then it'll parse for that many voices, which will be formatted like the following:
|
||||
name:String8;
|
||||
length:f32; **if this is 0, this is not an custom sound and is instead refering to something else which will be explained later™**
|
||||
|
||||
Given a non-zero length, this will parse the sounds as following:
|
||||
|instruction | description |
|
||||
| ---------- | ----------- |
|
||||
| 000 | read float32 and use as value |
|
||||
| 001 | read time(it'll always be a value between 0 and 1) |
|
||||
| 002 | read frequency in hz |
|
||||
| 003 | the constant PI |
|
||||
| 004 | Math.sin() on the following sequence |
|
||||
| 005 | multiplies the next two expressions |
|
||||
| 006 | adds the next two expressions |
|
||||
| 007 | divides the first expression by the second |
|
||||
| 008 | subtracts the second expression by the first |
|
||||
| 009 | first expression to the power of the second |
|
||||
| 010 | first expression to the modulo of the second |
|
||||
| 011 | absolute power of the next expression |
|
||||
| 012 | round the next expression |
|
||||
| 013 | Math.cos() on the next expression |
|
||||
> note
|
||||
> this is likely to expand in the future as more things are needed, but this is just how it is right now.
|
||||
|
||||
Once you've read all of the sounds in the file, you can move on to parsing the tracks.
|
||||
This starts out by reading a u16 to find out how many tracks there are, then you'll go on to try and parse that many.
|
||||
|
||||
each track will then read a u16 to find out how long it is, then it'll read bytes as the following.
|
||||
it'll first read the index(which is either a u8 or u16 depending on if the amount of voices was u8 or u16), which is the index of the voice 1-indexed, then if it's not 0 it'll parse two float32s in this order, the volume then the pitch of the sound, if it was 0 it'll instead read one 32f as a delay in the track. if it's a default sound it'll also read a third 32f for length
|
||||
|
||||
then finally you'll parse the audios which are the complete tracks. you'll first parse a u16 to get how many audios there are, then for each audio you'll first parse a string8 for the name, then a u16 for the length then according to the length you'll go on to parse a u16 to get the track (1-indexed again) where if it's 0 you'll instead add a delay according to the next f32, how many ever times according to the length.
|
|
@ -1,181 +1,34 @@
|
|||
class AVoice{
|
||||
audioCtx: AudioContext;
|
||||
info: { wave: string | Function; freq: number };
|
||||
playing: boolean;
|
||||
myArrayBuffer: AudioBuffer;
|
||||
gainNode: GainNode;
|
||||
buffer: Float32Array;
|
||||
source: AudioBufferSourceNode;
|
||||
constructor(wave: string | Function, freq: number, volume = 1){
|
||||
this.audioCtx = new window.AudioContext();
|
||||
this.info = { wave, freq };
|
||||
this.playing = false;
|
||||
this.myArrayBuffer = this.audioCtx.createBuffer(
|
||||
1,
|
||||
this.audioCtx.sampleRate,
|
||||
this.audioCtx.sampleRate
|
||||
);
|
||||
this.gainNode = this.audioCtx.createGain();
|
||||
this.gainNode.gain.value = volume;
|
||||
this.gainNode.connect(this.audioCtx.destination);
|
||||
this.buffer = this.myArrayBuffer.getChannelData(0);
|
||||
this.source = this.audioCtx.createBufferSource();
|
||||
this.source.buffer = this.myArrayBuffer;
|
||||
this.source.loop = true;
|
||||
this.source.start();
|
||||
this.updateWave();
|
||||
import { BinRead } from "../utils/binaryUtils.js";
|
||||
import { Track } from "./track.js";
|
||||
|
||||
export class Audio{
|
||||
name:string;
|
||||
tracks:(Track|number)[];
|
||||
constructor(name:string,tracks:(Track|number)[]){
|
||||
this.tracks=tracks;
|
||||
this.name=name;
|
||||
}
|
||||
get wave(): string | Function{
|
||||
return this.info.wave;
|
||||
}
|
||||
get freq(): number{
|
||||
return this.info.freq;
|
||||
}
|
||||
set wave(wave: string | Function){
|
||||
this.info.wave = wave;
|
||||
this.updateWave();
|
||||
}
|
||||
set freq(freq: number){
|
||||
this.info.freq = freq;
|
||||
this.updateWave();
|
||||
}
|
||||
updateWave(): void{
|
||||
const func = this.waveFunction();
|
||||
for(let i = 0; i < this.buffer.length; i++){
|
||||
this.buffer[i] = func(i / this.audioCtx.sampleRate, this.freq);
|
||||
static parse(read:BinRead,trackarr:Track[]):Audio{
|
||||
const name=read.readString8();
|
||||
const length=read.read16();
|
||||
const tracks:(Track|number)[]=[]
|
||||
for(let i=0;i<length;i++){
|
||||
let index=read.read16();
|
||||
if(index===0){
|
||||
tracks.push(read.readFloat32());
|
||||
}else{
|
||||
tracks.push(trackarr[index-1]);
|
||||
}
|
||||
}
|
||||
waveFunction(): Function{
|
||||
if(typeof this.wave === "function"){
|
||||
return this.wave;
|
||||
return new Audio(name,tracks)
|
||||
}
|
||||
switch(this.wave){
|
||||
case"sin":
|
||||
return(t: number, freq: number)=>{
|
||||
return Math.sin(t * Math.PI * 2 * freq);
|
||||
};
|
||||
case"triangle":
|
||||
return(t: number, freq: number)=>{
|
||||
return Math.abs(((4 * t * freq) % 4) - 2) - 1;
|
||||
};
|
||||
case"sawtooth":
|
||||
return(t: number, freq: number)=>{
|
||||
return((t * freq) % 1) * 2 - 1;
|
||||
};
|
||||
case"square":
|
||||
return(t: number, freq: number)=>{
|
||||
return(t * freq) % 2 < 1 ? 1 : -1;
|
||||
};
|
||||
case"white":
|
||||
return(_t: number, _freq: number)=>{
|
||||
return Math.random() * 2 - 1;
|
||||
};
|
||||
}
|
||||
return new Function();
|
||||
}
|
||||
play(): void{
|
||||
if(this.playing){
|
||||
return;
|
||||
}
|
||||
this.source.connect(this.gainNode);
|
||||
this.playing = true;
|
||||
}
|
||||
stop(): void{
|
||||
if(this.playing){
|
||||
this.source.disconnect();
|
||||
this.playing = false;
|
||||
async play(){
|
||||
for(const thing of this.tracks){
|
||||
if(thing instanceof Track){
|
||||
thing.play();
|
||||
}else{
|
||||
await new Promise((res)=>setTimeout(res,thing));
|
||||
}
|
||||
}
|
||||
static noises(noise: string): void{
|
||||
switch(noise){
|
||||
case"three": {
|
||||
const voicy = new AVoice("sin", 800);
|
||||
voicy.play();
|
||||
setTimeout(_=>{
|
||||
voicy.freq = 1000;
|
||||
}, 50);
|
||||
setTimeout(_=>{
|
||||
voicy.freq = 1300;
|
||||
}, 100);
|
||||
setTimeout(_=>{
|
||||
voicy.stop();
|
||||
}, 150);
|
||||
break;
|
||||
}
|
||||
case"zip": {
|
||||
const voicy = new AVoice((t: number, freq: number)=>{
|
||||
return Math.sin((t + 2) ** Math.cos(t * 4) * Math.PI * 2 * freq);
|
||||
}, 700);
|
||||
voicy.play();
|
||||
setTimeout(_=>{
|
||||
voicy.stop();
|
||||
}, 150);
|
||||
break;
|
||||
}
|
||||
case"square": {
|
||||
const voicy = new AVoice("square", 600, 0.4);
|
||||
voicy.play();
|
||||
setTimeout(_=>{
|
||||
voicy.freq = 800;
|
||||
}, 50);
|
||||
setTimeout(_=>{
|
||||
voicy.freq = 1000;
|
||||
}, 100);
|
||||
setTimeout(_=>{
|
||||
voicy.stop();
|
||||
}, 150);
|
||||
break;
|
||||
}
|
||||
case"beep": {
|
||||
const voicy = new AVoice("sin", 800);
|
||||
voicy.play();
|
||||
setTimeout(_=>{
|
||||
voicy.stop();
|
||||
}, 50);
|
||||
setTimeout(_=>{
|
||||
voicy.play();
|
||||
}, 100);
|
||||
setTimeout(_=>{
|
||||
voicy.stop();
|
||||
}, 150);
|
||||
break;
|
||||
}
|
||||
case "join":{
|
||||
const voicy = new AVoice("triangle", 600,.1);
|
||||
voicy.play();
|
||||
setTimeout(_=>{
|
||||
voicy.freq=800;
|
||||
}, 75);
|
||||
setTimeout(_=>{
|
||||
voicy.freq=1000;
|
||||
}, 150);
|
||||
setTimeout(_=>{
|
||||
voicy.stop();
|
||||
}, 200);
|
||||
break;
|
||||
}
|
||||
case "leave":{
|
||||
const voicy = new AVoice("triangle", 850,.5);
|
||||
voicy.play();
|
||||
setTimeout(_=>{
|
||||
voicy.freq=700;
|
||||
}, 100);
|
||||
setTimeout(_=>{
|
||||
voicy.stop();
|
||||
voicy.freq=400;
|
||||
}, 180);
|
||||
setTimeout(_=>{
|
||||
voicy.play();
|
||||
}, 200);
|
||||
setTimeout(_=>{
|
||||
voicy.stop();
|
||||
}, 250);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
static get sounds(){
|
||||
return["three", "zip", "square", "beep"];
|
||||
}
|
||||
}
|
||||
export{ AVoice as AVoice };
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
<p>I want to let the sound system of jank not be so hard coded, but I still need to work on everything a bit before that can happen. Thanks for your patience.</p>
|
||||
<h3>why does this tool need to exist?</h3>
|
||||
<p>For size reasons jank does not use normal sound files, so I need to make this whole format to be more adaptable</p>
|
||||
<button id="download">Download the sounds</button>
|
||||
</body>
|
||||
<script src="/audio/page.js" type="module"></script>
|
||||
|
||||
|
|
|
@ -1,3 +1,157 @@
|
|||
import { BinWrite } from "../utils/binaryUtils.js";
|
||||
import { setTheme } from "../utils/utils.js";
|
||||
import { Play } from "./play.js";
|
||||
|
||||
setTheme();
|
||||
const w=new BinWrite(2**12);
|
||||
w.writeStringNo("jasf");
|
||||
w.write8(4);
|
||||
|
||||
w.writeString8("sin");
|
||||
w.write32Float(0);
|
||||
w.writeString8("triangle");
|
||||
w.write32Float(0);
|
||||
w.writeString8("square");
|
||||
w.write32Float(0);
|
||||
|
||||
w.writeString8("custom");
|
||||
w.write32Float(150);
|
||||
//return Math.sin(((t + 2) ** Math.cos(t * 4)) * Math.PI * 2 * freq);
|
||||
//Math.sin((((t+2)**Math.cos((t*4)))*((Math.PI*2)*f)))
|
||||
w.write8(4);//sin
|
||||
w.write8(5)//times
|
||||
{
|
||||
w.write8(9);//Power
|
||||
|
||||
{
|
||||
w.write8(6);//adding
|
||||
w.write8(1);//t
|
||||
w.write8(0);w.write32Float(2);//2
|
||||
}
|
||||
w.write8(13);//cos
|
||||
w.write8(5);// times
|
||||
w.write8(1);//t
|
||||
w.write8(0);w.write32Float(4);//4
|
||||
}
|
||||
{
|
||||
w.write8(5)//times
|
||||
w.write8(5)//times
|
||||
w.write8(3);//PI
|
||||
w.write8(0);w.write32Float(2);//2
|
||||
w.write8(2);//freq
|
||||
}
|
||||
|
||||
w.write16(4);//3 tracks
|
||||
|
||||
w.write16(1);//zip
|
||||
w.write8(4);
|
||||
w.write32Float(1)
|
||||
w.write32Float(700)
|
||||
|
||||
w.write16(3);//beep
|
||||
{
|
||||
w.write8(1);
|
||||
w.write32Float(1)
|
||||
w.write32Float(700);
|
||||
w.write32Float(50);
|
||||
|
||||
w.write8(0);
|
||||
w.write32Float(100);
|
||||
|
||||
w.write8(1);
|
||||
w.write32Float(1)
|
||||
w.write32Float(700);
|
||||
w.write32Float(50);
|
||||
}
|
||||
|
||||
w.write16(5);//three
|
||||
{
|
||||
w.write8(1);
|
||||
w.write32Float(1)
|
||||
w.write32Float(800);
|
||||
w.write32Float(50);
|
||||
|
||||
w.write8(0);
|
||||
w.write32Float(50);
|
||||
|
||||
w.write8(1);
|
||||
w.write32Float(1)
|
||||
w.write32Float(1000);
|
||||
w.write32Float(50);
|
||||
|
||||
w.write8(0);
|
||||
w.write32Float(50);
|
||||
|
||||
w.write8(1);
|
||||
w.write32Float(1)
|
||||
w.write32Float(1300);
|
||||
w.write32Float(50);
|
||||
}
|
||||
|
||||
w.write16(5);//square
|
||||
{
|
||||
w.write8(3);
|
||||
w.write32Float(1)
|
||||
w.write32Float(600);
|
||||
w.write32Float(50);
|
||||
|
||||
w.write8(0);
|
||||
w.write32Float(50);
|
||||
|
||||
w.write8(3);
|
||||
w.write32Float(1)
|
||||
w.write32Float(800);
|
||||
w.write32Float(50);
|
||||
|
||||
w.write8(0);
|
||||
w.write32Float(50);
|
||||
|
||||
w.write8(3);
|
||||
w.write32Float(1)
|
||||
w.write32Float(1000);
|
||||
w.write32Float(50);
|
||||
}
|
||||
w.write16(4);//2 audio
|
||||
|
||||
w.writeString8("zip");
|
||||
w.write16(1);
|
||||
w.write16(1);
|
||||
|
||||
w.writeString8("beep");
|
||||
w.write16(1);
|
||||
w.write16(2);
|
||||
|
||||
w.writeString8("three");
|
||||
w.write16(1);
|
||||
w.write16(3);
|
||||
|
||||
w.writeString8("square");
|
||||
w.write16(1);
|
||||
w.write16(4);
|
||||
const buff=w.getBuffer();
|
||||
const play=Play.parseBin(buff);
|
||||
/*
|
||||
const zip=play.audios.get("square");
|
||||
if(zip){
|
||||
setInterval(()=>{
|
||||
zip.play()
|
||||
},1000)
|
||||
;
|
||||
console.log(play.voices[3][0].info.wave)
|
||||
};
|
||||
*/
|
||||
console.log(play,buff);
|
||||
|
||||
const download=document.getElementById("download");
|
||||
if(download){
|
||||
download.onclick=()=>{
|
||||
const blob = new Blob([buff], { type: "binary" });
|
||||
const downloadUrl = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = downloadUrl;
|
||||
a.download = "sounds.jasf";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
URL.revokeObjectURL(downloadUrl);
|
||||
}
|
||||
}
|
||||
|
|
48
src/webpage/audio/play.ts
Normal file
48
src/webpage/audio/play.ts
Normal file
|
@ -0,0 +1,48 @@
|
|||
import { BinRead } from "../utils/binaryUtils.js";
|
||||
import { Track } from "./track.js";
|
||||
import { AVoice } from "./voice.js";
|
||||
import { Audio } from "./audio.js";
|
||||
export class Play{
|
||||
voices:[AVoice,string][]
|
||||
tracks:Track[]
|
||||
audios:Map<string,Audio>;
|
||||
constructor(voices:[AVoice,string][],tracks:Track[],audios:Map<string,Audio>){
|
||||
this.voices=voices;
|
||||
this.tracks=tracks;
|
||||
this.audios=audios;
|
||||
}
|
||||
static parseBin(buffer:ArrayBuffer){
|
||||
const read=new BinRead(buffer);
|
||||
if(read.readStringNo(4)!=="jasf") throw new Error("this is not a jasf file");
|
||||
let voices=read.read8();
|
||||
let six=false;
|
||||
if(voices===255){
|
||||
voices=read.read16();
|
||||
six=true;
|
||||
}
|
||||
const voiceArr:[AVoice,string][]=[];
|
||||
for(let i=0;i<voices;i++){
|
||||
voiceArr.push(AVoice.getVoice(read));
|
||||
}
|
||||
|
||||
const tracks=read.read16();
|
||||
const trackArr:Track[]=[];
|
||||
for(let i=0;i<tracks;i++){
|
||||
trackArr.push(Track.parse(read,voiceArr,six));
|
||||
}
|
||||
|
||||
const audios=read.read16();
|
||||
const audioArr=new Map<string,Audio>();
|
||||
for(let i=0;i<audios;i++){
|
||||
const a=Audio.parse(read,trackArr);
|
||||
audioArr.set(a.name,a)
|
||||
}
|
||||
|
||||
return new Play(voiceArr,trackArr,audioArr);
|
||||
}
|
||||
static async playURL(url:string){
|
||||
const res=await fetch(url);
|
||||
const arr=await res.arrayBuffer();
|
||||
return this.parseBin(arr);
|
||||
}
|
||||
}
|
BIN
src/webpage/audio/sounds.jasf
Normal file
BIN
src/webpage/audio/sounds.jasf
Normal file
Binary file not shown.
46
src/webpage/audio/track.ts
Normal file
46
src/webpage/audio/track.ts
Normal file
|
@ -0,0 +1,46 @@
|
|||
import { BinRead } from "../utils/binaryUtils.js";
|
||||
import { AVoice } from "./voice.js";
|
||||
|
||||
export class Track{
|
||||
seq:(AVoice|number)[];
|
||||
constructor(playing:(AVoice|number)[]){
|
||||
this.seq=playing;
|
||||
}
|
||||
static parse(read:BinRead,play:[AVoice,string][],six:boolean):Track{
|
||||
const length=read.read16();
|
||||
const play2:(AVoice|number)[]=[];
|
||||
for(let i=0;i<length;i++){
|
||||
let index:number;
|
||||
if(six){
|
||||
index=read.read16();
|
||||
}else{
|
||||
index=read.read8();
|
||||
}
|
||||
if(index===0){
|
||||
play2.push(read.readFloat32());
|
||||
continue;
|
||||
}
|
||||
index--;
|
||||
if(!play[index]) throw new Error("voice not found");
|
||||
const [voice]=play[index];
|
||||
let temp:AVoice;
|
||||
if((voice.info.wave instanceof Function)){
|
||||
temp=voice.clone(read.readFloat32(),read.readFloat32());
|
||||
}else{
|
||||
temp=voice.clone(read.readFloat32(),read.readFloat32(),read.readFloat32());
|
||||
}
|
||||
play2.push(temp);
|
||||
|
||||
}
|
||||
return new Track(play2);
|
||||
}
|
||||
async play(){
|
||||
for(const thing of this.seq){
|
||||
if(thing instanceof AVoice){
|
||||
thing.playL();
|
||||
}else{
|
||||
await new Promise((res)=>setTimeout(res,thing));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
246
src/webpage/audio/voice.ts
Normal file
246
src/webpage/audio/voice.ts
Normal file
|
@ -0,0 +1,246 @@
|
|||
import { BinRead } from "../utils/binaryUtils.js";
|
||||
|
||||
class AVoice{
|
||||
audioCtx: AudioContext;
|
||||
info: { wave: string | Function; freq: number };
|
||||
playing: boolean;
|
||||
myArrayBuffer: AudioBuffer;
|
||||
gainNode: GainNode;
|
||||
buffer: Float32Array;
|
||||
source: AudioBufferSourceNode;
|
||||
length=1;
|
||||
constructor(wave: string | Function, freq: number, volume = 1,length=1000){
|
||||
this.length=length;
|
||||
this.audioCtx = new window.AudioContext();
|
||||
this.info = { wave, freq };
|
||||
this.playing = false;
|
||||
this.myArrayBuffer = this.audioCtx.createBuffer(
|
||||
1,
|
||||
this.audioCtx.sampleRate*length/1000,
|
||||
this.audioCtx.sampleRate
|
||||
);
|
||||
this.gainNode = this.audioCtx.createGain();
|
||||
this.gainNode.gain.value = volume;
|
||||
this.gainNode.connect(this.audioCtx.destination);
|
||||
this.buffer = this.myArrayBuffer.getChannelData(0);
|
||||
this.source = this.audioCtx.createBufferSource();
|
||||
this.source.buffer = this.myArrayBuffer;
|
||||
this.source.loop = true;
|
||||
this.source.start();
|
||||
this.updateWave();
|
||||
}
|
||||
clone(volume:number,freq:number,length=this.length){
|
||||
return new AVoice(this.wave,freq,volume,length);
|
||||
}
|
||||
get wave(): string | Function{
|
||||
return this.info.wave;
|
||||
}
|
||||
get freq(): number{
|
||||
return this.info.freq;
|
||||
}
|
||||
set wave(wave: string | Function){
|
||||
this.info.wave = wave;
|
||||
this.updateWave();
|
||||
}
|
||||
set freq(freq: number){
|
||||
this.info.freq = freq;
|
||||
this.updateWave();
|
||||
}
|
||||
updateWave(): void{
|
||||
const func = this.waveFunction();
|
||||
for(let i = 0; i < this.buffer.length; i++){
|
||||
this.buffer[i] = func(i / this.audioCtx.sampleRate, this.freq);
|
||||
}
|
||||
}
|
||||
waveFunction(): Function{
|
||||
if(typeof this.wave === "function"){
|
||||
return this.wave;
|
||||
}
|
||||
switch(this.wave){
|
||||
case"sin":
|
||||
return(t: number, freq: number)=>{
|
||||
return Math.sin(t * Math.PI * 2 * freq);
|
||||
};
|
||||
case"triangle":
|
||||
return(t: number, freq: number)=>{
|
||||
return Math.abs(((4 * t * freq) % 4) - 2) - 1;
|
||||
};
|
||||
case"sawtooth":
|
||||
return(t: number, freq: number)=>{
|
||||
return((t * freq) % 1) * 2 - 1;
|
||||
};
|
||||
case"square":
|
||||
return(t: number, freq: number)=>{
|
||||
return(t * freq) % 2 < 1 ? 1 : -1;
|
||||
};
|
||||
case"white":
|
||||
return(_t: number, _freq: number)=>{
|
||||
return Math.random() * 2 - 1;
|
||||
};
|
||||
}
|
||||
return new Function();
|
||||
}
|
||||
play(): void{
|
||||
if(this.playing){
|
||||
return;
|
||||
}
|
||||
this.source.connect(this.gainNode);
|
||||
this.playing = true;
|
||||
}
|
||||
playL(){
|
||||
this.play();
|
||||
setTimeout(()=>{
|
||||
this.stop();
|
||||
},this.length);
|
||||
}
|
||||
stop(): void{
|
||||
if(this.playing){
|
||||
this.source.disconnect();
|
||||
this.playing = false;
|
||||
}
|
||||
}
|
||||
static noises(noise: string): void{
|
||||
switch(noise){
|
||||
case"three": {
|
||||
const voicy = new AVoice("sin", 800);
|
||||
voicy.play();
|
||||
setTimeout(_=>{
|
||||
voicy.freq = 1000;
|
||||
}, 50);
|
||||
setTimeout(_=>{
|
||||
voicy.freq = 1300;
|
||||
}, 100);
|
||||
setTimeout(_=>{
|
||||
voicy.stop();
|
||||
}, 150);
|
||||
break;
|
||||
}
|
||||
case"zip": {
|
||||
const voicy = new AVoice((t: number, freq: number)=>{
|
||||
return Math.sin((t + 2) ** Math.cos(t * 4) * Math.PI * 2 * freq);
|
||||
}, 700);
|
||||
voicy.play();
|
||||
setTimeout(_=>{
|
||||
voicy.stop();
|
||||
}, 150);
|
||||
break;
|
||||
}
|
||||
case"square": {
|
||||
const voicy = new AVoice("square", 600, 0.4);
|
||||
voicy.play();
|
||||
setTimeout(_=>{
|
||||
voicy.freq = 800;
|
||||
}, 50);
|
||||
setTimeout(_=>{
|
||||
voicy.freq = 1000;
|
||||
}, 100);
|
||||
setTimeout(_=>{
|
||||
voicy.stop();
|
||||
}, 150);
|
||||
break;
|
||||
}
|
||||
case"beep": {
|
||||
const voicy = new AVoice("sin", 800);
|
||||
voicy.play();
|
||||
setTimeout(_=>{
|
||||
voicy.stop();
|
||||
}, 50);
|
||||
setTimeout(_=>{
|
||||
voicy.play();
|
||||
}, 100);
|
||||
setTimeout(_=>{
|
||||
voicy.stop();
|
||||
}, 150);
|
||||
break;
|
||||
}
|
||||
case "join":{
|
||||
const voicy = new AVoice("triangle", 600,.1);
|
||||
voicy.play();
|
||||
setTimeout(_=>{
|
||||
voicy.freq=800;
|
||||
}, 75);
|
||||
setTimeout(_=>{
|
||||
voicy.freq=1000;
|
||||
}, 150);
|
||||
setTimeout(_=>{
|
||||
voicy.stop();
|
||||
}, 200);
|
||||
break;
|
||||
}
|
||||
case "leave":{
|
||||
const voicy = new AVoice("triangle", 850,.5);
|
||||
voicy.play();
|
||||
setTimeout(_=>{
|
||||
voicy.freq=700;
|
||||
}, 100);
|
||||
setTimeout(_=>{
|
||||
voicy.stop();
|
||||
voicy.freq=400;
|
||||
}, 180);
|
||||
setTimeout(_=>{
|
||||
voicy.play();
|
||||
}, 200);
|
||||
setTimeout(_=>{
|
||||
voicy.stop();
|
||||
}, 250);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
static get sounds(){
|
||||
return["three", "zip", "square", "beep"];
|
||||
}
|
||||
static getVoice(read:BinRead):[AVoice,string]{
|
||||
const name = read.readString8();
|
||||
let length=read.readFloat32();
|
||||
let special:Function|string
|
||||
if(length!==0){
|
||||
special=this.parseExpression(read);
|
||||
}else{
|
||||
special=name;
|
||||
length=1;
|
||||
}
|
||||
return [new AVoice(special,0,0,length),name]
|
||||
}
|
||||
static parseExpression(read:BinRead):Function{
|
||||
return new Function("t","f",`return ${this.PEHelper(read)};`);
|
||||
}
|
||||
static PEHelper(read:BinRead):string{
|
||||
let state=read.read8();
|
||||
switch(state){
|
||||
case 0:
|
||||
return ""+read.readFloat32();
|
||||
case 1:
|
||||
return "t";
|
||||
case 2:
|
||||
return "f";
|
||||
case 3:
|
||||
return `Math.PI`
|
||||
case 4:
|
||||
return `Math.sin(${this.PEHelper(read)})`;
|
||||
case 5:
|
||||
return `(${this.PEHelper(read)}*${this.PEHelper(read)})`;
|
||||
case 6:
|
||||
return `(${this.PEHelper(read)}+${this.PEHelper(read)})`;
|
||||
case 7:
|
||||
return `(${this.PEHelper(read)}/${this.PEHelper(read)})`;
|
||||
case 8:
|
||||
return `(${this.PEHelper(read)}-${this.PEHelper(read)})`;
|
||||
case 9:
|
||||
return `(${this.PEHelper(read)}**${this.PEHelper(read)})`;
|
||||
case 10:
|
||||
return `(${this.PEHelper(read)}%${this.PEHelper(read)})`;
|
||||
case 11:
|
||||
return `Math.abs(${this.PEHelper(read)})`;
|
||||
case 12:
|
||||
return `Math.round(${this.PEHelper(read)})`;
|
||||
case 13:
|
||||
return `Math.cos(${this.PEHelper(read)})`;
|
||||
default:
|
||||
throw new Error("unexpected case found!");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export{ AVoice as AVoice };
|
|
@ -1,6 +1,6 @@
|
|||
"use strict";
|
||||
import{ Message }from"./message.js";
|
||||
import{ AVoice }from"./audio/audio.js";
|
||||
import{ AVoice }from"./audio/voice.js";
|
||||
import{ Contextmenu }from"./contextmenu.js";
|
||||
import{ Guild }from"./guild.js";
|
||||
import{ Localuser }from"./localuser.js";
|
||||
|
@ -1403,7 +1403,12 @@ class Channel extends SnowFlake{
|
|||
);
|
||||
}
|
||||
notify(message: Message, deep = 0){
|
||||
AVoice.noises(this.localuser.getNotificationSound());
|
||||
if(this.localuser.play){
|
||||
const voice=this.localuser.play.audios.get(this.localuser.getNotificationSound());
|
||||
if(voice){
|
||||
voice.play();
|
||||
}
|
||||
}
|
||||
if(!("Notification" in window)){
|
||||
}else if(Notification.permission === "granted"){
|
||||
let noticontent: string | undefined | null = message.content.textContent;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import{ Guild }from"./guild.js";
|
||||
import{ Channel }from"./channel.js";
|
||||
import{ Direct }from"./direct.js";
|
||||
import{ AVoice }from"./audio/audio.js";
|
||||
import{ AVoice }from"./audio/voice.js";
|
||||
import{ User }from"./user.js";
|
||||
import{ getapiurls, SW }from"./utils/utils.js";
|
||||
import { getBulkInfo, setTheme, Specialuser } from "./utils/utils.js";
|
||||
|
@ -14,6 +14,7 @@ import { Role } from "./role.js";
|
|||
import { VoiceFactory } from "./voice.js";
|
||||
import { I18n, langmap } from "./i18n.js";
|
||||
import { Emoji } from "./emoji.js";
|
||||
import { Play } from "./audio/play.js";
|
||||
|
||||
const wsCodesRetry = new Set([4000,4001,4002, 4003, 4005, 4007, 4008, 4009]);
|
||||
|
||||
|
@ -40,6 +41,7 @@ class Localuser{
|
|||
channelids: Map<string, Channel> = new Map();
|
||||
readonly userMap: Map<string, User> = new Map();
|
||||
voiceFactory?:VoiceFactory;
|
||||
play?:Play;
|
||||
instancePing = {
|
||||
name: "Unknown",
|
||||
};
|
||||
|
@ -51,6 +53,9 @@ class Localuser{
|
|||
this.userinfo.localuserStore = e;
|
||||
}
|
||||
constructor(userinfo: Specialuser | -1){
|
||||
Play.playURL("/audio/sounds.jasf").then((_)=>{
|
||||
this.play=_;
|
||||
})
|
||||
if(userinfo === -1){
|
||||
return;
|
||||
}
|
||||
|
@ -1234,8 +1239,7 @@ class Localuser{
|
|||
}
|
||||
{
|
||||
const sounds = AVoice.sounds;
|
||||
tas
|
||||
.addSelect(
|
||||
tas.addSelect(
|
||||
I18n.getTranslation("localuser.notisound"),
|
||||
_=>{
|
||||
this.setNotificationSound(sounds[_]);
|
||||
|
@ -1244,7 +1248,12 @@ class Localuser{
|
|||
{ defaultIndex: sounds.indexOf(this.getNotificationSound()) }
|
||||
)
|
||||
.watchForChange(_=>{
|
||||
AVoice.noises(sounds[_]);
|
||||
if(this.play){
|
||||
const voice=this.play.audios.get(sounds[_])
|
||||
if(voice){
|
||||
voice.play();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,11 @@ class BinRead{
|
|||
readString16(){
|
||||
return this.readStringNo(this.read16());
|
||||
}
|
||||
readFloat32(){
|
||||
const float = this.view.getFloat32(this.i);
|
||||
this.i += 4;
|
||||
return float;
|
||||
}
|
||||
readStringNo(length: number){
|
||||
const array = new Uint8Array(length);
|
||||
for(let i = 0; i < length; i++){
|
||||
|
@ -38,6 +43,10 @@ class BinWrite{
|
|||
this.buffer=new ArrayBuffer(maxSize);
|
||||
this.view=new DataView(this.buffer, 0);
|
||||
}
|
||||
write32Float(numb:number){
|
||||
this.view.setFloat32(this.i,numb);
|
||||
this.i+=4;
|
||||
}
|
||||
write16(numb:number){
|
||||
this.view.setUint16(this.i,numb);
|
||||
this.i+=2;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue