@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
156 lines (143 loc) • 5.33 kB
text/typescript
import {BaseSopOperation} from './_Base';
import {CoreGroup} from '../../../core/geometry/Group';
import {InputCloneMode} from '../../poly/InputCloneMode';
import {AttribClass, ATTRIBUTE_CLASSES} from '../../../core/geometry/Constant';
import {TypeAssert} from '../../poly/Assert';
import {NotesBuilder, NoteHolder} from '../../../core/audio/NotesBuilder';
import {CoreAttribute} from '../../../core/geometry/Attribute';
import {CoreEntity} from '../../../core/geometry/CoreEntity';
import {isBooleanTrue} from '../../../core/Type';
import {DefaultOperationParams} from '../../../core/operations/_Base';
import {pointsFromObject} from '../../../core/geometry/entities/point/CorePointUtils';
import {corePointClassFactory} from '../../../core/geometry/CoreObjectFactory';
import {CorePoint} from '../../../core/geometry/entities/point/CorePoint';
import {CoreObjectType} from '../../../core/geometry/ObjectContent';
enum OutOfRangeBehavior {
RESTART = 'restart',
BOUNCE = 'bounce',
}
export const OUT_OF_RANGE_BEHAVIOR: OutOfRangeBehavior[] = [OutOfRangeBehavior.RESTART, OutOfRangeBehavior.BOUNCE];
const _points: CorePoint<CoreObjectType>[] = [];
interface AudioNotesSopParams extends DefaultOperationParams {
class: number;
name: string;
toctave: boolean;
octaveName: string;
startOctave: number;
endOctave: number;
outOfRangeBehavior: number;
}
export class AudioNotesSopOperation extends BaseSopOperation {
static override readonly DEFAULT_PARAMS: AudioNotesSopParams = {
class: ATTRIBUTE_CLASSES.indexOf(AttribClass.OBJECT),
name: 'note',
toctave: false,
octaveName: 'octave',
startOctave: 2,
endOctave: 4,
outOfRangeBehavior: OUT_OF_RANGE_BEHAVIOR.indexOf(OutOfRangeBehavior.BOUNCE),
};
static override readonly INPUT_CLONED_STATE = InputCloneMode.FROM_NODE;
static override type(): Readonly<'AudioNotes'> {
return 'AudioNotes';
}
override cook(inputCoreGroups: CoreGroup[], params: AudioNotesSopParams) {
const inputCoreGroup = inputCoreGroups[0];
const attribClass = ATTRIBUTE_CLASSES[params.class];
this._addAttribute(attribClass, inputCoreGroup, params);
return inputCoreGroup;
}
private async _addAttribute(attribClass: AttribClass, coreGroup: CoreGroup, params: AudioNotesSopParams) {
switch (attribClass) {
case AttribClass.POINT:
return this._addPointAttribute(coreGroup, params);
case AttribClass.VERTEX: {
this.states?.error.set('vertex not supported yet');
return;
}
case AttribClass.PRIMITIVE: {
this.states?.error.set('primitive not supported yet');
return;
}
case AttribClass.OBJECT:
return this._addObjectAttribute(coreGroup, params);
case AttribClass.CORE_GROUP:
return this._addCoreGroupAttribute(coreGroup, params);
}
TypeAssert.unreachable(attribClass);
}
private _addPointAttribute(coreGroup: CoreGroup, params: AudioNotesSopParams) {
const objects = coreGroup.allObjects();
for (let object of objects) {
pointsFromObject(object, _points);
const corePointClass = corePointClassFactory(object);
const values = this._values(_points, params);
// const coreGeometry = coreObject.coreGeometry();
// if (coreGeometry) {
const notesIndexData = CoreAttribute.arrayToIndexedArrays(values.map((v) => v.note));
corePointClass.setIndexedAttribute(object, params.name, notesIndexData.values, notesIndexData.indices);
if (isBooleanTrue(params.toctave)) {
const octavesArray = values.map((v) => v.octave);
if (!corePointClass.hasAttribute(object, params.octaveName)) {
corePointClass.addNumericAttribute(object, params.octaveName, 1, 1);
}
let i = 0;
for (let corePoint of _points) {
corePoint.setAttribValue(params.octaveName, octavesArray[i]);
i++;
}
}
// }
}
}
private _addObjectAttribute(coreGroup: CoreGroup, params: AudioNotesSopParams) {
const coreObjects = coreGroup.allCoreObjects();
const values = this._values(coreObjects, params);
for (let i = 0; i < coreObjects.length; i++) {
const coreObject = coreObjects[i];
coreObject.addAttribute(params.name, values[i].note);
if (isBooleanTrue(params.toctave)) {
coreObject.addAttribute(params.octaveName, values[i].octave);
}
}
}
private _addCoreGroupAttribute(coreGroup: CoreGroup, params: AudioNotesSopParams) {
const values = this._values([coreGroup], params);
coreGroup.addAttribute(params.name, values[0].note);
if (isBooleanTrue(params.toctave)) {
coreGroup.addAttribute(params.octaveName, values[0].octave);
}
}
private _values(entities: CoreEntity[], params: AudioNotesSopParams) {
let increment = 1;
let i = 0;
const behavior = OUT_OF_RANGE_BEHAVIOR[params.outOfRangeBehavior];
const noteHolders = NotesBuilder.list(params.startOctave, params.endOctave);
const values: NoteHolder[] = [];
for (let k = 0; k < entities.length; k++) {
if (i >= noteHolders.length) {
switch (behavior) {
case OutOfRangeBehavior.BOUNCE: {
increment = -1;
i = noteHolders.length - 2;
break;
}
case OutOfRangeBehavior.RESTART: {
i = 0;
break;
}
}
}
if (behavior == OutOfRangeBehavior.BOUNCE) {
if (i == 0 && increment < 0) {
increment = +1;
i = 1;
}
}
const note = noteHolders[i];
values.push(note);
i += increment;
}
return values;
}
}