Skip to content

Commit 8528f53

Browse files
committed
move old message repeater to patch space
1 parent ebefc4c commit 8528f53

File tree

10 files changed

+168
-137
lines changed

10 files changed

+168
-137
lines changed

README.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
### Cycle-Patcher
22
A web based environment for real-time sound synthesis and pattern generation.
33

4-
### Build
4+
### Development
55
Install dependencies: `npm i`
66
Start local server: `npm start`
77
Navigate to `localhost:3001`
88

9+
### Build
10+
`npm run build`
11+
912
### Browser Requirements
10-
This project uses
13+
This project has a hard dependency on
1114
* [Web Components V1](https://caniuse.com/#feat=custom-elementsv1)
12-
* [Web Midi API](https://caniuse.com/#feat=midi)
13-
* [Broadcast Channel](https://caniuse.com/#feat=broadcastchannel) (to run a graphics window)
15+
16+
And feature level dependencies on
17+
* [Web Midi API](https://caniuse.com/#feat=midi) to interface with external synths and controllers
18+
* [Broadcast Channel](https://caniuse.com/#feat=broadcastchannel) to interface with a graphics window
1419

1520
### TODO
1621
* organize patcher components

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@
55
"main": "dist/index.js",
66
"scripts": {
77
"build:webpack": "webpack --mode=production --inline --colors --progress --content-base src",
8-
"build": "npm run clean; npm run build:webpack",
8+
"build:assets": "cp -r src/assets dist/assets",
9+
"build": "npm run clean; npm run build:webpack; npm run build:assets",
910
"clean": "rm -rf dist",
1011
"start": "webpack-dev-server --mode=development --inline --colors --progress --content-base src"
1112
},
1213
"devDependencies": {
1314
"html-webpack-plugin": "^3.2.0",
1415
"raw-loader": "^0.5.1",
15-
"webpack": "^4.20.2",
16+
"webpack": "^4.25.1",
1617
"webpack-cli": "^3.1.2",
17-
"webpack-dev-server": "^3.1.9"
18+
"webpack-dev-server": "^3.1.10"
1819
},
1920
"dependencies": {
2021
"three": "^0.92.0"

src/app/components/_util/componentManager.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import SynthNote from 'components/synth-note';
66
import button from 'components/button';
77
import PolyRythm from 'components/poly-rythm';
88
import PolyBox from 'components/poly-box';
9-
import MessageFitler from 'components/message-filter';
109
import Metronome from 'components/metronome';
1110
import ScaleSelector from 'components/scale-selector';
1211
import RouterOutlet from 'components/router-outlet';
@@ -43,6 +42,7 @@ import PatchLfo from 'components/patch-lfo';
4342
import PatchGrain from 'components/patch-grain';
4443
import PatchMessageSpread from 'components/patch-message-spread';
4544
import PatchMidiInterface from 'components/patch-midi-interface';
45+
import PatchMessageRepeater from 'components/patch-message-repeater';
4646

4747
const components = [
4848
app,
@@ -53,7 +53,6 @@ const components = [
5353
button,
5454
PolyRythm,
5555
PolyBox,
56-
MessageFitler,
5756
Metronome,
5857
ScaleSelector,
5958
RouterOutlet,
@@ -90,6 +89,7 @@ const components = [
9089
PatchGrain,
9190
PatchMessageSpread,
9291
PatchMidiInterface,
92+
PatchMessageRepeater,
9393
];
9494

9595
components.forEach(component => customElements.define(component.tag, component.element));

src/app/components/message-filter/index.js

Lines changed: 0 additions & 102 deletions
This file was deleted.

src/app/components/message-filter/message-filter.css

Lines changed: 0 additions & 8 deletions
This file was deleted.
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { AUDIO_TICK_MULTIPLIER } from 'services/midi/util';
2+
3+
function getMaxFromSchedules(schedules) {
4+
return schedules.reduce((max, schedule) => {
5+
if (schedule.audio > max.audio) { max.audio = schedule.audio; }
6+
if (schedule.midi > max.midi) { max.midi = schedule.midi; }
7+
return max;
8+
}, { audio: 0, midi: 0 });
9+
}
10+
11+
class RepeatStrategy {
12+
constructor(numRepeats, repeatFrequency, tempo, tickLength, time) {
13+
this.numRepeats = numRepeats;
14+
this.repeatFrequency = repeatFrequency;
15+
this.tempo = tempo;
16+
this.tickLength = tickLength;
17+
this.time = time;
18+
}
19+
20+
linear() {
21+
return new Array(this.numRepeats).fill(null)
22+
.map((n, index) => {
23+
const offset = index * this.tickLength * this.repeatFrequency;
24+
return {
25+
audio: this.time.audio + offset,
26+
midi: this.time.midi + offset * AUDIO_TICK_MULTIPLIER,
27+
};
28+
});
29+
}
30+
31+
rampDown(baseTime) {
32+
const baseAudio = baseTime ? baseTime.audio : this.time.audio;
33+
const baseMidi = baseTime ? baseTime.midi : this.time.midi;
34+
let diff = 4; // TODO: set as param
35+
const offsetList = new Array(this.numRepeats).fill(null)
36+
.map((n, index, array) => {
37+
let offsetAudio = 0;
38+
let offsetMidi = 0;
39+
if (index !== 0) {
40+
const lastValue = array[index - 1];
41+
const offset = lastValue + this.tickLength * this.repeatFrequency * diff;
42+
offsetAudio = offset;
43+
offsetMidi = offset * AUDIO_TICK_MULTIPLIER;
44+
diff /= 2; // TODO: set as param
45+
}
46+
return {
47+
audio: baseAudio + offsetAudio,
48+
midi: baseMidi + offsetMidi,
49+
};
50+
});
51+
return offsetList;
52+
}
53+
54+
rampUp(baseTime) {
55+
const baseAudio = baseTime ? baseTime.audio : this.time.audio;
56+
const baseMidi = baseTime ? baseTime.midi : this.time.midi;
57+
const rampDownSchedules = this.rampDown();
58+
const max = getMaxFromSchedules(rampDownSchedules);
59+
return rampDownSchedules.map(schedule => ({
60+
audio: max.audio - schedule.audio + baseAudio,
61+
midi: max.midi - schedule.midi + baseAudio,
62+
}));
63+
}
64+
65+
uShaped(baseTime) {
66+
const rampUpSchedules = this.rampUp(baseTime);
67+
const max = getMaxFromSchedules(rampUpSchedules);
68+
const rampDownSchedules = this.rampDown(max);
69+
return rampUpSchedules.concat(rampDownSchedules);
70+
}
71+
72+
nShaped(baseTime) {
73+
const rampDownSchedules = this.rampDown(baseTime);
74+
const max = getMaxFromSchedules(rampDownSchedules);
75+
const rampUpSchedules = this.rampUp(max);
76+
return rampDownSchedules.concat(rampUpSchedules);
77+
}
78+
}
79+
80+
export default function getTimeSchedules(numRepeats, repeatFrequency, repeatModifier, tempo, tickLength, time) {
81+
const repeatStrategy = new RepeatStrategy(numRepeats, repeatFrequency, tempo, tickLength, time);
82+
return repeatStrategy[repeatModifier]();
83+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import BaseComponent from 'components/_util/base-component';
2+
import Component from 'components/_util/component';
3+
import { PATCH_EVENT } from 'components/patch-space/modules/PatchEvent';
4+
import PatchAudioModel from 'components/patch-space/modules/PatchAudioModel';
5+
import PatchEventModel from 'components/patch-space/modules/PatchEventModel';
6+
import metronomeManager from 'services/metronome/metronomeManager';
7+
import getTimeSchedules from './RepeatStrategy';
8+
9+
const COMPONENT_NAME = 'patch-message-repeater';
10+
const style = require(`./${COMPONENT_NAME}.css`);
11+
const markup = require(`./${COMPONENT_NAME}.html`);
12+
13+
class PatchMessageRepeater extends BaseComponent {
14+
constructor() {
15+
super(style, markup);
16+
this.eventModel = new PatchEventModel(this.schedule.bind(this));
17+
this.audioModel = new PatchAudioModel('Repeater', this.eventModel, PATCH_EVENT.MESSAGE, PATCH_EVENT.MESSAGE);
18+
this.params = {
19+
numRepeats: 0,
20+
repeatFrequency: 1,
21+
repeatModifier: 'linear'
22+
};
23+
}
24+
setRepeatValue(value) {
25+
this.params.numRepeats = parseInt(value, 10);
26+
}
27+
28+
setRepeatFrequency(value) {
29+
this.params.repeatFrequency = parseInt(value, 10);
30+
}
31+
32+
setRepeatModifierValue(value) {
33+
this.params.repeatModifier = value;
34+
}
35+
36+
schedule(message) {
37+
const tempo = metronomeManager.getMetronome().getTempo();
38+
const tickLength = metronomeManager.getMetronome().getTickLength();
39+
const timeSchedules = getTimeSchedules(this.params.numRepeats, this.params.repeatFrequency, this.params.repeatModifier, tempo, tickLength, message.time);
40+
timeSchedules.forEach((timeSchedule) => {
41+
const modifiedMessage = { ...message, time: { ...timeSchedule } };
42+
this.eventModel.getOutlets().forEach(outlet => outlet.schedule(modifiedMessage));
43+
});
44+
}
45+
}
46+
47+
export default new Component(COMPONENT_NAME, PatchMessageRepeater);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.repeater-row {
2+
justify-content: space-between;
3+
align-items: center;
4+
margin: 4px 0;
5+
padding: 0 4px;
6+
}
7+
8+
.label {
9+
margin: 0 4px 0 0;
10+
}

src/app/components/message-filter/message-filter.html renamed to src/app/components/patch-message-repeater/patch-message-repeater.html

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,4 @@
1-
2-
<div class="message-filter">
3-
<p class="label">Pass:</p>
4-
<combo-box id="filter-select-box" change="setFilterValue">
5-
<option value="1" selected>1</option>
6-
<option value="2">2</option>
7-
<option value="3">3</option>
8-
<option value="4">4</option>
9-
<option value="6">6</option>
10-
<option value="8">8</option>
11-
</combo-box>
12-
1+
<div class="row repeater-row">
132
<p class="label">Rep freq:</p>
143
<combo-box id="repeat-frequency-select-box" change="setRepeatFrequency">
154
<option value="1" selected>1</option>
@@ -19,7 +8,9 @@
198
<option value="5">5</option>
209
<option value="6">6</option>
2110
</combo-box>
11+
</div>
2212

13+
<div class="row repeater-row">
2314
<p class="label">Rep N:</p>
2415
<combo-box id="repeat-select-box" change="setRepeatValue">
2516
<option value="1" selected>1</option>
@@ -31,13 +22,15 @@
3122
<option value="7">7</option>
3223
<option value="8">8</option>
3324
</combo-box>
25+
</div>
3426

27+
<div class="row repeater-row">
3528
<p class="label">Mode</p>
3629
<combo-box id="repeat-modifier" change="setRepeatModifierValue">
3730
<option value="linear" selected>linear</option>
38-
<option value="ramp-up">ramp-up</option>
39-
<option value="ramp-down">ramp-down</option>
40-
<option value="u-shaped">u-shaped</option>
41-
<option value="n-shaped">n-shaped</option>
31+
<option value="rampUp">ramp-up</option>
32+
<option value="rampDown">ramp-down</option>
33+
<option value="uShaped">u-shaped</option>
34+
<option value="nShaped">n-shaped</option>
4235
</combo-box>
4336
</div>

0 commit comments

Comments
 (0)