Robustify AudioContext code (thanks for the surprise, Chrome!)

This commit is contained in:
Jeff Parsons 2015-03-07 10:53:15 -08:00 • committed by jeffpar
commit 568c4e031e
6 changed files with 1628 additions and 1597 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -3,20 +3,22 @@ PCjs Sources
Structure Structure
--- ---
All the code for PCjs is contained in the following JavaScript files, which roughly divide the These JavaScript files divide PCjs functionality into major PC components. Most of the files are device
functionality into major PC components, aka "devices". However, not every file implements a device, components, implementing a specific device (or set of devices, in the case of [chipset.js](chipset.js)).
and "component" is an overloaded term, since *[Component](/docs/pcjs/component/)* is also the name of
the shared base class used for most PCjs devices (see [component.js](../../shared/lib/component.js)).
So it's best to refer to these files generically as "modules", and more specifically as "device modules"
whenever they implement a specific device (or set of devices, in the case of [*ChipSet*](/docs/pcjs/chipset/)).
Examples of non-device modules include UI modules like [panel.js](panel.js) and [debugger.js](debugger.js), Be aware that *component* is an overloaded term, since **Component** is also the name of the
and sub-modules like [x86opxx.js](x86opxx.js) and [x86func.js](x86func.js) that separate the CPU functionality shared base class in [component.js](../../shared/lib/component.js) used by most machine components.
of [x86.js](x86.js) into more manageable pieces. A few low-level components (eg, the **Memory** and **State** components, the Card class of the **Video**
component, the Color and Rectangle classes of the **Panel** component, etc) do not extend **Component**,
so don't assume that every PCjs object has access to [component.js](../../shared/lib/component.js) methods.
These modules should always be loaded or compiled in the order listed by the *pcJSFiles* property in Examples of non-device components include UI components like [panel.js](panel.js) and [debugger.js](debugger.js),
[package.json](../../../package.json), which includes all the necessary *shared* modules as well. and sub-components like [x86opxx.js](x86opxx.js) and [x86func.js](x86func.js) that separate the CPU
At the time of this writing, the order is: functionality of [x86.js](x86.js) into more manageable pieces.
These components should always be loaded or compiled in the order listed by the *pcJSFiles* property in
[package.json](../../../package.json), which includes all the necessary *shared* components as well.
At the time of this writing, the recommended order is:
* [shared/defines.js](../../shared/lib/defines.js) * [shared/defines.js](../../shared/lib/defines.js)
* [shared/diskapi.js](../../shared/lib/diskapi.js) * [shared/diskapi.js](../../shared/lib/diskapi.js)
@ -38,6 +40,8 @@ At the time of this writing, the order is:
* [pcjs/x86seg.js](x86seg.js) * [pcjs/x86seg.js](x86seg.js)
* [pcjs/x86cpu.js](x86cpu.js) * [pcjs/x86cpu.js](x86cpu.js)
* [pcjs/x86func.js](x86func.js) * [pcjs/x86func.js](x86func.js)
* [pcjs/x86opxx.js](x86opxx.js)
* [pcjs/x86op0f.js](x86op0f.js)
* [pcjs/x86modb.js](x86modb.js) * [pcjs/x86modb.js](x86modb.js)
* [pcjs/x86modw.js](x86modw.js) * [pcjs/x86modw.js](x86modw.js)
* [pcjs/x86modb16.js](x86modb16.js) * [pcjs/x86modb16.js](x86modb16.js)
@ -45,8 +49,6 @@ At the time of this writing, the order is:
* [pcjs/x86modb32.js](x86modb32.js) * [pcjs/x86modb32.js](x86modb32.js)
* [pcjs/x86modw32.js](x86modw32.js) * [pcjs/x86modw32.js](x86modw32.js)
* [pcjs/x86modsib.js](x86modsib.js) * [pcjs/x86modsib.js](x86modsib.js)
* [pcjs/x86opxx.js](x86opxx.js)
* [pcjs/x86op0f.js](x86op0f.js)
* [pcjs/chipset.js](chipset.js) * [pcjs/chipset.js](chipset.js)
* [pcjs/rom.js](rom.js) * [pcjs/rom.js](rom.js)
* [pcjs/ram.js](ram.js) * [pcjs/ram.js](ram.js)
@ -62,16 +64,16 @@ At the time of this writing, the order is:
* [pcjs/computer.js](computer.js) * [pcjs/computer.js](computer.js)
* [shared/embed.js](../../shared/lib/embed.js) * [shared/embed.js](../../shared/lib/embed.js)
Some of the modules *can* be reordered or even omitted (eg, [debugger.js](debugger.js) or Some of the components *can* be reordered or even omitted (eg, [debugger.js](debugger.js) or
[embed.js](../../shared/lib/embed.js)), but you should observe the following: [embed.js](../../shared/lib/embed.js)), but you should observe the following:
* [component.js](../../shared/lib/component.js) must be listed before any module that extends [*Component*](/docs/pcjs/component/) * [component.js](../../shared/lib/component.js) must be listed before any component that extends **Component**
* [panel.js](panel.js) should be loaded early to initialize the Control Panel (if any) as soon as possible * [panel.js](panel.js) should be loaded early to initialize the Control Panel (if any) as soon as possible
* [computer.js](computer.js) should be the last device module, as it supervises and notifies all the other device modules * [computer.js](computer.js) should be the last device component, as it supervises and notifies all the other device components
To minimize ordering requirements, the init() handlers and constructors of all modules should avoid To minimize ordering requirements, the init() handlers and constructors of all components should avoid
referencing other modules. Device modules should define an initBus() notification handler, which the referencing other components. Device components should define an initBus() notification handler, which the
[*Computer*](/docs/pcjs/computer/) will call after it has created/initialized the *Bus* object. *Computer* component will call after it has created/initialized the *Bus* component.
Features Features
--- ---

