Kaynağa Gözat

Add nonlinear sliders; show values

master
Fen Dweller 4 yıl önce
ebeveyn
işleme
d678ac9416
10 değiştirilmiş dosya ile 209 ekleme ve 52 silme
  1. +9
    -3
      src/audio.ts
  2. +74
    -0
      src/components/NodeNumberProp.vue
  3. +14
    -24
      src/components/NodeProps.vue
  4. +80
    -0
      src/components/NodeRangeProp.vue
  5. +6
    -1
      src/filters/HighpassFilter.ts
  6. +6
    -1
      src/filters/LowpassFilter.ts
  7. +7
    -14
      src/sources/IntervalSource.ts
  8. +1
    -9
      src/sources/LoopingSource.ts
  9. +2
    -0
      src/sources/PremadeSources.ts
  10. +10
    -0
      src/sources/Source.ts

+ 9
- 3
src/audio.ts Dosyayı Görüntüle

@@ -48,18 +48,24 @@ export abstract class Node {
constructor(public name: string) {}
}

export type NumberMetadata = {
export type PropMetadata = {
name: string;
};

export type NumberMetadata = PropMetadata & {
min: number;
max: number;
format?: (value: number) => string;
map?: (value: number) => number;
unmap?: (value: number) => number;
};

export type RangeMetadata = {
name: string;
export type RangeMetadata = PropMetadata & {
min: number;
max: number;
format?: (value: number) => string;
map?: (value: number) => number;
unmap?: (value: number) => number;
};

export const exposedMetadataNumber = Symbol("exposedNumber");


+ 74
- 0
src/components/NodeNumberProp.vue Dosyayı Görüntüle

@@ -0,0 +1,74 @@
<template>
<div class="node-prop">
<div class="prop-name">
{{ metadata.name }} - {{ metadata.format(mappedValue) }}
</div>
<Slider
v-model="mappedValue"
:min="metadata.map ? metadata.map(metadata.min) : metadata.min"
:max="metadata.map ? metadata.map(metadata.max) : metadata.max"
:step="-1"
:showTooltip="'drag'"
:format="metadata.format"
:options="test"
/>
</div>
</template>

<script lang="ts">
import { NumberMetadata } from "@/audio";
import { Options, Vue } from "vue-class-component";
import Slider from "@vueform/slider";
import { Node } from "@/audio";

@Options({
props: {
node: Node,
propKey: String,
metadata: {},
},
components: {
Slider,
},
})
export default class NodeNumberProp extends Vue {
propKey!: string;
type!: string;
node!: Record<string, number>;
metadata!: NumberMetadata & { key: string };

// it still animates ?????
// this fixes logarithmic sliders
// Why????
// ???????????
// ???????????????????
test = { animate: false };
get mappedValue(): number {
let result: number = this.node[this.metadata.key];
if (this.metadata.map) {
result = this.metadata.map(result);
}

return result;
}

set mappedValue(value: number) {
if (this.metadata.unmap) {
value = this.metadata.unmap(value);
}

this.node[this.metadata.key] = value;
}
}
</script>

<style scoped>
.node-prop {
margin: 20px;
user-select: none;
}
.prop-name {
font-size: 150%;
margin-bottom: 4px;
}
</style>

+ 14
- 24
src/components/NodeProps.vue Dosyayı Görüntüle

@@ -1,31 +1,17 @@
<template>
<div class="node-props">
<div
class="node-prop"
<node-number-prop
v-for="(metadata, index) in numberProps"
:node="node"
:key="index"
>
<div class="prop-name">{{ metadata.name }}</div>
<Slider
v-model="node[metadata.key]"
:min="metadata.min"
:max="metadata.max"
:step="-1"
:showTooltip="'drag'"
:format="metadata.format"
/>
</div>
<div class="node-prop" v-for="(metadata, index) in rangeProps" :key="index">
<div class="prop-name">{{ metadata.name }}</div>
<Slider
v-model="node[metadata.key]"
:min="metadata.min"
:max="metadata.max"
:step="-1"
:showTooltip="'drag'"
:format="metadata.format"
/>
</div>
:metadata="metadata"
/>
<node-range-prop
v-for="(metadata, index) in rangeProps"
:node="node"
:key="index"
:metadata="metadata"
/>
</div>
</template>

@@ -39,6 +25,8 @@ import {
import { Options, Vue } from "vue-class-component";
import Slider from "@vueform/slider";
import { Node } from "@/audio";
import NodeNumberProp from "@/components/NodeNumberProp.vue";
import NodeRangeProp from "@/components/NodeRangeProp.vue";

@Options({
props: {
@@ -46,6 +34,8 @@ import { Node } from "@/audio";
},
components: {
Slider,
NodeNumberProp,
NodeRangeProp,
},
})
export default class NodeProps extends Vue {


+ 80
- 0
src/components/NodeRangeProp.vue Dosyayı Görüntüle

@@ -0,0 +1,80 @@
<template>
<div class="node-prop">
<div class="prop-name">
{{ metadata.name }} - {{ metadata.format(mappedValue[0]) }}-{{
metadata.format(mappedValue[1])
}}
</div>
<Slider
v-model="mappedValue"
:min="metadata.map ? metadata.map(metadata.min) : metadata.min"
:max="metadata.map ? metadata.map(metadata.max) : metadata.max"
:step="-1"
:showTooltip="'drag'"
:format="metadata.format"
:options="test"
/>
</div>
</template>

<script lang="ts">
import { NumberMetadata } from "@/audio";
import { Options, Vue } from "vue-class-component";
import Slider from "@vueform/slider";
import { Node } from "@/audio";

@Options({
props: {
node: Node,
propKey: String,
metadata: {},
},
components: {
Slider,
},
})
export default class NodeRangeProp extends Vue {
propKey!: string;
type!: string;
node!: Record<string, [number, number]>;
metadata!: NumberMetadata & { key: string };

// it still animates ?????
// this fixes logarithmic sliders
// Why????
// ???????????
// ???????????????????
test = { animate: false };
get mappedValue(): [number, number] {
let result: [number, number] = this.node[this.metadata.key];
if (this.metadata.map) {
result = [this.metadata.map(result[0]), this.metadata.map(result[1])];
}

return result;
}

set mappedValue(value: [number, number]) {
if (this.metadata.unmap) {
value = [this.metadata.unmap(value[0]), this.metadata.unmap(value[1])];
}

const old = this.node[this.metadata.key];

// this was causing an infinite loop
if (old[0] != value[0] || old[1] != value[1])
this.node[this.metadata.key] = [value[0], value[1]];
}
}
</script>

<style scoped>
.node-prop {
margin: 20px;
user-select: none;
}
.prop-name {
font-size: 150%;
margin-bottom: 4px;
}
</style>

+ 6
- 1
src/filters/HighpassFilter.ts Dosyayı Görüntüle

@@ -8,7 +8,12 @@ export class HighpassFilter extends Filter {
name: "Cutoff Frequency",
min: 10,
max: 10000,
format: (value: number) => value + "Hz",
format: (value: number) =>
Math.pow(2, value).toLocaleString(undefined, {
maximumFractionDigits: 0,
}) + "Hz",
map: (value: number) => Math.log(value) / Math.log(2),
unmap: (value: number) => Math.pow(2, value),
})
public cutoff = 500;



+ 6
- 1
src/filters/LowpassFilter.ts Dosyayı Görüntüle

@@ -8,7 +8,12 @@ export class BiquadFilter extends Filter {
name: "Cutoff Frequency",
min: 10,
max: 10000,
format: (value: number) => value + "Hz",
format: (value: number) =>
Math.pow(2, value).toLocaleString(undefined, {
maximumFractionDigits: 0,
}) + "Hz",
map: (value: number) => Math.log(value) / Math.log(2),
unmap: (value: number) => Math.pow(2, value),
})
public cutoff = 1000;



+ 7
- 14
src/sources/IntervalSource.ts Dosyayı Görüntüle

@@ -1,29 +1,22 @@
import { Source } from "./Source";
import { exposedNumber, context, exposedRange } from "../audio";
import { context, exposedRange } from "../audio";

export class IntervalSource extends Source {
kind = "Interval";

@exposedNumber({
name: "Pitch",
min: 0.25,
max: 4,
format: (value: number) => Math.round(value * 100) + "%",
})
public pitch = 1;

//
@exposedNumber({
@exposedRange({
name: "Interval",
min: 0.25,
max: 30,
max: 300,
format: (value: number) => {
return (
value.toLocaleString(undefined, {
Math.pow(2, value).toLocaleString(undefined, {
maximumFractionDigits: 2,
}) + "s"
);
},
map: (value: number) => Math.log(value) / Math.log(2),
unmap: (value: number) => Math.pow(2, value),
})
public interval: [number, number] = [4, 6];

@@ -33,7 +26,7 @@ export class IntervalSource extends Source {
max: 1,
format: (value: number) => {
if (value < 0) {
return Math.round(value * 100) + "L";
return Math.round(-value * 100) + "L";
} else if (value > 0) {
return Math.round(value * 100) + "R";
} else {


+ 1
- 9
src/sources/LoopingSource.ts Dosyayı Görüntüle

@@ -1,5 +1,5 @@
import { Source } from "./Source";
import { context, exposedNumber } from "../audio";
import { context } from "../audio";

export class LoopingSource extends Source {
kind = "Looping";
@@ -7,14 +7,6 @@ export class LoopingSource extends Source {
private started = false;
private running = false;

@exposedNumber({
name: "Pitch",
min: 0.25,
max: 4,
format: (value: number) => Math.round(value * 100) + "%",
})
public pitch = 1;

constructor(name: string) {
super(name);
}


+ 2
- 0
src/sources/PremadeSources.ts Dosyayı Görüntüle

@@ -14,6 +14,8 @@ export function makeGlorps(): Source {
source.loadSound("bowels-churn-safe");
source.loadSound("bowels-churn-danger");

console.log(source);

return source;
}



+ 10
- 0
src/sources/Source.ts Dosyayı Görüntüle

@@ -28,6 +28,16 @@ export abstract class Source extends Node {
})
public volume = 1;

@exposedNumber({
name: "Pitch",
min: 0.25,
max: 4,
format: (value: number) => Math.round(Math.pow(4, value) * 100) + "%",
map: (value: number) => Math.log(value) / Math.log(4),
unmap: (value: number) => Math.pow(4, value),
})
public pitch = 1;

constructor(name: string) {
super(name);
this.gain = context.createGain();


Yükleniyor…
İptal
Kaydet