mirror of
https://github.com/billsonnn/nitro-renderer.git
synced 2025-01-18 22:36:27 +01:00
Merge branch 'dev'
This commit is contained in:
commit
e7d9e7a828
@ -2,9 +2,6 @@
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
|
||||
# For the full list of supported browsers by the Angular framework, please see:
|
||||
# https://angular.io/guide/browser-support
|
||||
|
||||
# You can see what browsers were selected by your queries by running:
|
||||
# npx browserslist
|
||||
|
||||
@ -13,6 +10,3 @@ last 1 Firefox version
|
||||
last 2 Edge major versions
|
||||
last 2 Safari major versions
|
||||
last 2 iOS major versions
|
||||
Firefox ESR
|
||||
not IE 9-10 # Angular support for IE 9-10 has been deprecated and will be removed as of Angular v11. To opt-in, remove the 'not' prefix on this line.
|
||||
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
|
||||
|
@ -33,6 +33,7 @@ import { IRoomSessionManager } from './session/IRoomSessionManager';
|
||||
import { ISessionDataManager } from './session/ISessionDataManager';
|
||||
import { RoomSessionManager } from './session/RoomSessionManager';
|
||||
import { SessionDataManager } from './session/SessionDataManager';
|
||||
import { ISoundManager } from './sound/ISoundManager';
|
||||
import { SoundManager } from './sound/SoundManager';
|
||||
import { HabboWebTools } from './utils/HabboWebTools';
|
||||
|
||||
@ -98,6 +99,7 @@ export class Nitro extends Application implements INitro
|
||||
|
||||
if(this._worker) this._worker.onmessage = this.createWorkerEvent.bind(this);
|
||||
}
|
||||
soundManager: ISoundManager;
|
||||
|
||||
public static bootstrap(): void
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Resource, Texture } from '@pixi/core';
|
||||
import { Resource, Texture } from '@pixi/core';
|
||||
import { NitroContainer, NitroTexture } from '../../..';
|
||||
import { IAssetManager } from '../../../core/asset/IAssetManager';
|
||||
import { IMessageEvent } from '../../../core/communication/messages/IMessageEvent';
|
||||
@ -202,24 +202,27 @@ export class BadgeImageManager implements IDisposable
|
||||
|
||||
const partNames = ((part.type === 'b') ? this._groupBases.get(part.key) : this._groupSymbols.get(part.key));
|
||||
|
||||
for(const partName of partNames)
|
||||
if(partNames)
|
||||
{
|
||||
if(!partName || !partName.length) continue;
|
||||
for(const partName of partNames)
|
||||
{
|
||||
if(!partName || !partName.length) continue;
|
||||
|
||||
const texture = this._assets.getTexture(`badgepart_${ partName }`);
|
||||
const texture = this._assets.getTexture(`badgepart_${ partName }`);
|
||||
|
||||
if(!texture) continue;
|
||||
if(!texture) continue;
|
||||
|
||||
const { x, y } = part.calculatePosition(texture);
|
||||
const sprite = new NitroSprite(texture);
|
||||
const { x, y } = part.calculatePosition(texture);
|
||||
const sprite = new NitroSprite(texture);
|
||||
|
||||
sprite.position.set(x, y);
|
||||
sprite.position.set(x, y);
|
||||
|
||||
if(isFirst) sprite.tint = parseInt(this._groupPartColors.get(part.color), 16);
|
||||
if(isFirst) sprite.tint = parseInt(this._groupPartColors.get(part.color), 16);
|
||||
|
||||
isFirst = false;
|
||||
isFirst = false;
|
||||
|
||||
container.addChild(sprite);
|
||||
container.addChild(sprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
7
src/nitro/sound/ISoundManager.ts
Normal file
7
src/nitro/sound/ISoundManager.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { INitroManager } from '../../core/common/INitroManager';
|
||||
import { IMusicManager } from './music/IMusicManager';
|
||||
|
||||
export interface ISoundManager extends INitroManager
|
||||
{
|
||||
musicManager: IMusicManager;
|
||||
}
|
@ -2,8 +2,11 @@ import { AdvancedMap, Nitro, NitroSettingsEvent, RoomEngineEvent, RoomEngineObje
|
||||
import { NitroManager } from '../../core/common/NitroManager';
|
||||
import { NitroSoundEvent } from '../events/NitroSoundEvent';
|
||||
import { NitroEvent } from './../../core/events/NitroEvent';
|
||||
import { ISoundManager } from './ISoundManager';
|
||||
import { IMusicManager } from './music/IMusicManager';
|
||||
import { MusicManager } from './music/MusicManager';
|
||||
|
||||
export class SoundManager extends NitroManager
|
||||
export class SoundManager extends NitroManager implements ISoundManager
|
||||
{
|
||||
private _volumeSystem: number;
|
||||
private _volumeFurni: number;
|
||||
@ -13,6 +16,8 @@ export class SoundManager extends NitroManager
|
||||
private _furniSamples: AdvancedMap<number, HTMLAudioElement>;
|
||||
private _furnitureBeingPlayed: AdvancedMap<number, number>;
|
||||
|
||||
private _musicManager: MusicManager;
|
||||
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
@ -25,9 +30,37 @@ export class SoundManager extends NitroManager
|
||||
this._furniSamples = new AdvancedMap();
|
||||
this._furnitureBeingPlayed = new AdvancedMap();
|
||||
|
||||
this._musicManager = new MusicManager();
|
||||
|
||||
this.onEvent = this.onEvent.bind(this);
|
||||
}
|
||||
|
||||
public onInit(): void
|
||||
{
|
||||
this._musicManager.init();
|
||||
|
||||
Nitro.instance.roomEngine.events.addEventListener(RoomEngineSamplePlaybackEvent.PLAY_SAMPLE, this.onEvent);
|
||||
Nitro.instance.roomEngine.events.addEventListener(RoomEngineObjectEvent.REMOVED, this.onEvent);
|
||||
Nitro.instance.roomEngine.events.addEventListener(RoomEngineEvent.DISPOSED, this.onEvent);
|
||||
Nitro.instance.events.addEventListener(NitroSettingsEvent.SETTINGS_UPDATED, this.onEvent);
|
||||
Nitro.instance.events.addEventListener(NitroSoundEvent.PLAY_SOUND, this.onEvent);
|
||||
}
|
||||
|
||||
public onDispose(): void
|
||||
{
|
||||
if(this._musicManager)
|
||||
{
|
||||
this._musicManager.dispose();
|
||||
this._musicManager = null;
|
||||
}
|
||||
|
||||
Nitro.instance.roomEngine.events.removeEventListener(RoomEngineSamplePlaybackEvent.PLAY_SAMPLE, this.onEvent);
|
||||
Nitro.instance.roomEngine.events.removeEventListener(RoomEngineObjectEvent.REMOVED, this.onEvent);
|
||||
Nitro.instance.roomEngine.events.removeEventListener(RoomEngineEvent.DISPOSED, this.onEvent);
|
||||
Nitro.instance.events.removeEventListener(NitroSettingsEvent.SETTINGS_UPDATED, this.onEvent);
|
||||
Nitro.instance.events.removeEventListener(NitroSoundEvent.PLAY_SOUND, this.onEvent);
|
||||
}
|
||||
|
||||
private onEvent(event: NitroEvent)
|
||||
{
|
||||
switch(event.type)
|
||||
@ -72,24 +105,6 @@ export class SoundManager extends NitroManager
|
||||
}
|
||||
}
|
||||
|
||||
public onInit(): void
|
||||
{
|
||||
Nitro.instance.roomEngine.events.addEventListener(RoomEngineSamplePlaybackEvent.PLAY_SAMPLE, this.onEvent);
|
||||
Nitro.instance.roomEngine.events.addEventListener(RoomEngineObjectEvent.REMOVED, this.onEvent);
|
||||
Nitro.instance.roomEngine.events.addEventListener(RoomEngineEvent.DISPOSED, this.onEvent);
|
||||
Nitro.instance.events.addEventListener(NitroSettingsEvent.SETTINGS_UPDATED, this.onEvent);
|
||||
Nitro.instance.events.addEventListener(NitroSoundEvent.PLAY_SOUND, this.onEvent);
|
||||
}
|
||||
|
||||
public onDispose(): void
|
||||
{
|
||||
Nitro.instance.roomEngine.events.removeEventListener(RoomEngineSamplePlaybackEvent.PLAY_SAMPLE, this.onEvent);
|
||||
Nitro.instance.roomEngine.events.removeEventListener(RoomEngineObjectEvent.REMOVED, this.onEvent);
|
||||
Nitro.instance.roomEngine.events.removeEventListener(RoomEngineEvent.DISPOSED, this.onEvent);
|
||||
Nitro.instance.events.removeEventListener(NitroSettingsEvent.SETTINGS_UPDATED, this.onEvent);
|
||||
Nitro.instance.events.removeEventListener(NitroSoundEvent.PLAY_SOUND, this.onEvent);
|
||||
}
|
||||
|
||||
private playSample(sample: HTMLAudioElement, volume: number, pitch: number = 1): void
|
||||
{
|
||||
sample.volume = volume;
|
||||
@ -205,4 +220,9 @@ export class SoundManager extends NitroManager
|
||||
sample.volume = volume;
|
||||
});
|
||||
}
|
||||
|
||||
public get musicManager(): IMusicManager
|
||||
{
|
||||
return this._musicManager;
|
||||
}
|
||||
}
|
||||
|
53
src/nitro/sound/common/SongStartRequestData.ts
Normal file
53
src/nitro/sound/common/SongStartRequestData.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { Nitro } from './../../Nitro';
|
||||
|
||||
export class SongStartRequestData
|
||||
{
|
||||
private _songId: number;
|
||||
private _startPos: number;
|
||||
private _playLength: number;
|
||||
private _playRequestTime: number;
|
||||
private _fadeInSeconds: number;
|
||||
private _fadeOutSeconds: number;
|
||||
|
||||
constructor(songId: number, startPos: number, playLength: number, playRequestTime: number, fadeInSeconds: number, fadeOutSeconds: number)
|
||||
{
|
||||
this._songId = songId;
|
||||
this._startPos = startPos;
|
||||
this._playLength = playLength;
|
||||
this._playRequestTime = playRequestTime;
|
||||
this._fadeInSeconds = fadeInSeconds;
|
||||
this._fadeOutSeconds = fadeOutSeconds;
|
||||
}
|
||||
|
||||
public get songId(): number
|
||||
{
|
||||
return this._songId;
|
||||
}
|
||||
|
||||
public get startPos(): number
|
||||
{
|
||||
if(this._startPos < 0) return 0;
|
||||
|
||||
return this._startPos + ((Nitro.instance.time - this._playRequestTime) / 1000);
|
||||
}
|
||||
|
||||
public get playLength(): number
|
||||
{
|
||||
return this._playLength;
|
||||
}
|
||||
|
||||
public get playRequestTime(): number
|
||||
{
|
||||
return this._playRequestTime;
|
||||
}
|
||||
|
||||
public get fadeInSeconds(): number
|
||||
{
|
||||
return this._fadeInSeconds;
|
||||
}
|
||||
|
||||
public get fadeOutSeconds(): number
|
||||
{
|
||||
return this._fadeOutSeconds;
|
||||
}
|
||||
}
|
22
src/nitro/sound/common/TraxChannel.ts
Normal file
22
src/nitro/sound/common/TraxChannel.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { TraxChannelItem } from './TraxChannelItem';
|
||||
export class TraxChannel
|
||||
{
|
||||
private _id: number;
|
||||
private _items: TraxChannelItem[];
|
||||
|
||||
constructor(id: number)
|
||||
{
|
||||
this._id = id;
|
||||
this._items = [];
|
||||
}
|
||||
|
||||
public addChannelItem(item: TraxChannelItem): void
|
||||
{
|
||||
this._items.push(item);
|
||||
}
|
||||
|
||||
public get items(): TraxChannelItem[]
|
||||
{
|
||||
return this._items;
|
||||
}
|
||||
}
|
21
src/nitro/sound/common/TraxChannelItem.ts
Normal file
21
src/nitro/sound/common/TraxChannelItem.ts
Normal file
@ -0,0 +1,21 @@
|
||||
export class TraxChannelItem
|
||||
{
|
||||
private _id: number;
|
||||
private _length: number;
|
||||
|
||||
constructor(id: number, length: number)
|
||||
{
|
||||
this._id = id;
|
||||
this._length = length;
|
||||
}
|
||||
|
||||
public get id(): number
|
||||
{
|
||||
return this._id;
|
||||
}
|
||||
|
||||
public get length(): number
|
||||
{
|
||||
return this._length;
|
||||
}
|
||||
}
|
94
src/nitro/sound/common/TraxData.ts
Normal file
94
src/nitro/sound/common/TraxData.ts
Normal file
@ -0,0 +1,94 @@
|
||||
import { TraxChannel } from './TraxChannel';
|
||||
import { TraxChannelItem } from './TraxChannelItem';
|
||||
export class TraxData
|
||||
{
|
||||
private _channels: TraxChannel[];
|
||||
private _metaData: Map<string, string>;
|
||||
|
||||
constructor(data: string)
|
||||
{
|
||||
this._channels = [];
|
||||
let channelLines: string[] = [];
|
||||
|
||||
const lines: string[] = data.split(':');
|
||||
const lastLine: string = lines[lines.length - 1];
|
||||
|
||||
if(lastLine.indexOf('meta') > -1)
|
||||
{
|
||||
const metaData: string[] = lastLine.split(';');
|
||||
|
||||
for(const meta of metaData)
|
||||
{
|
||||
const metaAttributes: string[] = meta.split(',');
|
||||
this._metaData.set(metaAttributes[0], metaAttributes[1]);
|
||||
}
|
||||
|
||||
channelLines = lines.slice(0, lines.length - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
channelLines = lines;
|
||||
}
|
||||
|
||||
for(let i = 0; i < channelLines.length / 2; i++)
|
||||
{
|
||||
if(channelLines[i * 2].length > 0)
|
||||
{
|
||||
const channelId: number = parseInt(channelLines[i * 2]);
|
||||
const channelItemSets: string[] = channelLines[(i * 2) + 1].split(';');
|
||||
|
||||
const channel: TraxChannel = new TraxChannel(channelId);
|
||||
|
||||
for(const channelItemSet of channelItemSets)
|
||||
{
|
||||
const channelItemData: string[] = channelItemSet.split(',');
|
||||
|
||||
if(channelItemData.length !== 2) return;
|
||||
|
||||
channel.addChannelItem(new TraxChannelItem(parseInt(channelItemData[0]), parseInt(channelItemData[1])));
|
||||
}
|
||||
|
||||
this._channels.push(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public get channels(): TraxChannel[]
|
||||
{
|
||||
return this._channels;
|
||||
}
|
||||
|
||||
public getSampleIds(): number[]
|
||||
{
|
||||
const ids: number[] = [];
|
||||
|
||||
for(const channel of this._channels)
|
||||
{
|
||||
for(const item of channel.items)
|
||||
{
|
||||
if(ids.indexOf(item.id) === -1) ids.push(item.id);
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
public get hasMetaData(): boolean
|
||||
{
|
||||
return this._metaData.get('meta') !== null;
|
||||
}
|
||||
|
||||
public get metaCutMode(): boolean
|
||||
{
|
||||
return this._metaData.get('c') !== null;
|
||||
}
|
||||
|
||||
public get metaTempo(): number
|
||||
{
|
||||
const tempo: string = this._metaData.get('t');
|
||||
|
||||
if(!tempo) return null;
|
||||
|
||||
return parseInt(tempo);
|
||||
}
|
||||
}
|
195
src/nitro/sound/common/TraxSample.ts
Normal file
195
src/nitro/sound/common/TraxSample.ts
Normal file
@ -0,0 +1,195 @@
|
||||
import { BinaryWriter } from '../../../core/communication/codec/BinaryWriter';
|
||||
import { BinaryReader } from './../../../core/communication/codec/BinaryReader';
|
||||
|
||||
export class TraxSample
|
||||
{
|
||||
public static readonly SAMPLE_FREQUENCY_44KHZ: string = 'sample_44khz';
|
||||
public static readonly SAMPLE_FREQUENCY_22KHZ: string = 'sample_22khz';
|
||||
public static readonly SAMPLE_FREQUENCY_11KHZ: string = 'sample_11khz';
|
||||
public static readonly SAMPLE_SCALE_16BIT: string = 'sample_16bit';
|
||||
public static readonly SAMPLE_SCALE_8BIT: string = 'sample_8bit';
|
||||
public static readonly _Str_11575: number = (1 / 0x8000);
|
||||
private static readonly _Str_14308: number = 32;
|
||||
private static readonly MASK_8BIT: number = 0xFF;
|
||||
private static readonly MASK_16BIT: number = 0xFFFF;
|
||||
private static readonly OFFSET_8BIT: number = 127;
|
||||
private static readonly OFFSET_16BIT: number = 32767;
|
||||
|
||||
private _sampleData: number[];
|
||||
private _id: number;
|
||||
private _samplesPerValue: number;
|
||||
private _sampleRepeats: number;
|
||||
private _usageList: any[];
|
||||
private _usageTimestamp: number;
|
||||
|
||||
constructor(k: BinaryWriter, sampleId: number, sampleFrequency: string = TraxSample.SAMPLE_FREQUENCY_44KHZ, sampleScale: string = TraxSample.SAMPLE_SCALE_16BIT)
|
||||
{
|
||||
this._id = sampleId;
|
||||
this._samplesPerValue = 2;
|
||||
this._sampleRepeats = 1;
|
||||
|
||||
let local5 = 65536;
|
||||
|
||||
switch(sampleFrequency)
|
||||
{
|
||||
case TraxSample.SAMPLE_FREQUENCY_22KHZ:
|
||||
this._sampleRepeats = 2;
|
||||
break;
|
||||
case TraxSample.SAMPLE_FREQUENCY_11KHZ:
|
||||
this._sampleRepeats = 4;
|
||||
break;
|
||||
default:
|
||||
this._sampleRepeats = 1;
|
||||
}
|
||||
|
||||
if(sampleScale === TraxSample.SAMPLE_SCALE_8BIT)
|
||||
{
|
||||
this._samplesPerValue = 4;
|
||||
local5 = 0x0100;
|
||||
}
|
||||
|
||||
const local6: number = this._samplesPerValue * this._sampleRepeats;
|
||||
const local7: number = (Math.trunc(k.getBuffer().byteLength / 8) / local6) * local6;
|
||||
|
||||
this._sampleData = new Array(local7/local6);
|
||||
|
||||
const local8: number = 1 / (local5 / 2);
|
||||
|
||||
k.position = 0;
|
||||
|
||||
const reader: BinaryReader = new BinaryReader(k.getBuffer());
|
||||
|
||||
let local9: number;
|
||||
const local10: number = (local7 / this._sampleRepeats);
|
||||
let local12: number;
|
||||
let local15: number;
|
||||
|
||||
for(let i = 0; i < local10; i++)
|
||||
{
|
||||
local12 = reader.readFloat();
|
||||
reader.readFloat();
|
||||
|
||||
for(let j = 2; j <= this._sampleRepeats; j++)
|
||||
{
|
||||
local15 = reader.readFloat();
|
||||
reader.readFloat();
|
||||
|
||||
local12 = (((j * (j - 1)) / j) + (local15 / j));
|
||||
}
|
||||
|
||||
if(i >= ((local10 - 1) - TraxSample._Str_14308)) local12 = (local12 * (((local10 - 1) - 1) / TraxSample._Str_14308));
|
||||
|
||||
let local14 = ((local12 + 1) / local8);
|
||||
|
||||
if(local14 < 0)
|
||||
{
|
||||
local14 = 0;
|
||||
}
|
||||
else if(local14 >= local5)
|
||||
{
|
||||
local14 = local5 - 1;
|
||||
}
|
||||
|
||||
local9 = (local9 * local5) + local14;
|
||||
|
||||
if((i % this._samplesPerValue) === this._samplesPerValue - 1)
|
||||
{
|
||||
this._sampleData[Math.trunc(i / this._samplesPerValue)] = local9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public setSample(k: number[], arg2: number, arg3: number, arg4: number): number
|
||||
{
|
||||
let local8: number;
|
||||
let local9: number;
|
||||
let local10: number;
|
||||
|
||||
if(k === null || this._sampleData === null) return arg4;
|
||||
|
||||
const local5 = this._samplesPerValue * this._sampleRepeats;
|
||||
arg4 = arg4 / local5;
|
||||
|
||||
if(arg2 < 0) arg3 = arg3 + arg2;
|
||||
|
||||
if(arg3 > k.length - arg2) arg3 = k.length - arg2;
|
||||
|
||||
let local6 = arg3 / local5;
|
||||
let local7: number;
|
||||
|
||||
if(local6 > this._sampleData.length - arg4)
|
||||
{
|
||||
local7 = (local6 - this._sampleData.length - arg4) * local5;
|
||||
local6 = this._sampleData.length - arg4;
|
||||
|
||||
if(local7 > (k.length - arg2)) local7 = k.length - arg2;
|
||||
}
|
||||
|
||||
if(this._sampleRepeats === 1)
|
||||
{
|
||||
if(this._samplesPerValue === 2)
|
||||
{
|
||||
while(local6-- > 0)
|
||||
{
|
||||
local8 = this._sampleData[arg4++];
|
||||
|
||||
k[arg2++] = (((local8 >> 16) & TraxSample.MASK_16BIT) - TraxSample.OFFSET_16BIT);
|
||||
k[arg2++] = ((local8 & TraxSample.MASK_16BIT) - TraxSample.OFFSET_16BIT);
|
||||
}
|
||||
}
|
||||
else if(this._samplesPerValue === 4)
|
||||
{
|
||||
while(local6-- > 0)
|
||||
{
|
||||
local8 = this._sampleData[arg4++];
|
||||
|
||||
k[arg2++] = ((((local8 >> 24) & TraxSample.MASK_8BIT) - TraxSample.OFFSET_8BIT) << 8);
|
||||
k[arg2++] = ((((local8 >> 16) & TraxSample.MASK_8BIT) - TraxSample.OFFSET_8BIT) << 8);
|
||||
k[arg2++] = ((((local8 >> 8) & TraxSample.MASK_8BIT) - TraxSample.OFFSET_8BIT) << 8);
|
||||
k[arg2++] = (((local8 & TraxSample.MASK_8BIT) - TraxSample.OFFSET_8BIT) << 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(this._sampleRepeats >= 2)
|
||||
{
|
||||
local9 = 0;
|
||||
local10 = 0;
|
||||
|
||||
if(this._samplesPerValue === 2)
|
||||
{
|
||||
while(local6-- > 0)
|
||||
{
|
||||
local8 = this._sampleData[arg4++];
|
||||
local10 = (((local8 >> 16) & TraxSample.MASK_16BIT) - TraxSample.OFFSET_16BIT);
|
||||
local9 = this._sampleRepeats;
|
||||
|
||||
while(local9 > 0)
|
||||
// eslint-disable-next-line no-empty
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public get id(): number
|
||||
{
|
||||
return this._id;
|
||||
}
|
||||
|
||||
public get length(): number
|
||||
{
|
||||
return this._sampleData.length * this._samplesPerValue * this._sampleRepeats;
|
||||
}
|
||||
|
||||
public get usageCount(): number
|
||||
{
|
||||
return this._usageList.length;
|
||||
}
|
||||
|
||||
public get usageTimestamp(): number
|
||||
{
|
||||
return this._usageTimestamp;
|
||||
}
|
||||
}
|
166
src/nitro/sound/common/TraxSequencer.ts
Normal file
166
src/nitro/sound/common/TraxSequencer.ts
Normal file
@ -0,0 +1,166 @@
|
||||
import { TraxData } from './TraxData';
|
||||
export class TraxSequencer
|
||||
{
|
||||
private static readonly SAMPLES_PER_SECOND: number = 44100;
|
||||
private static readonly BUFFER_LENGTH: number = 0x2000;
|
||||
private static readonly SAMPLES_BAR_LENGTH: number = 88000;
|
||||
private static readonly BAR_LENGTH: number = 88000;
|
||||
private static readonly MIXING_BUFFER: number[] = new Array(this.BUFFER_LENGTH);
|
||||
private static readonly INTERPOLATION_BUFFER: number[] = new Array(this.BUFFER_LENGTH);
|
||||
|
||||
private _volume: number;
|
||||
//sound
|
||||
//soundChannel
|
||||
private _traxData: TraxData;
|
||||
private _samples: Map<number, any>;
|
||||
private _ready: boolean;
|
||||
private _songId: number;
|
||||
private _playLengthSamples: number = 0;
|
||||
private _playHead: number;
|
||||
//sequence array
|
||||
private _prepared: boolean;
|
||||
private _finished: boolean = true;
|
||||
private _lengthSamples: number;
|
||||
private _latencyMs: number;
|
||||
private _fadeInActive: boolean;
|
||||
private _fadeOutActive: boolean;
|
||||
private _fadeInLengthSamples: number;
|
||||
private _fadeOutLengthSamples: number;
|
||||
private _fadeInSampleCounter: number;
|
||||
private _fadeOutSampleCounter: number;
|
||||
//fadeOutStopTimer
|
||||
//stopTimer
|
||||
private _useCutMode: boolean;
|
||||
private _expectedStreamPosition: number = 0;
|
||||
private _bufferUnderRunCount: number = 0;
|
||||
|
||||
constructor(songId: number, traxData: TraxData, samples: any)
|
||||
{
|
||||
this._latencyMs = 30;
|
||||
//set events
|
||||
this._songId = songId;
|
||||
this._volume = 1;
|
||||
//set sound new Sound()
|
||||
//set soundchannel null
|
||||
this._samples = new Map();
|
||||
this._traxData = traxData;
|
||||
this._ready = true;
|
||||
this._playHead = 0;
|
||||
//set sequence []
|
||||
this._prepared = false;
|
||||
this._lengthSamples = 0;
|
||||
this._finished = false;
|
||||
this._fadeInActive = false;
|
||||
this._fadeOutActive = false;
|
||||
this._fadeInLengthSamples = 0;
|
||||
this._fadeOutLengthSamples = 0;
|
||||
this._fadeInSampleCounter = 0;
|
||||
this._fadeOutSampleCounter = 0;
|
||||
}
|
||||
|
||||
public prepare(): boolean
|
||||
{
|
||||
if(!this._ready) return false;
|
||||
|
||||
if(this._prepared) return true;
|
||||
|
||||
if(this._traxData != null)
|
||||
{
|
||||
this._useCutMode = false;
|
||||
|
||||
if(this._traxData.hasMetaData)
|
||||
{
|
||||
this._useCutMode = this._traxData.metaCutMode;
|
||||
}
|
||||
|
||||
if(this._useCutMode)
|
||||
// eslint-disable-next-line no-empty
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public prepareSequence(): void
|
||||
{
|
||||
for(const channel of this._traxData.channels)
|
||||
{
|
||||
for(const item of channel.items)
|
||||
{
|
||||
const sample = this._samples.get(item.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public get position(): number
|
||||
{
|
||||
return this._playHead / TraxSequencer.SAMPLES_PER_SECOND;
|
||||
}
|
||||
|
||||
private set position(value: number)
|
||||
{
|
||||
this._playHead = value * TraxSequencer.SAMPLES_PER_SECOND;
|
||||
}
|
||||
|
||||
public get volume(): number
|
||||
{
|
||||
return this._volume;
|
||||
}
|
||||
|
||||
public set volume(value: number)
|
||||
{
|
||||
this._volume = value;
|
||||
|
||||
//soundTransform for channel
|
||||
}
|
||||
|
||||
public get ready(): boolean
|
||||
{
|
||||
return this._ready;
|
||||
}
|
||||
|
||||
public set ready(value: boolean)
|
||||
{
|
||||
this._ready = value;
|
||||
}
|
||||
|
||||
public get finished(): boolean
|
||||
{
|
||||
return this._finished;
|
||||
}
|
||||
|
||||
public set finished(value: boolean)
|
||||
{
|
||||
this._finished = value;
|
||||
}
|
||||
|
||||
public get fadeOutSeconds(): number
|
||||
{
|
||||
return this._fadeOutLengthSamples / TraxSequencer.SAMPLES_PER_SECOND;
|
||||
}
|
||||
|
||||
public set fadeOutSeconds(value: number)
|
||||
{
|
||||
this._fadeOutLengthSamples = value * TraxSequencer.SAMPLES_PER_SECOND;
|
||||
}
|
||||
|
||||
public get fadeInSetconds(): number
|
||||
{
|
||||
return this._fadeInLengthSamples / TraxSequencer.SAMPLES_PER_SECOND;
|
||||
}
|
||||
|
||||
public set fadeInSeconds(value: number)
|
||||
{
|
||||
this._fadeInLengthSamples = value * TraxSequencer.SAMPLES_PER_SECOND;
|
||||
}
|
||||
|
||||
public get traxData(): TraxData
|
||||
{
|
||||
return this._traxData;
|
||||
}
|
||||
|
||||
public get length(): number
|
||||
{
|
||||
return this._lengthSamples / TraxSequencer.SAMPLES_PER_SECOND;
|
||||
}
|
||||
}
|
11
src/nitro/sound/events/SoundManagerEvent.ts
Normal file
11
src/nitro/sound/events/SoundManagerEvent.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { NitroEvent } from '../../../core/events/NitroEvent';
|
||||
|
||||
export class SoundManagerEvent extends NitroEvent
|
||||
{
|
||||
public static TRAX_SONG_COMPLETE: string = 'SME_TRAX_SONG_COMPLETE';
|
||||
|
||||
constructor(type: string)
|
||||
{
|
||||
super(type);
|
||||
}
|
||||
}
|
7
src/nitro/sound/music/IMusicManager.ts
Normal file
7
src/nitro/sound/music/IMusicManager.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { INitroManager } from '../../../core/common/INitroManager';
|
||||
|
||||
|
||||
export interface IMusicManager extends INitroManager
|
||||
{
|
||||
playPosition: number;
|
||||
}
|
190
src/nitro/sound/music/MusicManager.ts
Normal file
190
src/nitro/sound/music/MusicManager.ts
Normal file
@ -0,0 +1,190 @@
|
||||
import { NitroManager } from '../../../core/common/NitroManager';
|
||||
import { NitroEvent } from '../../../core/events/NitroEvent';
|
||||
import { JukeboxPlayListFullMessageEvent } from '../../communication/messages/incoming/sound/JukeboxPlayListFullMessageEvent';
|
||||
import { JukeboxSongDisksMessageEvent } from '../../communication/messages/incoming/sound/JukeboxSongDisksMessageEvent';
|
||||
import { NowPlayingMessageEvent } from '../../communication/messages/incoming/sound/NowPlayingMessageEvent';
|
||||
import { TraxSongInfoMessageEvent } from '../../communication/messages/incoming/sound/TraxSongInfoMessageEvent';
|
||||
import { UserSongDisksInventoryMessageEvent } from '../../communication/messages/incoming/sound/UserSongDisksInventoryMessageEvent';
|
||||
import { GetSongInfoMessageComposer } from '../../communication/messages/outgoing/sound/GetSongInfoMessageComposer';
|
||||
import { Nitro } from '../../Nitro';
|
||||
import { RoomObjectSoundMachineEvent } from '../../room/events/RoomObjectSoundMachineEvent';
|
||||
import { SongStartRequestData } from '../common/SongStartRequestData';
|
||||
import { SoundManagerEvent } from '../events/SoundManagerEvent';
|
||||
import { SongInfoEntry } from './../../communication/messages/incoming/sound/SongInfoEntry';
|
||||
import { IMusicManager } from './IMusicManager';
|
||||
import { MusicPriorities } from './MusicPriorities';
|
||||
|
||||
export class MusicManager extends NitroManager implements IMusicManager
|
||||
{
|
||||
public static readonly SKIP_POSITION_SET: number = -1;
|
||||
private static readonly MAXIMUM_NOTIFY_PRIORITY: number = MusicPriorities.PRIORITY_ROOM_PLAYLIST;
|
||||
|
||||
private _timerInstance: any;
|
||||
private _songRequestList: number[];
|
||||
private _requestedSongs: Map<number, boolean>;
|
||||
private _availableSongs: Map<number, SongInfoEntry>;
|
||||
private _songRequestsPerPriority: SongStartRequestData[];
|
||||
|
||||
private _currentEntryId: number;
|
||||
private _playPosition: number;
|
||||
private _isPlaying: boolean;
|
||||
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
|
||||
this._timerInstance = null;
|
||||
this._songRequestList = [];
|
||||
this._requestedSongs = new Map();
|
||||
this._availableSongs = new Map();
|
||||
this._songRequestsPerPriority = [];
|
||||
|
||||
this._currentEntryId = -1;
|
||||
this._playPosition = -1;
|
||||
this._isPlaying = false;
|
||||
|
||||
this.onEvent = this.onEvent.bind(this);
|
||||
|
||||
this._timerInstance = setInterval(this.onTick.bind(this), 1000);
|
||||
}
|
||||
|
||||
public onInit(): void
|
||||
{
|
||||
Nitro.instance.communication.connection.addMessageEvent(new TraxSongInfoMessageEvent(this.onEvent));
|
||||
Nitro.instance.communication.connection.addMessageEvent(new UserSongDisksInventoryMessageEvent(this.onEvent));
|
||||
Nitro.instance.communication.connection.addMessageEvent(new NowPlayingMessageEvent(this.onNowPlayingMessageEvent.bind(this)));
|
||||
Nitro.instance.communication.connection.addMessageEvent(new JukeboxSongDisksMessageEvent(this.onEvent));
|
||||
Nitro.instance.communication.connection.addMessageEvent(new JukeboxPlayListFullMessageEvent(this.onEvent));
|
||||
Nitro.instance.roomEngine.events.addEventListener(RoomObjectSoundMachineEvent.JUKEBOX_INIT, this.onEvent);
|
||||
Nitro.instance.roomEngine.events.addEventListener(RoomObjectSoundMachineEvent.JUKEBOX_DISPOSE, this.onEvent);
|
||||
Nitro.instance.roomEngine.events.addEventListener(RoomObjectSoundMachineEvent.SOUND_MACHINE_INIT, this.onEvent);
|
||||
Nitro.instance.roomEngine.events.addEventListener(RoomObjectSoundMachineEvent.SOUND_MACHINE_DISPOSE, this.onEvent);
|
||||
this.events.addEventListener(SoundManagerEvent.TRAX_SONG_COMPLETE, this.onEvent);
|
||||
}
|
||||
|
||||
public onDispose(): void
|
||||
{
|
||||
if(this._timerInstance)
|
||||
{
|
||||
clearInterval(this._timerInstance);
|
||||
this._timerInstance = null;
|
||||
}
|
||||
|
||||
Nitro.instance.communication.connection.removeMessageEvent(new TraxSongInfoMessageEvent(this.onEvent));
|
||||
Nitro.instance.communication.connection.removeMessageEvent(new UserSongDisksInventoryMessageEvent(this.onEvent));
|
||||
Nitro.instance.communication.connection.removeMessageEvent(new NowPlayingMessageEvent(this.onNowPlayingMessageEvent.bind(this)));
|
||||
Nitro.instance.communication.connection.removeMessageEvent(new JukeboxSongDisksMessageEvent(this.onEvent));
|
||||
Nitro.instance.communication.connection.removeMessageEvent(new JukeboxPlayListFullMessageEvent(this.onEvent));
|
||||
Nitro.instance.roomEngine.events.removeEventListener(RoomObjectSoundMachineEvent.JUKEBOX_INIT, this.onEvent);
|
||||
Nitro.instance.roomEngine.events.removeEventListener(RoomObjectSoundMachineEvent.JUKEBOX_DISPOSE, this.onEvent);
|
||||
Nitro.instance.roomEngine.events.removeEventListener(RoomObjectSoundMachineEvent.SOUND_MACHINE_INIT, this.onEvent);
|
||||
Nitro.instance.roomEngine.events.removeEventListener(RoomObjectSoundMachineEvent.SOUND_MACHINE_DISPOSE, this.onEvent);
|
||||
this.events.removeEventListener(SoundManagerEvent.TRAX_SONG_COMPLETE, this.onEvent);
|
||||
}
|
||||
|
||||
private onEvent(event: NitroEvent): void
|
||||
{
|
||||
console.log('music manager', event);
|
||||
}
|
||||
|
||||
private onTraxSongInfoMessageEvent(event: TraxSongInfoMessageEvent): void
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
for(const song of parser.songs)
|
||||
{
|
||||
const songAvailable: boolean = (this._availableSongs.get(song.id) !== null);
|
||||
const areSamplesRequested: boolean = (this._requestedSongs.get(song.id) !== null);
|
||||
|
||||
if(!songAvailable)
|
||||
{
|
||||
if(areSamplesRequested)
|
||||
{
|
||||
//LoadTraxSong
|
||||
}
|
||||
|
||||
const songInfoEntry: SongInfoEntry = new SongInfoEntry(song.id, song.length, song.name, song.creator, song.data);
|
||||
this._availableSongs.set(song.id, songInfoEntry);
|
||||
|
||||
const topRequestPriotityIndex: number = this.getTopRequestPriority();
|
||||
const songId: number = this.getSongIdRequestedAtPriority(topRequestPriotityIndex);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private onNowPlayingMessageEvent(event: NowPlayingMessageEvent): void
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
this._isPlaying = (parser.currentSongId !== -1);
|
||||
|
||||
if(parser.currentSongId >= 0)
|
||||
{
|
||||
this.playSong(parser.currentSongId, MusicPriorities.PRIORITY_ROOM_PLAYLIST, (parser.syncCount / 1000), 0, 1, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.stopPlaying();
|
||||
}
|
||||
|
||||
if(parser.nextSongId >= 0) this.requestSong(parser.nextSongId, true);
|
||||
|
||||
this._playPosition = parser.currentPosition;
|
||||
//Dispatch local event NowPlayingEvent
|
||||
}
|
||||
|
||||
private onTick(): void
|
||||
{
|
||||
if(this._songRequestList.length === 0) return;
|
||||
|
||||
Nitro.instance.communication.connection.send(new GetSongInfoMessageComposer(...this._songRequestList));
|
||||
this._songRequestList = [];
|
||||
}
|
||||
|
||||
private requestSong(songId: number, arg2: boolean): void
|
||||
{
|
||||
if(this._requestedSongs.get(songId) === null)
|
||||
{
|
||||
this._requestedSongs.set(songId, arg2);
|
||||
this._songRequestList.push(songId);
|
||||
}
|
||||
}
|
||||
|
||||
private playSong(songId: number, priority: number, startPos: number = 0, playLength: number = 0, fadeInSeconds: number = 0.5, fadeOutSeconds: number = 0.5)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private stopPlaying(): void
|
||||
{
|
||||
this._currentEntryId = -1;
|
||||
this._playPosition = -1;
|
||||
this._isPlaying = false;
|
||||
}
|
||||
|
||||
private getTopRequestPriority(): number
|
||||
{
|
||||
return this._songRequestsPerPriority.length - 1;
|
||||
}
|
||||
|
||||
private getSongIdRequestedAtPriority(priorityIndex: number): number
|
||||
{
|
||||
if(priorityIndex < 0 || priorityIndex >= MusicPriorities.PRIORITY_COUNT) return -1;
|
||||
|
||||
if(!this._songRequestsPerPriority[priorityIndex]) return -1;
|
||||
|
||||
return this._songRequestsPerPriority[priorityIndex].songId;
|
||||
}
|
||||
|
||||
public get playPosition(): number
|
||||
{
|
||||
return this._playPosition;
|
||||
}
|
||||
|
||||
public set playPosition(value: number)
|
||||
{
|
||||
this._playPosition = value;
|
||||
}
|
||||
}
|
8
src/nitro/sound/music/MusicPriorities.ts
Normal file
8
src/nitro/sound/music/MusicPriorities.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export class MusicPriorities
|
||||
{
|
||||
public static readonly PRIORITY_ROOM_PLAYLIST: number = 0;
|
||||
public static readonly PRIORITY_USER_PLAYLIST: number = 1;
|
||||
public static readonly PRIORITY_SONG_PLAY: number = 2;
|
||||
public static readonly PRIORITY_PURCHASE_PREVIEW: number = 3;
|
||||
public static readonly PRIORITY_COUNT: number = 4;
|
||||
}
|
Loading…
Reference in New Issue
Block a user