Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
L
logging-scratch-gui
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
David Goessmann
logging-scratch-gui
Commits
d1d98337
Commit
d1d98337
authored
5 years ago
by
Paul Kaplan
Browse files
Options
Downloads
Patches
Plain Diff
Update docs and tests
parent
bb80fa49
No related branches found
No related tags found
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
src/containers/sound-editor.jsx
+16
-14
16 additions, 14 deletions
src/containers/sound-editor.jsx
src/lib/audio/audio-util.js
+23
-6
23 additions, 6 deletions
src/lib/audio/audio-util.js
test/unit/util/audio-util.test.js
+9
-9
9 additions, 9 deletions
test/unit/util/audio-util.test.js
with
48 additions
and
29 deletions
src/containers/sound-editor.jsx
+
16
−
14
View file @
d1d98337
...
...
@@ -10,7 +10,7 @@ import {
computeChunkedRMS
,
encodeAndAddSoundToVM
,
downsampleIfNeeded
,
backupDown
Sample
r
dropEveryOther
Sample
}
from
'
../lib/audio/audio-util.js
'
;
import
AudioEffects
from
'
../lib/audio/audio-effects.js
'
;
import
SoundEditorComponent
from
'
../components/sound-editor/sound-editor.jsx
'
;
...
...
@@ -138,7 +138,7 @@ class SoundEditor extends React.Component {
});
}
submitNewSamples
(
samples
,
sampleRate
,
skipUndo
)
{
return
downsampleIfNeeded
(
samples
,
sampleRate
,
this
.
resampleBufferToRate
)
return
downsampleIfNeeded
(
{
samples
,
sampleRate
}
,
this
.
resampleBufferToRate
)
.
then
(({
samples
:
newSamples
,
sampleRate
:
newSampleRate
})
=>
WavEncoder
.
encode
({
sampleRate
:
newSampleRate
,
...
...
@@ -208,9 +208,9 @@ class SoundEditor extends React.Component {
trimEnd
:
null
});
});
}
handleDeleteInverse
()
{
// Delete everything outside of the trimmers
const
{
samples
,
sampleRate
}
=
this
.
copyCurrentBuffer
();
const
sampleCount
=
samples
.
length
;
const
startIndex
=
Math
.
floor
(
this
.
state
.
trimStart
*
sampleCount
);
...
...
@@ -331,19 +331,21 @@ class SoundEditor extends React.Component {
const
sampleRateRatio
=
newRate
/
buffer
.
sampleRate
;
const
newLength
=
sampleRateRatio
*
buffer
.
samples
.
length
;
let
offlineContext
;
if
(
window
.
OfflineAudioContext
)
{
offlineContext
=
new
window
.
OfflineAudioContext
(
1
,
newLength
,
newRate
);
}
else
if
(
window
.
webkitOfflineAudioContext
)
{
try
{
// Try to use either OfflineAudioContext or webkitOfflineAudioContext to resample
// The constructors will throw if trying to resample at an unsupported rate
// (e.g. Safari/webkitOAC does not support lower than 44khz).
try
{
if
(
window
.
OfflineAudioContext
)
{
offlineContext
=
new
window
.
OfflineAudioContext
(
1
,
newLength
,
newRate
);
}
else
if
(
window
.
webkitOfflineAudioContext
)
{
offlineContext
=
new
window
.
webkitOfflineAudioContext
(
1
,
newLength
,
newRate
);
}
catch
{
if
(
newRate
===
(
buffer
.
sampleRate
/
2
))
{
return
resolve
(
backupDownSampler
(
buffer
,
newRate
));
}
return
reject
(
'
Could not resample
'
);
}
}
else
{
return
reject
(
'
No offline audio context
'
);
}
catch
{
// If no OAC available and downsampling by 2, downsample by dropping every other sample.
if
(
newRate
===
buffer
.
sampleRate
/
2
)
{
return
resolve
(
dropEveryOtherSample
(
buffer
));
}
return
reject
(
'
Could not resample
'
);
}
const
source
=
offlineContext
.
createBufferSource
();
const
audioBuffer
=
offlineContext
.
createBuffer
(
1
,
buffer
.
samples
.
length
,
buffer
.
sampleRate
);
...
...
This diff is collapsed.
Click to expand it.
src/lib/audio/audio-util.js
+
23
−
6
View file @
d1d98337
import
WavEncoder
from
'
wav-encoder
'
;
import
log
from
'
../log.js
'
;
const
SOUND_BYTE_LIMIT
=
10
*
1000
*
1000
;
// 10mb
...
...
@@ -60,7 +59,21 @@ const encodeAndAddSoundToVM = function (vm, samples, sampleRate, name, callback)
});
};
const
downsampleIfNeeded
=
(
samples
,
sampleRate
,
resampler
)
=>
{
/**
@typedef SoundBuffer
@type {Object}
@property {Float32Array} samples Array of audio samples
@property {number} sampleRate Audio sample rate
*/
/**
* Downsample the given buffer to try to reduce file size below SOUND_BYTE_LIMIT
* @param {SoundBuffer} buffer - Buffer to resample
* @param {function(SoundBuffer):Promise<SoundBuffer>} resampler - resampler function
* @returns {SoundBuffer} Downsampled buffer with half the sample rate
*/
const
downsampleIfNeeded
=
(
buffer
,
resampler
)
=>
{
const
{
samples
,
sampleRate
}
=
buffer
;
const
duration
=
samples
.
length
/
sampleRate
;
const
encodedByteLength
=
samples
.
length
*
2
;
/* bitDepth 16 bit */
// Resolve immediately if already within byte limit
...
...
@@ -76,8 +89,12 @@ const downsampleIfNeeded = (samples, sampleRate, resampler) => {
return
Promise
.
reject
(
'
Sound too large to save, refusing to edit
'
);
};
const
backupDownSampler
=
(
buffer
,
newRate
)
=>
{
log
.
warn
(
`Using backup down sampler for conversion from
${
buffer
.
sampleRate
}
to
${
newRate
}
`
);
/**
* Drop every other sample of an audio buffer as a last-resort way of downsampling.
* @param {SoundBuffer} buffer - Buffer to resample
* @returns {SoundBuffer} Downsampled buffer with half the sample rate
*/
const
dropEveryOtherSample
=
buffer
=>
{
const
newLength
=
Math
.
floor
(
buffer
.
samples
.
length
/
2
);
const
newSamples
=
new
Float32Array
(
newLength
);
for
(
let
i
=
0
;
i
<
newLength
;
i
++
)
{
...
...
@@ -85,7 +102,7 @@ const backupDownSampler = (buffer, newRate) => {
}
return
{
samples
:
newSamples
,
sampleRate
:
newRate
sampleRate
:
buffer
.
rate
/
2
};
};
...
...
@@ -94,5 +111,5 @@ export {
computeChunkedRMS
,
encodeAndAddSoundToVM
,
downsampleIfNeeded
,
backupDown
Sample
r
dropEveryOther
Sample
};
This diff is collapsed.
Click to expand it.
test/unit/util/audio-util.test.js
+
9
−
9
View file @
d1d98337
...
...
@@ -2,7 +2,7 @@ import {
computeRMS
,
computeChunkedRMS
,
downsampleIfNeeded
,
backupDown
Sample
r
dropEveryOther
Sample
}
from
'
../../../src/lib/audio/audio-util
'
;
describe
(
'
computeRMS
'
,
()
=>
{
...
...
@@ -60,38 +60,38 @@ describe('downsampleIfNeeded', () => {
const
sampleRate
=
44100
;
test
(
'
returns given data when no downsampling needed
'
,
async
()
=>
{
samples
.
length
=
1
;
const
res
=
await
downsampleIfNeeded
(
samples
,
sampleRate
,
null
);
const
res
=
await
downsampleIfNeeded
(
{
samples
,
sampleRate
}
,
null
);
expect
(
res
.
samples
).
toEqual
(
samples
);
expect
(
res
.
sampleRate
).
toEqual
(
sampleRate
);
});
test
(
'
downsamples to 22050 if that puts it under the limit
'
,
async
()
=>
{
samples
.
length
=
44100
*
3
*
60
;
const
resampler
=
jest
.
fn
(()
=>
'
TEST
'
);
const
res
=
await
downsampleIfNeeded
(
samples
,
sampleRate
,
resampler
);
const
res
=
await
downsampleIfNeeded
(
{
samples
,
sampleRate
}
,
resampler
);
expect
(
resampler
).
toHaveBeenCalledWith
({
samples
,
sampleRate
},
22050
);
expect
(
res
).
toEqual
(
'
TEST
'
);
});
test
(
'
fails if resampling would not put it under the limit
'
,
async
()
=>
{
samples
.
length
=
44100
*
4
*
60
;
try
{
await
downsampleIfNeeded
(
samples
,
sampleRate
,
null
);
await
downsampleIfNeeded
(
{
samples
,
sampleRate
}
,
null
);
}
catch
(
e
)
{
expect
(
e
).
toEqual
(
'
Sound too large to save, refusing to edit
'
);
}
});
});
describe
(
'
backupDown
Sample
r
'
,
()
=>
{
describe
(
'
dropEveryOther
Sample
'
,
()
=>
{
const
buffer
=
{
samples
:
[
1
,
0
,
1
,
0
,
1
,
0
,
1
],
samples
:
[
1
,
0
,
2
,
0
,
3
,
0
],
sampleRate
:
2
};
test
(
'
result is half the length
'
,
()
=>
{
const
{
samples
}
=
backupDown
Sample
r
(
buffer
,
1
);
const
{
samples
}
=
dropEveryOther
Sample
(
buffer
,
1
);
expect
(
samples
.
length
).
toEqual
(
Math
.
floor
(
buffer
.
samples
.
length
/
2
));
});
test
(
'
result contains only even-index items
'
,
()
=>
{
const
{
samples
}
=
backupDown
Sample
r
(
buffer
,
1
);
expect
(
samples
.
every
(
v
=>
v
===
1
)).
toBe
(
true
);
const
{
samples
}
=
dropEveryOther
Sample
(
buffer
,
1
);
expect
(
samples
).
toEqual
(
new
Float32Array
([
1
,
2
,
3
])
);
});
});
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment