Skip to content

Commit

Permalink
feat: most of remaining fairlight audio
Browse files Browse the repository at this point in the history
  • Loading branch information
Julusian committed Apr 16, 2021
1 parent 3d62c37 commit 6cedb95
Show file tree
Hide file tree
Showing 25 changed files with 1,428 additions and 25 deletions.
16 changes: 15 additions & 1 deletion src/__tests__/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,21 @@ export function createEmptyState(): AtemState {
channels: {}
}
state.fairlight = {
inputs: {}
inputs: {},
master: {
equalizerBands: [undefined, undefined, undefined, undefined, undefined],
equalizerGain: 0,
equalizerEnabled: false,
makeUpGain: 0,
faderGain: 0,
followFadeToBlack: false
}
}

for (let i = 0; i < 6000; i++) {
state.fairlight.inputs[i] = {
sources: {}
}
}

if (state.info.multiviewer) {
Expand Down
67 changes: 67 additions & 0 deletions src/commands/Fairlight/FairlightMixerAnalogAudioCommand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { AtemState, InvalidIdError } from '../../state'
import { FairlightAudioInputAnalog } from '../../state/fairlight'
import * as Util from '../../lib/atemUtil'
import { DeserializedCommand, WritableCommand } from '../CommandBase'
import { OmitReadonly } from '../../lib/types'

/**
* TODO - how does this not clash with the normal update command?
*/

export class FairlightMixerAnalogAudioCommand extends WritableCommand<OmitReadonly<FairlightAudioInputAnalog>> {
public static readonly rawName = 'CFAA'

public readonly index: number

constructor(index: number) {
super()

this.index = index
}

public serialize(): Buffer {
const buffer = Buffer.alloc(4)
buffer.writeUInt16BE(this.index, 0)

buffer.writeUInt8(this.properties.inputLevel || 0, 2)

return buffer
}
}

export class FairlightMixerAnalogAudioUpdateCommand extends DeserializedCommand<FairlightAudioInputAnalog> {
public static readonly rawName = 'FAAI'

public readonly index: number

constructor(index: number, properties: FairlightAudioInputAnalog) {
super(properties)

this.index = index
}

public static deserialize(rawCommand: Buffer): FairlightMixerAnalogAudioUpdateCommand {
const index = rawCommand.readUInt16BE(0)

const properties = {
supportedInputLevels: Util.getComponents(rawCommand.readUInt8(3)),
inputLevel: rawCommand.readUInt8(4)
}

return new FairlightMixerAnalogAudioUpdateCommand(index, properties)
}

public applyToState(state: AtemState): string {
if (!state.fairlight) {
throw new InvalidIdError('Fairlight')
}

// TODO
// state.fairlight.inputs[this.index] = {
// sources: {},
// ...state.fairlight.inputs[this.index],
// properties: this.properties
// }
return `fairlight.inputs.${this.index}.properties`
}
}
63 changes: 63 additions & 0 deletions src/commands/Fairlight/FairlightMixerMasterCommand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { FairlightAudioMasterChannel } from '../../state/fairlight'
import { AtemState, InvalidIdError } from '../../state'
import { DeserializedCommand, WritableCommand } from '../CommandBase'
import { OmitReadonly } from '../../lib/types'
import * as Util from '../../lib/atemUtil'
export class FairlightMixerMasterCommand extends WritableCommand<OmitReadonly<FairlightAudioMasterChannel>> {
public static MaskFlags = {
equalizerEnabled: 1 << 0,
equalizerGain: 1 << 1,
makeUpGain: 1 << 2,
faderGain: 1 << 3,
followFadeToBlack: 1 << 4
}

public static readonly rawName = 'CFMP'

public serialize(): Buffer {
const buffer = Buffer.alloc(20)
buffer.writeUInt8(this.flag, 0)

buffer.writeUInt8(this.properties.equalizerEnabled ? 1 : 0, 1)
buffer.writeInt32BE(this.properties.equalizerGain || 0, 4)
buffer.writeInt32BE(this.properties.makeUpGain || 0, 8)
buffer.writeInt32BE(this.properties.faderGain || 0, 12)
buffer.writeUInt8(this.properties.followFadeToBlack ? 1 : 0, 16)
return buffer
}
}

export class FairlightMixerMasterUpdateCommand extends DeserializedCommand<
Omit<FairlightAudioMasterChannel, 'equalizerBands'> & { bandCount: number }
> {
public static readonly rawName = 'FAMP'

public static deserialize(rawCommand: Buffer): FairlightMixerMasterUpdateCommand {
const properties = {
bandCount: rawCommand.readUInt8(0),
equalizerEnabled: rawCommand.readUInt8(1) > 0,
equalizerGain: rawCommand.readInt32BE(4),
makeUpGain: rawCommand.readInt32BE(8),
faderGain: rawCommand.readInt32BE(12),
followFadeToBlack: rawCommand.readUInt8(16) > 0
}

return new FairlightMixerMasterUpdateCommand(properties)
}

public applyToState(state: AtemState): string {
if (!state.fairlight) {
throw new InvalidIdError('Fairlight')
}

state.fairlight.master = {
// default bands to empty
equalizerBands: new Array(this.properties.bandCount).fill(undefined),
// preserve old bands
...state.fairlight.master,
...Util.omit(this.properties, 'bandCount')
}

return `fairlight.master`
}
}
68 changes: 68 additions & 0 deletions src/commands/Fairlight/FairlightMixerMasterCompressorCommand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { FairlightAudioCompressorState } from '../../state/fairlight'
import { AtemState, InvalidIdError } from '../../state'
import { DeserializedCommand, WritableCommand } from '../CommandBase'
import { OmitReadonly } from '../../lib/types'

export class FairlightMixerMasterCompressorCommand extends WritableCommand<
OmitReadonly<FairlightAudioCompressorState>
> {
public static MaskFlags = {
compressorEnabled: 1 << 0,
threshold: 1 << 1,
ratio: 1 << 2,
attack: 1 << 3,
hold: 1 << 4,
release: 1 << 5
}

public static readonly rawName = 'CMCP'

public serialize(): Buffer {
const buffer = Buffer.alloc(24)
buffer.writeUInt8(this.flag, 0)

buffer.writeUInt8(this.properties.compressorEnabled ? 1 : 0, 1)
buffer.writeInt32BE(this.properties.threshold || 0, 4)
buffer.writeInt16BE(this.properties.ratio || 0, 8)
buffer.writeInt32BE(this.properties.attack || 0, 12)
buffer.writeInt32BE(this.properties.hold || 0, 16)
buffer.writeInt32BE(this.properties.release || 0, 20)

return buffer
}
}

export class FairlightMixerMasterCompressorUpdateCommand extends DeserializedCommand<FairlightAudioCompressorState> {
public static readonly rawName = 'MOCP'

public static deserialize(rawCommand: Buffer): FairlightMixerMasterCompressorUpdateCommand {
const properties = {
compressorEnabled: rawCommand.readUInt8(0) > 0,
threshold: rawCommand.readInt32BE(4),
ratio: rawCommand.readInt16BE(8),
attack: rawCommand.readInt32BE(12),
hold: rawCommand.readInt32BE(16),
release: rawCommand.readInt32BE(20)
}

return new FairlightMixerMasterCompressorUpdateCommand(properties)
}

public applyToState(state: AtemState): string {
if (!state.fairlight) {
throw new InvalidIdError('Fairlight')
}

if (!state.fairlight.master) {
throw new InvalidIdError('Fairlight.Master')
}

if (!state.fairlight.master.dynamics) {
state.fairlight.master.dynamics = {}
}

state.fairlight.master.dynamics.compressor = this.properties

return `fairlight.master.dynamics.compressor`
}
}
27 changes: 27 additions & 0 deletions src/commands/Fairlight/FairlightMixerMasterDynamicsResetCommand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { WritableCommand } from '../CommandBase'
import { FairlightDynamicsResetProps } from './common'

export class FairlightMixerMasterDynamicsResetCommand extends WritableCommand<FairlightDynamicsResetProps> {
public static readonly rawName = 'RMOD'

public serialize(): Buffer {
const buffer = Buffer.alloc(4)

let val = 0
if (this.properties.dynamics) {
val |= 1 << 0
}
if (this.properties.expander) {
val |= 1 << 1
}
if (this.properties.compressor) {
val |= 1 << 2
}
if (this.properties.limiter) {
val |= 1 << 3
}

buffer.writeUInt8(val, 1)
return buffer
}
}
90 changes: 90 additions & 0 deletions src/commands/Fairlight/FairlightMixerMasterEqualizerBandCommand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { FairlightAudioEqualizerBandState } from '../../state/fairlight'
import { AtemState, InvalidIdError } from '../../state'
import { DeserializedCommand, WritableCommand } from '../CommandBase'
import { OmitReadonly } from '../../lib/types'
import * as AtemUtil from '../../lib/atemUtil'

export class FairlightMixerMasterEqualizerBandCommand extends WritableCommand<
OmitReadonly<FairlightAudioEqualizerBandState>
> {
public static MaskFlags = {
bandEnabled: 1 << 0,
shape: 1 << 1,
frequencyRange: 1 << 2,
frequency: 1 << 3,
gain: 1 << 4,
qFactor: 1 << 5
}

public static readonly rawName = 'CMBP'

public readonly band: number

public constructor(band: number) {
super()

this.band = band
}

public serialize(): Buffer {
const buffer = Buffer.alloc(20)
buffer.writeUInt8(this.flag, 0)

buffer.writeUInt8(this.band, 1)
buffer.writeUInt8(this.properties.bandEnabled ? 1 : 0, 2)
buffer.writeUInt8(this.properties.shape || 0, 3)
buffer.writeUInt8(this.properties.frequencyRange || 0, 4)
buffer.writeUInt32BE(this.properties.frequency || 0, 8)
buffer.writeInt32BE(this.properties.gain || 0, 12)
buffer.writeInt16BE(this.properties.qFactor || 0, 16)

return buffer
}
}

export class FairlightMixerMasterEqualizerBandUpdateCommand extends DeserializedCommand<
FairlightAudioEqualizerBandState
> {
public static readonly rawName = 'AMBP'

public readonly band: number

constructor(band: number, properties: FairlightAudioEqualizerBandState) {
super(properties)

this.band = band
}

public static deserialize(rawCommand: Buffer): FairlightMixerMasterEqualizerBandUpdateCommand {
const band = rawCommand.readUInt8(0)
const properties = {
bandEnabled: rawCommand.readUInt8(1) > 0,
supportedShapes: AtemUtil.getComponents(rawCommand.readUInt8(2)),
shape: rawCommand.readUInt8(3),
supportedFrequencyRanges: AtemUtil.getComponents(rawCommand.readUInt8(4)),
frequencyRange: rawCommand.readUInt8(5),
frequency: rawCommand.readUInt32BE(8),
gain: rawCommand.readInt32BE(12),
qFactor: rawCommand.readInt16BE(16)
}

return new FairlightMixerMasterEqualizerBandUpdateCommand(band, properties)
}

public applyToState(state: AtemState): string {
if (!state.fairlight) {
throw new InvalidIdError('Fairlight')
}

if (!state.fairlight.master) {
throw new InvalidIdError('Fairlight.Master')
}
if (this.band >= state.fairlight.master.equalizerBands.length) {
throw new InvalidIdError('Fairlight.Master.Equalizer', this.band)
}

state.fairlight.master.equalizerBands[this.band] = this.properties

return `fairlight.master.equalizerBands.${this.band}`
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { WritableCommand } from '../CommandBase'

export class FairlightMixerMasterEqualizerResetCommand extends WritableCommand<{ equalizer: boolean; band: number }> {
public static MaskFlags = {
equalizer: 1 << 0,
band: 1 << 1
}

public static readonly rawName = 'RMOE'

public serialize(): Buffer {
const buffer = Buffer.alloc(4)

buffer.writeUInt8(this.flag, 0)
buffer.writeUInt8(this.properties.equalizer ? 1 : 0, 1)
buffer.writeUInt8(this.properties.band || 0, 2)

return buffer
}
}
Loading

0 comments on commit 6cedb95

Please sign in to comment.