diff --git a/js/gravity-force-lab/model/GravityForceLabModel.js b/js/gravity-force-lab/model/GravityForceLabModel.js index 7bbb1e1a..0ca6e5e7 100644 --- a/js/gravity-force-lab/model/GravityForceLabModel.js +++ b/js/gravity-force-lab/model/GravityForceLabModel.js @@ -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 @@ -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 ); } } ); } ); diff --git a/js/gravity-force-lab/view/ForceSoundGenerator.js b/js/gravity-force-lab/view/ForceSoundGenerator.js index 48bbfa39..87cf033a 100644 --- a/js/gravity-force-lab/view/ForceSoundGenerator.js +++ b/js/gravity-force-lab/view/ForceSoundGenerator.js @@ -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' ); @@ -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 ); @@ -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 ); }; } /** diff --git a/js/gravity-force-lab/view/GravityForceLabScreenView.js b/js/gravity-force-lab/view/GravityForceLabScreenView.js index 7e4493d9..024712c3 100644 --- a/js/gravity-force-lab/view/GravityForceLabScreenView.js +++ b/js/gravity-force-lab/view/GravityForceLabScreenView.js @@ -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' ); @@ -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' ); @@ -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 ]; @@ -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' ) @@ -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 ); + } + } ); } );