Skip to content

Commit

Permalink
generalized force sound generation, initial integration into Gravity …
Browse files Browse the repository at this point in the history
…Force Lab, see #181
  • Loading branch information
jbphet committed Oct 29, 2019
1 parent a82ab3e commit b774ce4
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 11 deletions.
8 changes: 8 additions & 0 deletions js/gravity-force-lab/model/GravityForceLabModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ define( require => {
phetioDocumentation: 'Whether or not to display the force using scientific notation'
} );

// @public (read-only) {Boolean} - whether or not the model is in the process of being reset
this.resetInProgressProperty = new BooleanProperty( false, {
tandem: tandem.createTandem( 'resetInProgressProperty' ),
phetioDocumentation: 'Whether or not a reset is occurring in the model'
} );

// pass initial masses and positions into the model
const massValue1 = 100; // mass in kg
const massValue2 = 400; // mass in kg
Expand Down Expand Up @@ -75,10 +81,12 @@ define( require => {

// @public
reset: function() {
this.resetInProgressProperty.set( true );
this.rulerPositionProperty.reset();
this.scientificNotationProperty.reset();
this.constantRadiusProperty.reset();
ISLCModel.prototype.reset.call( this );
this.resetInProgressProperty.set( false );
}
} );
} );
33 changes: 25 additions & 8 deletions js/gravity-force-lab/view/ForceSoundGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,27 @@ define( require => {
class ForceSoundGenerator extends SoundClip {

/**
* @param {GFLBModel} model
* @param {NumberProperty} forceProperty
* @param {Range} forceRange
* @param {BooleanProperty} resetInProgressProperty
* @param {Object} [options]
* @constructor
*/
constructor( model, options ) {
constructor( forceProperty, forceRange, resetInProgressProperty, options ) {

options = merge( {
initialOutputLevel: 0.7,
loop: true,
trimSilence: false

// {number} min and max playback rate, default to ~3 octaves
// TODO make this a range
minPlaybackRate: 1 / 3,
maxPlaybackRate: 3
}, options );

// these options must be set in order for the sound generation to work properly
options.loop = true;
options.trimSilence = false;

// options checking
assert && assert( !options || !options.loop || options.loop === true, 'must be a loop to work correctly' );

Expand All @@ -58,13 +66,22 @@ define( require => {
// function for starting the force sound or adjusting the volume
const forceListener = force => {

if ( !model.resetInProgressProperty.value ) {
if ( !resetInProgressProperty.value ) {

// calculate the playback rate based on the amount of force, see the design document for detailed explanation
const normalizedForce = Math.log( force / model.getMinForce() ) / Math.log( model.getMaxForce() / model.getMinForce() );
const normalizedForce = Math.log( force / forceRange.min ) / Math.log( forceRange.max / forceRange.min );
const centerForce = normalizedForce - 0.5;
const midiNote = PITCH_RANGE_IN_SEMI_TONES / 2 * centerForce + PITCH_CENTER_OFFSET;
const playbackRate = Math.pow( 2, midiNote / 12 );
console.log( '----------------' );
console.log( 'playbackRate = ' + playbackRate );

const normalizedForce2 = ( force - forceRange.min ) / forceRange.getLength();
console.log( 'normalizedForce2 = ' + normalizedForce2 );
const playbackRateAlt = options.minPlaybackRate + normalizedForce * ( options.maxPlaybackRate - options.minPlaybackRate );
console.log( 'playbackRateAlt = ' + playbackRateAlt );
const playbackRateAltAlt = options.minPlaybackRate + normalizedForce2 * ( options.maxPlaybackRate - options.minPlaybackRate );
console.log( 'playbackRateAltAlt = ' + playbackRateAltAlt );

this.setPlaybackRate( playbackRate );
this.setOutputLevel( this.nonFadedOutputLevel );
Expand All @@ -76,10 +93,10 @@ define( require => {
this.fadeCountdownTime = FADE_START_DELAY + FADE_TIME + DELAY_BEFORE_STOP;
}
};
model.forceProperty.lazyLink( forceListener );
forceProperty.lazyLink( forceListener );

// @private {function}
this.disposeForceSoundGenerator = () => { model.forceProperty.unlink( forceListener ); };
this.disposeForceSoundGenerator = () => { forceProperty.unlink( forceListener ); };
}

/**
Expand Down
28 changes: 25 additions & 3 deletions js/gravity-force-lab/view/GravityForceLabScreenView.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ define( require => {
const AccessiblePeer = require( 'SCENERY/accessibility/AccessiblePeer' );
const Bounds2 = require( 'DOT/Bounds2' );
const DefaultDirection = require( 'INVERSE_SQUARE_LAW_COMMON/view/DefaultDirection' );
const ForceSoundGenerator = require( 'GRAVITY_FORCE_LAB/gravity-force-lab/view/ForceSoundGenerator' );
const gravityForceLab = require( 'GRAVITY_FORCE_LAB/gravityForceLab' );
const GravityForceLabA11yStrings = require( 'GRAVITY_FORCE_LAB/gravity-force-lab/GravityForceLabA11yStrings' );
const GravityForceLabAlertManager = require( 'GRAVITY_FORCE_LAB/gravity-force-lab/view/GravityForceLabAlertManager' );
Expand All @@ -34,8 +35,10 @@ define( require => {
const MassPDOMNode = require( 'GRAVITY_FORCE_LAB/gravity-force-lab/view/MassPDOMNode' );
const ModelViewTransform2 = require( 'PHETCOMMON/view/ModelViewTransform2' );
const Node = require( 'SCENERY/nodes/Node' );
const Range = require( 'DOT/Range' );
const ResetAllButton = require( 'SCENERY_PHET/buttons/ResetAllButton' );
const ScreenView = require( 'JOIST/ScreenView' );
const soundManager = require( 'TAMBO/soundManager' );
const SpherePositionsPDOMNode = require( 'GRAVITY_FORCE_LAB/gravity-force-lab/view/SpherePositionsPDOMNode' );
const Vector2 = require( 'DOT/Vector2' );

Expand Down Expand Up @@ -156,7 +159,6 @@ define( require => {
thisElementName: AccessiblePeer.PRIMARY_SIBLING
} );


// a list of Properties to that, when changed, should trigger an update in descriptions in the MassControl
const propertiesToMonitorForDescriptionChanges = [ model.forceProperty, model.constantRadiusProperty ];

Expand Down Expand Up @@ -234,10 +236,20 @@ define( require => {
align: 'left'
} );

// @private - sound generation for the force sound
this.forceSoundGenerator = new ForceSoundGenerator(
model.forceProperty,
new Range( model.getMinForce(), model.getMaxForce() ),
model.resetInProgressProperty,
{ initialOutputLevel: 0.2 }
);
soundManager.addSoundGenerator( this.forceSoundGenerator );

const resetAllButton = new ResetAllButton( {
listener: function() {
listener: () => {
model.reset();
gravityForceLabRuler.reset();
this.forceSoundGenerator.reset();
},
scale: 0.81,
tandem: tandem.createTandem( 'resetAllButton' )
Expand Down Expand Up @@ -311,5 +323,15 @@ define( require => {

gravityForceLab.register( 'GravityForceLabScreenView', GravityForceLabScreenView );

return inherit( ScreenView, GravityForceLabScreenView );
return inherit( ScreenView, GravityForceLabScreenView, {

/**
* step the view
* @param {number} dt
* @public
*/
step( dt ) {
this.forceSoundGenerator.step( dt );
}
} );
} );

0 comments on commit b774ce4

Please sign in to comment.