Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions gallium-live/src/BPMSelector.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ const Input = styled.input`
font-family: monospace;
cursor: pointer;
outline: none;
color: #252525;
color: white;
&:active,
&:hover {
box-shadow: 0 0 0 1px #252525;
box-shadow: 0 0 0 1px white;
}
margin-left: 10px;
`;
154 changes: 108 additions & 46 deletions gallium-live/src/Editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import * as Playback from "./playback";
import * as AppActions from "./app_actions";
import { BPMSelector } from "./BPMSelector";
import { ToggleInvert } from "./ToggleInvert";
import * as Shader from "./shader";

type OwnProps = {};

Expand Down Expand Up @@ -44,7 +45,9 @@ export class _Editor extends React.Component<
};
}

textarea: ?HTMLTextAreaElement;
textarea: HTMLTextAreaElement;

textCanvas: HTMLCanvasElement;

componentDidMount() {
this.props.dispatch(AppActions.initialize());
Expand All @@ -57,10 +60,14 @@ export class _Editor extends React.Component<
}

onChange = (e: *) => {
const text = e.target.value;
this.setState({
text: e.target.value
text
});
this.updateABT(e.target.value);
this.updateABT(text);
if (this.textCanvas) {
this.drawText(text);
}
};

updateABT(text: string) {
Expand Down Expand Up @@ -112,50 +119,81 @@ export class _Editor extends React.Component<
}
};

onTextareaRefLoad = (ref: HTMLTextAreaElement) => {
this.textarea = ref;
if (!this.textarea) {
registerContent = (ref: HTMLElement) => {
if (!ref) {
return;
}
const canvas: HTMLCanvasElement = (ref.children[0]: any);
const textCanvas: HTMLCanvasElement = (ref.children[1]: any);

(textCanvas.width = Math.max(window.innerHeight, window.innerWidth)),
(textCanvas.height = textCanvas.width);

this.textCanvas = textCanvas;
this.drawText(this.state.text);
Shader.registerWebGL({ canvas, textCanvas });
};

registerTextarea = (ref: HTMLTextAreaElement) => {
if (!ref) {
return;
}
this.textarea.focus();
ref.focus();
this.textarea = ref;
};

drawText(text: string) {
const ctx = this.textCanvas.getContext("2d");
ctx.clearRect(0, 0, this.textCanvas.width, this.textCanvas.height);
ctx.font = "16px mono";
ctx.fillStyle = "white";
const lineHeight = ctx.measureText("M").width * 1.8;
const lines = text.split("\n");
let y = 0;
for (const line of lines) {
ctx.fillText(line, 0, y);
y += lineHeight;
}
}

render() {
const barStyle = this.state.error ? "dotted" : "solid";
return (
<Container
isInitialized={this.state.isInitialized}
style={{ filter: this.props.invert ? "invert()" : "" }}
>
<Pane>
<PaneChild>
<Description>gallium.live</Description>
</PaneChild>
<PaneChild>
<Link href="https://github.com/sleexyz/gallium">source</Link>
</PaneChild>
</Pane>
<Content>
<Content innerRef={this.registerContent}>
<Canvas />
<TextCanvas />
<Textarea
id="gallium-textarea"
onChange={this.onChange}
onKeyPress={this.onKeyPress}
value={this.state.text}
innerRef={this.onTextareaRefLoad}
innerRef={this.registerTextarea}
barStyle={barStyle}
/>
<Pane style={{ top: 0 }}>
<PaneChild>
<Description>gallium.live</Description>
</PaneChild>
<PaneChild>
<Link href="https://github.com/sleexyz/gallium">source</Link>
</PaneChild>
</Pane>
<Pane style={{ bottom: 0 }}>
<PaneChild>
<BPMSelector />
</PaneChild>
<PaneChild>
<ToggleInvert />
</PaneChild>
<PaneChild>
<OutputSelector />
</PaneChild>
</Pane>
</Content>
<Pane>
<PaneChild>
<BPMSelector />
</PaneChild>
<PaneChild>
<ToggleInvert />
</PaneChild>
<PaneChild>
<OutputSelector />
</PaneChild>
</Pane>
</Container>
);
}
Expand All @@ -168,21 +206,25 @@ export const Container: React$ComponentType<{
}> = styled.div`
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
opacity: ${props => (props.isInitialized ? 1 : 0)};
transition: opacity 500ms ease-in-out;
background-color: white;
`;

const paneHeight = 60;

const Pane = styled.div`
flex: 0 1 auto;
min-height: 50px;
height: ${paneHeight}px;
display: flex;
width: 100%;
justify-content: flex-end;
align-items: center;
padding: 0px 20px;
${Styles.transition};
position: fixed;
background-color: transparent;
z-index: 1;
pointer-events: none;
color: white;
mix-blend-mode: exclusion;
opacity: 0.5;
&:hover {
opacity: 1;
Expand All @@ -191,34 +233,54 @@ const Pane = styled.div`

const PaneChild = styled.div`
padding: 10px 20px;
pointer-events: all;
`;

const Content = styled.div`
padding: 10vh 10vw;
flex-grow: 1;
flex-shrink: 0;
align-items: center;
background-color: transparent;
height: 100%;
width: 100%;
position: absolute;
display: flex;
background-color: white;
justify-content: center;
align-items: center;
`;

const Canvas = styled.canvas`
position: absolute;
height: 100%;
width: 100%;
margin: 0;
padding: 0;
top: 0;
left: 0;
background-color: black;
`;

const TextCanvas = styled.canvas`
display: none;
`;

export const Textarea: React.ComponentType<{
barStyle: string
}> = styled.textarea`
${Styles.transition};
border: 0;
font-size: 16px;
background-color: transparent;
margin: 0;
flex-grow: 1;
background-color: transparent;
font-family: monospace;
outline: none;
padding: 0;
padding-left: 0.2em;
border-left: 1px ${props => props.barStyle} #000;
opacity: 0.75;
&:focus {
opacity: 1;
}
border-left: 1px ${props => props.barStyle} #fff;
opacity: 1;
width: calc(100% - 10px);
margin-left: 10px;
color: white;
mix-blend-mode: exclusion;
height: calc(100% - 2*${paneHeight}px);
z-index: 1;
`;

const Description = styled.div`
Expand Down
4 changes: 2 additions & 2 deletions gallium-live/src/OutputSelector.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ const Selector = styled.select`
font-family: monospace;
cursor: pointer;
outline: none;
color: #252525;
color: white;
&:active,
&:hover {
box-shadow: 0 0 0 1px #252525;
box-shadow: 0 0 0 1px #white;
}
`;
9 changes: 8 additions & 1 deletion gallium-live/src/playback.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ function getBeatLength(bpm: number): number {
return 1000 * 60 / bpm;
}

//invariant: kickQueue is ordered by timestamp
window.kickQueue = [];

export class Player {
+state: AppState;

Expand All @@ -23,7 +26,6 @@ export class Player {
now + (event.start - this.state.beat) * getBeatLength(this.state.bpm);
const timestampOff =
now + (event.end - this.state.beat) * getBeatLength(this.state.bpm) - 1;

this.state.output.send(
MIDIUtils.noteOn({
channel: event.value.channel,
Expand All @@ -41,6 +43,11 @@ export class Player {
}),
timestampOff
);
if (event.value.pitch === 127) {
window.kickQueue.push({ value: 1.0, timestamp: timestampOn });
const kickOff = timestampOn + Math.min(timestampOff - timestampOn, 30);
window.kickQueue.push({ value: 0.0, timestamp: kickOff });
}
}

queryAndSend(): void {
Expand Down
Loading