Skip to content

Commit

Permalink
the bass hummer appears to work
Browse files Browse the repository at this point in the history
  • Loading branch information
moxious committed Jan 1, 2018
1 parent 1ff57cf commit b7106b9
Show file tree
Hide file tree
Showing 9 changed files with 138 additions and 19 deletions.
7 changes: 4 additions & 3 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class App extends React.Component {

this.state = {
world: null,
hummer: null,
conductor: new Conductor(),
};
}
Expand All @@ -23,6 +24,9 @@ class App extends React.Component {

componentDidMount() {
this.state.world = new BouncingBalls({ });
this.state.hummer = new Hummer(this.state.conductor);

this.state.hummer.start();

this.state.world.getPhysics().getBodies().forEach(body => {
body.sounds = new BodySound(this.state.conductor, body);
Expand All @@ -31,9 +35,6 @@ class App extends React.Component {
this.state.conductor.coordinate(this.state.world);

this.state.world.getRenderer().resize();

const h = new Hummer(this.state.conductor);
h.start();
}

render() {
Expand Down
2 changes: 1 addition & 1 deletion src/components/BouncingBallsControls.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export default class BouncingBallsControls extends React.Component {

addBody(incr) {
if (incr > 0) {
return this.state.app.world.addBody();
return this.state.app.world.addBody(this.state.app.conductor);
}

return this.state.app.world.removeBody();
Expand Down
89 changes: 89 additions & 0 deletions src/components/HummerControls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import * as React from 'react';

import RaisedButton from 'material-ui/RaisedButton';
import IconMenu from 'material-ui/IconMenu';
import MenuItem from 'material-ui/MenuItem';
import Divider from 'material-ui/Divider';
import Slider from 'material-ui/Slider';
import SurroundSound from 'material-ui/svg-icons/av/surround-sound';
import IconButton from 'material-ui/IconButton';


// import {Card, CardActions, CardHeader, CardText} from 'material-ui/Card';
import { ToolbarGroup } from 'material-ui/Toolbar';

export default class HummerControls extends React.Component {
constructor(props) {
super(props);

// Contains world, conductor.
this.state = {
app: props.app,
openMenu: false,
tempo: props.app.conductor.getTempo(),
};
}

start() { this.state.app.hummer.start(); }
stop() { this.state.app.hummer.stop(); }

adjustTempo(factor) {
const tempo = this.state.app.conductor.getTempo() * factor;
this.state.app.conductor.setTempo(Math.floor(tempo));
}

arpeggiate() {
this.state.app.hummer.setMode('arpeggiate');
}

tonics() {
this.state.app.hummer.setMode('tonic');
}

handleOnRequestChange = (value) => {
this.setState({
openMenu: value,
});
}

handleOpenMenu() {
console.log('Setting menu');
this.setState({
openMenu: true,
});
}


handleTempoSlider = (event, value) => {
this.setState({ tempo: value });
this.state.app.conductor.setTempo(value);
};

render() {
return (
<ToolbarGroup>
<IconMenu
iconButtonElement={<IconButton tooltip="Hummer"
tooltipPosition="top-center"><SurroundSound /></IconButton>}
onRequestChange={this.handleOnRequestChange}
open={this.state.openMenu}>
<MenuItem primaryText="Stop" onClick={(e) => this.stop(e)} />
<MenuItem primaryText="Start" onClick={(e) => this.start(e)} />
<Divider />
<Slider
min={5}
max={200}
step={5}
value={this.state.tempo}
onChange={this.handleTempoSlider}
/>
<MenuItem primaryText="Faster" onClick={(e) => this.adjustTempo(1.2)} />
<MenuItem primaryText="Slower" onClick={(e) => this.adjustTempo(0.8)} />
<Divider />
<MenuItem primaryText="Arpeggiate" onClick={(e) => this.arpeggiate(e)} />
<MenuItem primaryText="Tonics" onClick={(e) => this.tonics(e)} />
</IconMenu>
</ToolbarGroup>
);
}
}
2 changes: 2 additions & 0 deletions src/components/NPBToolbar.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react';
import BouncingBallsControls from './BouncingBallsControls';
import HummerControls from './HummerControls';
import { Toolbar } from 'material-ui/Toolbar';

export default class NPBToolbar extends React.Component {
Expand All @@ -14,6 +15,7 @@ export default class NPBToolbar extends React.Component {
render() {
return (
<Toolbar>
<HummerControls app={this.state.app}/>
<BouncingBallsControls app={this.state.app}/>
</Toolbar>
);
Expand Down
10 changes: 6 additions & 4 deletions src/model/World.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Physics from 'physicsjs';
import choosePalette from './Palette';
import BodySound from '../sound/BodySound';

/**
* A world is an abstract physics container full of bodies and interactions.
Expand All @@ -16,7 +17,7 @@ export default class World {
repalette() {
const p = choosePalette();

console.log('REPALETTE old ', this.palette, ' new ', p);
// console.log('REPALETTE old ', this.palette, ' new ', p);
this.palette = p;

this.getPhysics().getBodies().forEach(body => {
Expand All @@ -39,7 +40,6 @@ export default class World {
}

makeBody(world, renderer) {
const vert = Math.random() > 0.5;
const neg = Math.random() > 0.5;

let body = Physics.body('circle', {
Expand Down Expand Up @@ -73,8 +73,10 @@ export default class World {
return this.getPhysics().getBodies().length;
}

addBody() {
this.getPhysics().add(this.makeBody(this.getPhysics(), this.renderer));
addBody(conductor) {
const body = this.makeBody(this.getPhysics(), this.renderer);
body.sounds = new BodySound(conductor, body);
this.getPhysics().add(body);
}

removeBody() {
Expand Down
1 change: 0 additions & 1 deletion src/sound/ChordProgression.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ export default class ChordProgression {
}

this.activeSet = this.toneSets[this.index];
console.log('CP new activeSet', this.activeSet);
return this.activeSet;
}
};
8 changes: 5 additions & 3 deletions src/sound/Conductor.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default class Conductor {
this.tonic = props.tonic || 'C';
this.key = props.key || 'M';
this.tempo = props.tempo || 50;
this.octaves = props.octaves || ['2', '3', '4', '5'];
this.octaves = props.octaves || ['3', '4', '5'];
this.synth = props.synth || 'triangle';
this.muted = props.muted || false;
this.tones = Tonal.Chord.notes(this.getTonalChord());
Expand Down Expand Up @@ -127,6 +127,8 @@ export default class Conductor {
}

setTempo(tempo) {
if (!tempo || tempo < 2 || tempo > 250) { return; }
console.log('Tempo: ', this.tempo, ' => ', tempo);
this.tempo = tempo;
this.notify('tempo');
// Set master synth tempo.
Expand Down Expand Up @@ -161,10 +163,10 @@ export default class Conductor {
coordinate(world, replaceSynths = false) {
world.getPhysics().getBodies().forEach(body => {
if (body.sounds) {
console.log("coodinate/reassign");
// console.log("coodinate/reassign");
body.sounds.reassign(replaceSynths);
} else {
console.log('coordinate/new');
// console.log('coordinate/new');
body.sounds = new BodySound(this, body);
}
});
Expand Down
26 changes: 21 additions & 5 deletions src/sound/Hummer.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import * as Tonal from 'tonal';
import * as Tone from 'tone';
import Loop from './Loop';
import ChordProgression from './ChordProgression';

export default class Hummer extends Loop {
constructor(conductor) {
super(conductor);


this.octave = 2;
this.mode = 'tonic';
this.cp = ChordProgression.I_IV_V('C', 'M');
this.loopFrequency = '4n';
conductor.register(this);

console.log('Hummer CP ', this.cp);
}

setMode(mode) {
this.mode = mode;
}

onConductorChange(changeType, newValue, conductor){
if (changeType === 'tonic' || changeType === 'key') {
console.log('Changing hummer progression');
Expand All @@ -22,8 +27,19 @@ export default class Hummer extends Loop {

play(time) {
if (!this.conductor.muted) {
const tone = `${this.cp.getToneSet()[0]}2`;
console.log('Hummer play: ', tone, time);
const tonic = `${this.conductor.getTonic()}${this.octave}`;
const nextInArpeggio = `${this.cp.getToneSet()[0]}${this.octave}`;

let tone;

if (this.mode === 'tonic') {
tone = tonic;
} else {
tone = nextInArpeggio;
}

// console.log('Hummer play: ', tone, time);

this.synth.triggerAttackRelease(tone, '16n', time);
this.cp.advance();
}
Expand Down
12 changes: 10 additions & 2 deletions src/sound/Loop.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import * as Tone from 'tone';
export default class Loop {
constructor(conductor) {
this.conductor = conductor;
this.synth = this.conductor.makeSynth();
this.synth = this.conductor.makeSynth();
this.started = false;
}

getSynth() {
Expand All @@ -15,12 +16,19 @@ export default class Loop {
}

start() {
this.loop = new Tone.Loop(time => this.play(time), '16n');
if (this.started) {
console.log('Not starting an already running loop');
return;
}

this.started = true;
this.loop = new Tone.Loop(time => this.play(time), this.loopFrequency || '4n');
this.loop.start(this.startOn || '1m');
Tone.Transport.start(0);
}

stop() {
this.started = false;
if (!this.loop) {
throw new Error('Not started');
}
Expand Down

0 comments on commit b7106b9

Please sign in to comment.