mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
b=923106 recompute frequency dependent parameters when OscillatorType changes r=padenot
mSquare, mTriangle, and mSaw are not initialized in the OscillatorNodeEngine constructor, just like they are not initialized when switching to OscillatorType::Sine. These parameters are initialized if and when switching to the OscillatorTypes that use them. mFinalFrequency, mNumberOfHarmonics, mSignalPeriod, mAmplitudeAtZero, mPhaseIncrement, mPhaseWrap are not initialized in the OscillatorNodeEngine constructor, just like they are not initialized immediately on switching OscillatorType. These parameters are initialized in UpdateParametersIfNeeded(), conditional on mRecomputeParameters. --HG-- extra : transplant_source : a%C1%83%03%03%5CJ%88%99j%A0%93%05%92%06%CA%D6%8B%00%21
This commit is contained in:
parent
1f3a3a581f
commit
fa7c6ec5b6
@ -70,16 +70,13 @@ public:
|
||||
, mDetune(0.f)
|
||||
, mType(OscillatorType::Sine)
|
||||
, mPhase(0.)
|
||||
, mFinalFrequency(0.0)
|
||||
, mNumberOfHarmonics(0)
|
||||
, mSignalPeriod(0.0)
|
||||
, mAmplitudeAtZero(0.0)
|
||||
, mPhaseIncrement(0.0)
|
||||
, mSquare(0.0)
|
||||
, mTriangle(0.0)
|
||||
, mSaw(0.0)
|
||||
, mPhaseWrap(0.0)
|
||||
, mRecomputeFrequency(true)
|
||||
// mSquare, mTriangle, and mSaw are not used for default type "sine".
|
||||
// They are initialized if and when switching to the OscillatorTypes that
|
||||
// use them.
|
||||
// mFinalFrequency, mNumberOfHarmonics, mSignalPeriod, mAmplitudeAtZero,
|
||||
// mPhaseIncrement, and mPhaseWrap are initialized in
|
||||
// UpdateParametersIfNeeded() when mRecomputeParameters is set.
|
||||
, mRecomputeParameters(true)
|
||||
, mCustomLength(0)
|
||||
{
|
||||
}
|
||||
@ -101,7 +98,7 @@ public:
|
||||
const AudioParamTimeline& aValue,
|
||||
TrackRate aSampleRate) MOZ_OVERRIDE
|
||||
{
|
||||
mRecomputeFrequency = true;
|
||||
mRecomputeParameters = true;
|
||||
switch (aIndex) {
|
||||
case FREQUENCY:
|
||||
MOZ_ASSERT(mSource && mDestination);
|
||||
@ -139,6 +136,7 @@ public:
|
||||
mCustomLength = 0;
|
||||
mCustom = nullptr;
|
||||
mPeriodicWave = nullptr;
|
||||
mRecomputeParameters = true;
|
||||
}
|
||||
// Update BLIT integrators with the new initial conditions.
|
||||
switch (mType) {
|
||||
@ -208,7 +206,7 @@ public:
|
||||
return mType == OscillatorType::Square || mType == OscillatorType::Triangle;
|
||||
}
|
||||
|
||||
void UpdateFrequencyIfNeeded(TrackTicks ticks, size_t count)
|
||||
void UpdateParametersIfNeeded(TrackTicks ticks, size_t count)
|
||||
{
|
||||
double frequency, detune;
|
||||
|
||||
@ -217,7 +215,7 @@ public:
|
||||
|
||||
// Shortcut if frequency-related AudioParam are not automated, and we
|
||||
// already have computed the frequency information and related parameters.
|
||||
if (simpleFrequency && simpleDetune && !mRecomputeFrequency) {
|
||||
if (simpleFrequency && simpleDetune && !mRecomputeParameters) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -233,7 +231,7 @@ public:
|
||||
}
|
||||
|
||||
mFinalFrequency = frequency * pow(2., detune / 1200.);
|
||||
mRecomputeFrequency = false;
|
||||
mRecomputeParameters = false;
|
||||
|
||||
// When using bipolar BLIT, we divide the signal period by two, because we
|
||||
// are using two BLIT out of phase.
|
||||
@ -308,7 +306,7 @@ public:
|
||||
void ComputeSine(float * aOutput, TrackTicks ticks, uint32_t aStart, uint32_t aEnd)
|
||||
{
|
||||
for (uint32_t i = aStart; i < aEnd; ++i) {
|
||||
UpdateFrequencyIfNeeded(ticks, i);
|
||||
UpdateParametersIfNeeded(ticks, i);
|
||||
|
||||
aOutput[i] = sin(mPhase);
|
||||
|
||||
@ -319,7 +317,7 @@ public:
|
||||
void ComputeSquare(float * aOutput, TrackTicks ticks, uint32_t aStart, uint32_t aEnd)
|
||||
{
|
||||
for (uint32_t i = aStart; i < aEnd; ++i) {
|
||||
UpdateFrequencyIfNeeded(ticks, i);
|
||||
UpdateParametersIfNeeded(ticks, i);
|
||||
// Integration to get us a square. It turns out we can have a
|
||||
// pure integrator here.
|
||||
mSquare += BipolarBLIT();
|
||||
@ -334,7 +332,7 @@ public:
|
||||
{
|
||||
float dcoffset;
|
||||
for (uint32_t i = aStart; i < aEnd; ++i) {
|
||||
UpdateFrequencyIfNeeded(ticks, i);
|
||||
UpdateParametersIfNeeded(ticks, i);
|
||||
// DC offset so the Saw does not ramp up to infinity when integrating.
|
||||
dcoffset = mFinalFrequency / mSource->SampleRate();
|
||||
// Integrate and offset so we get mAmplitudeAtZero sawtooth. We have a
|
||||
@ -350,7 +348,7 @@ public:
|
||||
void ComputeTriangle(float * aOutput, TrackTicks ticks, uint32_t aStart, uint32_t aEnd)
|
||||
{
|
||||
for (uint32_t i = aStart; i < aEnd; ++i) {
|
||||
UpdateFrequencyIfNeeded(ticks, i);
|
||||
UpdateParametersIfNeeded(ticks, i);
|
||||
// Integrate to get a square
|
||||
mSquare += BipolarBLIT();
|
||||
// Leaky integrate to get a triangle. We get too much dc offset if we don't
|
||||
@ -380,7 +378,7 @@ public:
|
||||
float rate = 1.0 / mSource->SampleRate();
|
||||
|
||||
for (uint32_t i = aStart; i < aEnd; ++i) {
|
||||
UpdateFrequencyIfNeeded(ticks, i);
|
||||
UpdateParametersIfNeeded(ticks, i);
|
||||
mPeriodicWave->waveDataForFundamentalFrequency(mFinalFrequency,
|
||||
lowerWaveData,
|
||||
higherWaveData,
|
||||
@ -484,7 +482,7 @@ public:
|
||||
float mTriangle;
|
||||
float mSaw;
|
||||
float mPhaseWrap;
|
||||
bool mRecomputeFrequency;
|
||||
bool mRecomputeParameters;
|
||||
nsRefPtr<ThreadSharedFloatArrayBufferList> mCustom;
|
||||
uint32_t mCustomLength;
|
||||
nsAutoPtr<WebCore::PeriodicWave> mPeriodicWave;
|
||||
|
@ -97,6 +97,7 @@ support-files =
|
||||
[test_oscillatorNode.html]
|
||||
[test_oscillatorNode2.html]
|
||||
[test_oscillatorNodeStart.html]
|
||||
[test_oscillatorTypeChange.html]
|
||||
[test_pannerNode.html]
|
||||
[test_pannerNodeAbove.html]
|
||||
[test_pannerNodeChannelCount.html]
|
||||
|
58
content/media/webaudio/test/test_oscillatorTypeChange.html
Normal file
58
content/media/webaudio/test/test_oscillatorTypeChange.html
Normal file
@ -0,0 +1,58 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test OscillatorNode type change after it has started and triangle phase</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="webaudio.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const bufferSize = 1024;
|
||||
|
||||
function startTest() {
|
||||
var ctx = new AudioContext();
|
||||
|
||||
var oscillator1 = ctx.createOscillator();
|
||||
oscillator1.connect(ctx.destination);
|
||||
oscillator1.start(0);
|
||||
|
||||
// Assuming the above Web Audio operations have already scheduled an event
|
||||
// to run in stable state and start the graph thread, schedule a subsequent
|
||||
// event to change the type of oscillator1.
|
||||
SimpleTest.executeSoon(function() {
|
||||
oscillator1.type = "triangle";
|
||||
|
||||
// Another triangle wave with -1 gain should cancel the first. This is
|
||||
// starting at the same time as the type change, assuming that the phase
|
||||
// is reset on type change. A negative frequency should achieve the same
|
||||
// as the -1 gain but for bug 916285.
|
||||
var oscillator2 = ctx.createOscillator();
|
||||
oscillator2.type = "triangle";
|
||||
oscillator2.start(0);
|
||||
|
||||
var processor = ctx.createScriptProcessor(bufferSize, 1, 0);
|
||||
oscillator1.connect(processor);
|
||||
var gain = ctx.createGain();
|
||||
gain.gain.value = -1;
|
||||
gain.connect(processor);
|
||||
oscillator2.connect(gain);
|
||||
|
||||
processor.onaudioprocess = function(e) {
|
||||
compareBuffers(e.inputBuffer.getChannelData(0),
|
||||
new Float32Array(bufferSize));
|
||||
e.target.onaudioprocess = null;
|
||||
SimpleTest.finish();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
startTest();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user