Age | Commit message (Collapse) | Author |
|
Playback can resume after encountering loader errors (though not
always). Ideally, these should be visible to the user and the loader
state should be reset after encountering such errors. This patch
also has the side effect of not crashing on seek when playing MP3 files
(However, it still does not seek to the correct location) :^)
|
|
The current sample count is already reported like that, so this fixes a
mismatch between current and total. In the future, we should look into
abstracting this away properly instead of requiring the user to think of
converting it manually everywhere.
|
|
If we failed to decode a sample we'd presumably want to tell the user,
and we definitely don't want to just go into another round of decoding
somewhere in the middle of a broken sample.
|
|
|
|
This was unintuitive, and only useful in a few cases. In the majority,
users had to immediately call `stop()`, and several who did want the
timer started would call `start()` on it immediately anyway. Case in
point: There are only two places I had to add a manual `start()`.
|
|
Rip that bandaid off!
This does the following, in one big, awkward jump:
- Replace all uses of `set_main_widget<Foo>()` with the `try` version.
- Remove `set_main_widget<Foo>()`.
- Rename the `try` version to just be `set_main_widget` because it's now
the only one.
The majority of places that call `set_main_widget<Foo>()` are inside
constructors, so this unfortunately gives us a big batch of new
`release_value_but_fixme_should_propagate_errors()` calls.
|
|
Otherwise running "SoundPlayer --help" on the terminal tries to open a
file named "--help".
|
|
These instances were detected by searching for files that include
Kernel/Debug.h, but don't match the regex:
\\b(acos|acosh|asin|asinh|atan|atan2|atanh|cbrt|ceil|cos|cosh|E|exp|exp2
|fabs|fmod|hypot|log|log10|log2|NaN|Pi|pow|product_even|product_odd|rema
inder|round_to|rsqrt|sin|sincos|sinh|sqrt|Sqrt1_2|Sqrt2|tan|tanh)\\b
(Without the linebreaks.)
This regex is pessimistic, so there might be more files that don't
actually use any math functions.
In theory, one might use LibCPP to detect things like this
automatically, but let's do this one step after another.
|
|
|
|
This generally seems like a better name, especially if we somehow also
need a better name for "read the entire buffer, but not the entire file"
somewhere down the line.
|
|
We have a new, improved string type coming up in AK (OOM aware, no null
state), and while it's going to use UTF-8, the name UTF8String is a
mouthful - so let's free up the String name by renaming the existing
class.
Making the old one have an annoying name will hopefully also help with
quick adoption :^)
|
|
|
|
|
|
When the visualization is set to "Album Cover", the player will now try
to load the embedded image. On failure, it defaults to a "Cover" image
file in the directory.
In Player::play_file_path, file_name_changed now needs to be executed
after that the loader have been set, to get the correct image.
|
|
This patch will switch cursor to DragCopy when a user enters a widget
while dragging file(s), giving them a visual clue that it *might* be
dropped into this widget.
This is a rather naive approach, as the cursor icon will change for any
kind of file, as currently programs don't know the drag contents before
dropping it. But after all I think it's better than nothing. :^)
|
|
Otherwise, we end up propagating those dependencies into targets that
link against that library, which creates unnecessary link-time
dependencies.
Also included are changes to readd now missing dependencies to tools
that actually need them.
|
|
|
|
`aplay` and two files of `SoundPlayer` were relying on the include of
`LibCore/File.h` by `Loader.h`.
|
|
Also make the path parameter a StringView, since that's what gets passed
in.
|
|
And adjust some GML properties. Since a808cfa, splitters grow
opportunistically. Setting them to fixed sizes now quite literally
fixes them in place. Fixes immovable splitters missed in the
aforementioned commit.
|
|
The new layout system conveniently calculates these for us now.
In the case of Mandelbrot where it needs to be overriden, make
sure to disable obey min widget size first. In EmojiInputDialog's
case, the window needs to be resized instead to center correctly.
|
|
That's the standard naming convention, but I didn't follow it when
originally creating LibDSP and nobody corrected me, so here I am one
year later :^)
|
|
The automatic nomenclature change for IPC sockets got this one wrong.
|
|
Each of these strings would previously rely on StringView's char const*
constructor overload, which would call __builtin_strlen on the string.
Since we now have operator ""sv, we can replace these with much simpler
versions. This opens the door to being able to remove
StringView(char const*).
No functional changes.
|
|
|
|
|
|
This looks nicer in every way imaginable.
|
|
|
|
This has been overkill from the start, and it has been bugging me for a
long time. With this change, we're probably a bit slower on most
platforms but save huge amounts of space with all in-memory sample
datastructures.
|
|
The file is now renamed to Queue.h, and the Resampler APIs with
LegacyBuffer are also removed. These changes look large because nobody
actually needs Buffer.h (or Queue.h). It was mostly transitive
dependencies on the massive list of includes in that header, which are
now almost all gone. Instead, we include common things like Sample.h
directly, which should give faster compile times as very few files
actually need Queue.h.
|
|
Previously, we were sending Buffers to the server whenever we had new
audio data for it. This meant that for every audio enqueue action, we
needed to create a new shared memory anonymous buffer, send that
buffer's file descriptor over IPC (+recfd on the other side) and then
map the buffer into the audio server's memory to be able to play it.
This was fine for sending large chunks of audio data, like when playing
existing audio files. However, in the future we want to move to
real-time audio in some applications like Piano. This means that the
size of buffers that are sent need to be very small, as just the size of
a buffer itself is part of the audio latency. If we were to try
real-time audio with the existing system, we would run into problems
really quickly. Dealing with a continuous stream of new anonymous files
like the current audio system is rather expensive, as we need Kernel
help in multiple places. Additionally, every enqueue incurs an IPC call,
which are not optimized for >1000 calls/second (which would be needed
for real-time audio with buffer sizes of ~40 samples). So a fundamental
change in how we handle audio sending in userspace is necessary.
This commit moves the audio sending system onto a shared single producer
circular queue (SSPCQ) (introduced with one of the previous commits).
This queue is intended to live in shared memory and be accessed by
multiple processes at the same time. It was specifically written to
support the audio sending case, so e.g. it only supports a single
producer (the audio client). Now, audio sending follows these general
steps:
- The audio client connects to the audio server.
- The audio client creates a SSPCQ in shared memory.
- The audio client sends the SSPCQ's file descriptor to the audio server
with the set_buffer() IPC call.
- The audio server receives the SSPCQ and maps it.
- The audio client signals start of playback with start_playback().
- At the same time:
- The audio client writes its audio data into the shared-memory queue.
- The audio server reads audio data from the shared-memory queue(s).
Both sides have additional before-queue/after-queue buffers, depending
on the exact application.
- Pausing playback is just an IPC call, nothing happens to the buffer
except that the server stops reading from it until playback is
resumed.
- Muting has nothing to do with whether audio data is read or not.
- When the connection closes, the queues are unmapped on both sides.
This should already improve audio playback performance in a bunch of
places.
Implementation & commit notes:
- Audio loaders don't create LegacyBuffers anymore. LegacyBuffer is kept
for WavLoader, see previous commit message.
- Most intra-process audio data passing is done with FixedArray<Sample>
or Vector<Sample>.
- Improvements to most audio-enqueuing applications. (If necessary I can
try to extract some of the aplay improvements.)
- New APIs on LibAudio/ClientConnection which allows non-realtime
applications to enqueue audio in big chunks like before.
- Removal of status APIs from the audio server connection for
information that can be directly obtained from the shared queue.
- Split the pause playback API into two APIs with more intuitive names.
I know this is a large commit, and you can kinda tell from the commit
message. It's basically impossible to break this up without hacks, so
please forgive me. These are some of the best changes to the audio
subsystem and I hope that that makes up for this :yaktangle: commit.
:yakring:
|
|
With the following change in how we send audio, the old Buffer type is
not really needed anymore. However, moving WavLoader to the new system
is a bit more involved and out of the scope of this PR. Therefore, we
need to keep Buffer around, but to make it clear that it's the old
buffer type which will be removed soon, we rename it to LegacyBuffer.
Most of the users will be gone after the next commit anyways.
|
|
|
|
|
|
It seems like this happens in quite some valid situations, so my
initially sensible failsafe doesn't make sense. As the buffer system is
hopefully gone soon, it won't be an issue in the future either way.
|
|
This was regressed at some point though I never saw it working.
Basically, while jump to slider works correctly it doesn't even get
actioned. While the user is clicking the slider it's very likely that a
buffer finishes playing and the callback for that changes the slider
value. This means that the user click just gets lost. There's some
additional weird behavior where values are lost in even more cases, so
an additional fix that is needed is to store the slider value in the
AutoSlider while we're dragging and apply it on mouse up.
|
|
I found these by running SoundPlayer under UserspaceEmulator.
After boot we attempt to read from these values before they
are initialized.
|
|
Now that we have y-axis (gain) logarithmic display, we should also have
x-axis (frequency) logarithmic display; that's how our ears work. This
can be turned off with an option, but it generally looks much nicer.
|
|
This should give us better peaks by also reducing the energy on lower
frequency bars.
|
|
For DSP reasons I can't explain myself (yet, sorry), short-time Fourier
transform (STFT) is much more accurate and aesthetically pleasing when
the windows that select the samples for STFT overlap. This implements
that behavior by storing the previous samples and performing windowed
FFT over both it as well as the current samples. This gives us 50%
overlap between windows, a common standard that is nice to look at.
|
|
The input to the FFT was distorted by the usage of fabs on the samples.
It led to a big DC offset and a distorted spectrum. Simply removing fabs
improves the quality of the spectrum a lot.
The FFT input should be windowed to reduce spectral leakage. This also
improves the visual quality of the spectrum.
Also, no need to do a FFT of the whole buffer if we only mean to render
64 bars. A 8192 point FFT may smooth out fast local changes but at 44100
hz samplerate that's 200 ms worth of sound which significantly reduces
FPS.
A better approach for a fluent visualization is to do small FFTs at the
current playing position inside the current buffer.
There may be a better way to get the current playing position, but for
now it's implemented as an estimation depending on how many frames where
already rendered with the current buffer.
Also I picked y-axis log scale as a default because there's usually a
big difference in energy between low and high frequency bands. log scale
looks nicer.
|
|
Visualization widgets should only have to tell how many samples they
need per frame and have a render method which receives all data relevant
to draw the next frame.
|
|
Although it's nice to have this as an option, it should be the default
to adjust higher frequencies as they intrinsically have less energy than
lower energies.
|
|
Several related improvements to our Fast Fourier Transform
implementation:
- FFT now operates on spans, allowing it to use many more container
types other than Vector. It's intended anyways that FFT transmutes the
input data.
- FFT is now constexpr, moving the implementation to the header and
removing the cpp file. This means that if we have static collections
of samples, we can transform them at compile time.
- sample_data.data() weirdness is now gone.
|
|
|
|
Instead of drawing the album cover scaled to cover the whole
visualization area, draw it resized to fit the area without altering the
aspect ratio.
|
|
Since the NoVisualization widget now shows the album cover, it should be
called AlbumCoverVisualization instead.
|
|
Display the album cover for the current playing song in the
visualization area for the "None" Visualization.
For now only "cover.png" and "cover.jpg" are looked for in the same
directory for the album cover image.
When no cover image is found the serenity background is shown instead as
a fallback.
|
|
This adds a new start_new_file() function to VisualizationWidget which
is called when the player starts a new file, passing the filename of the
file. This allows VisualizationWidget subclasses to do any setup needed
when a new file is started.
|
|
When the bars visualization receives a new buffer, it checks if it needs
a new buffer, which is only the case after it has repainted. However,
after then setting m_is_using_last, which is the flag for this, it
checks the buffer size of the passed buffer and returns if that is too
small. This means that if the visualizer receives a buffer that is too
small, and because of external circumstances the update doesn't run
after the buffer modification routine, the m_is_using_last variable is
stuck at true, which means that the visualization incorrectly believes
that the passed buffer is old and we need not update. This simply fixes
that by resetting m_is_using_last if the buffer we're passed is too
small, because in that case, we're clearly not using the last buffer
anymore.
Note: This bug is not exposed by the current SoundPlayer behavior. It
will become an issue with future changes, so we should fix it
regardless.
|