This commit adds basic support for importing, viewing and playing WAV
samples at different pitches.
Naming issues:
- We are using the Sample struct from Music.h, but also the Sample
struct from LibAudio (Audio::Sample). This is a little confusing.
set_recorded_sample() finds the peak sample and then divides all the
samples by that peak to get a guaranteed min/max of -1/1. This is nice
because our other waves are also bound between these values and we can
just do the same stuff. This is why we're using Audio::Sample, because
it uses floats, whereas Music.h's Sample uses i16s. It's a little
annoying that we have to use a mixture of floats and doubles though.
For playback at lower frequencies, we're calculating in-between samples,
rather than just playing samples multiple times. Basically, you get the
current sample and add the difference between the current sample and the
next sample multiplied by the distance from the current sample. This is
like drawing the hypotenuse of a right-angled triangle.
This was only used by HashTable::dump() which I used when doing the
first HashTable implementation. Removing this allows us to also remove
most includes of <AK/kstdio.h>.
This is not a bug currently, since the first column immediately starts
playing at startup and leaves no time for the user to put notes in it.
However, this is needed for exporting.
The piano roll data definitely belongs in AudioEngine along with the
note and time data. Now RollWidget only has GUI information, much like
the other widgets.
Note that this commit exacerbates issue #1158 which is caused by
RollWidget::paint_event().
I started adding things to a Draw namespace, but it somehow felt really
wrong seeing Draw::Rect and Draw::Bitmap, etc. So instead, let's rename
the library to LibGfx. :^)
This makes getting a pseudoterminal pair a little bit more portable.
Note that grantpt() and unlockpt() are currently no-ops, since we've
already granted the pseudoterminal slave to the calling user.
We also accept O_CLOEXEC to posix_openpt(), unlike some systems. :^)
FileUtils.cpp:131:34: error: cannot pass object of non-trivial type 'const AK::String' through variadic method; call will abort at runtime [-Wnon-pod-varargs]
Notice that we are calculating release time according to the level when
the note is turned off rather than the sustain level. Naively using the
sustain level gives very long release times if you turn the note off
during attack, whereas this deterministically gives the same release
time.
1. Make decay sample-granular rather than buffer-granular
You only have ~43 buffers per second which can make a jagged signal.
2. Calculate decay in milliseconds
Decay is supposed to be a time value.
I say "phony" because it's not actually playing the same frequency
twice, it's just playing the same frequency at a higher volume. We can
properly implement this later but at the moment it'll get in the way of
our ADSR implementation.
Now you can change the defaults in AudioEngine and not be totally
confused.
1. The default for m_octave_knob was actually upside-down.
2. The default for m_decay_knob wasn't respecting AudioEngine.
3. The default for m_delay_knob wasn't respecting AudioEngine.
I've been wanting to do this for a long time. It's time we start being
consistent about how this stuff works.
The new convention is:
- "LibFoo" is a userspace library that provides the "Foo" namespace.
That's it :^) This was pretty tedious to convert and I didn't even
start on LibGUI yet. But it's coming up next.