View file

@ -233,10 +233,14 @@ function ChipSet(parmsChipSet)
*/ */
this.fSpeaker = false; this.fSpeaker = false;
if (parmsChipSet['sound']) { if (parmsChipSet['sound']) {
if (window && 'webkitAudioContext' in window) { this.classAudio = this.contextAudio = null;
this.contextAudio = new window['webkitAudioContext'](); if (window) {
this.classAudio = window['AudioContext'] || window['webkitAudioContext'];
}
if (this.classAudio) {
this.contextAudio = new this.classAudio();
} else { } else {
if (DEBUG) this.log("webkitAudioContext not available"); if (DEBUG) this.log("AudioContext not available");
} }
} }
@ -4771,6 +4775,7 @@ ChipSet.prototype.parseSwitches = function(s, def)
ChipSet.prototype.setSpeaker = function(fOn) ChipSet.prototype.setSpeaker = function(fOn)
{ {
if (this.contextAudio) { if (this.contextAudio) {
try {
if (fOn !== undefined) { if (fOn !== undefined) {
this.fSpeaker = fOn; this.fSpeaker = fOn;
} else { } else {
@ -4789,20 +4794,38 @@ ChipSet.prototype.setSpeaker = function(fOn)
if (this.messageEnabled(Messages.SPEAKER)) this.printMessage("speaker set to " + freq + "hz", true); if (this.messageEnabled(Messages.SPEAKER)) this.printMessage("speaker set to " + freq + "hz", true);
} else { } else {
this.sourceAudio = this.contextAudio['createOscillator'](); this.sourceAudio = this.contextAudio['createOscillator']();
this.sourceAudio['type'] = "square"; // any of: "sine", "square", "sawtooth", "triangle", "custom" if (this.sourceAudio) {
if (typeof this.sourceAudio['type'] == "number") {
this.sourceAudio['type'] = 1; // deprecated: 0: "sine", 1: "square", 2: "sawtooth", 3: "triangle"
} else {
this.sourceAudio['type'] = "square";
}
this.sourceAudio['connect'](this.contextAudio['destination']); this.sourceAudio['connect'](this.contextAudio['destination']);
this.sourceAudio['frequency']['value'] = freq; this.sourceAudio['frequency']['value'] = freq;
if (this.messageEnabled(Messages.SPEAKER)) this.printMessage("speaker on at " + freq + "hz", true); if ('start' in this.sourceAudio) {
this.sourceAudio['start'](0); this.sourceAudio['start'](0);
} else {
this.sourceAudio['noteOn'](0); // deprecated: this.sourceAudio['noteOn'](0)
}
if (this.messageEnabled(Messages.SPEAKER)) this.printMessage("speaker on at " + freq + "hz", true);
}
} }
} else { } else {
if (this.sourceAudio) { if (this.sourceAudio) {
if ('stop' in this.sourceAudio) {
this.sourceAudio['stop'](0); this.sourceAudio['stop'](0);
} else {
this.sourceAudio['noteOff'](0); // deprecated: this.sourceAudio['noteOff'](0)
}
this.sourceAudio['disconnect'](); // QUESTION: is this automatic following a stop(), since this particular source cannot be started again? this.sourceAudio['disconnect'](); // QUESTION: is this automatic following a stop(), since this particular source cannot be started again?
delete this.sourceAudio; // QUESTION: ditto? delete this.sourceAudio; // QUESTION: ditto?
if (this.messageEnabled(Messages.SPEAKER)) this.printMessage("speaker off at " + freq + "hz", true); if (this.messageEnabled(Messages.SPEAKER)) this.printMessage("speaker off at " + freq + "hz", true);
} }
} }
} catch(e) {
this.notice("AudioContext exception: " + e.message);
this.contextAudio = null;
}
} else if (fOn) { } else if (fOn) {
this.printMessage("BEEP", Messages.SPEAKER); this.printMessage("BEEP", Messages.SPEAKER);
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long