The center of this is now an ABuffer class in LibAudio.
ABuffer contains ASample, which has two channels (left/right) in
floating point for mixing purposes, in 44100hz.
This means that the loaders (AWavLoader in this case) needs to do some
manipulation to get things in the right format, but that we don't need
to care after format loading is done.
While we're at it, do some correctness fixes. PCM data is unsigned if
it's 8 bit, but 16 bit is signed. And /dev/audio also wants signed 16
bit audio, so give it what it wants.
On top of this, AudioServer now accepts requests to play a buffer.
The IPC mechanism here is pretty much a 1:1 copy-paste from
LibGUI/WindowServer. It can be generalized more in the future, but for
now I want to get AudioServer working decently first :)
Additionally, add a little "aplay" tool to load and play a WAV file. It
will break with large WAVs (run out of memory, heh...) but it's a start.
Future work needs to make AudioServer block buffer submission from
clients until it has played the buffer they are requesting to play.
Currently the two available input types are:
- GMessageBox::InputType::OK (default)
- GMessageBox::InputType::OKCancel
Based on your choice, GMessageBox::exec() will return ExecOK or ExecCancel.
Currently this will be used by the WindowServer to show some dialogs.
This is needed since WindowServer can't use LibGUI and reimplementing
message box functionality inside WindowServer would be silly. :^)
The only dialog supported in this initial version is --shutdown
This way, CNotifier can mutate state to its little heart's content
without destroying the world when the global CNotifier hash changes
during delivery.
If custom I/O is being done outside CIODevice, we need a way to force blocking sometimes.
This also fixes the default of CLocalSocket to be non-blocking, the same
as CTCPSocket.
We were locking the list of references, and then destroying the
reference, which made things go a little crazy.
It's more straightforward to just remove the per-reference lock: the
syscalls all have to lock the full list anyway, so let's just do that
and avoid the hassle.
While I'm at it, also move the SharedBuffer code out to its own file as it's
getting a little long and unwieldly, and Process.cpp is already huge.
I was messing around with this to tell the compiler that these functions
always return the same value no matter how many times you call them.
It doesn't really seem to improve code generation and it looks weird so
let's just get rid of it.
Rather than limiting it to two shared processes, store a Vector of
references, so we can add more if we want. Makes the code a little
more generic.
No actual change to the syscall interface yet, so nothing takes
advantage of this yet.
Meet TStyle. It allows you to write things like this:
dbg() << TStyle(TStyle::Red, TStyle::Bold) << "Hello, friends!";
Any style used will be reset along with the newline emitted when the dbg()
temporary goes out of scope. :^)
This can definitely be improved, but I think it's a decent place to start.
This is the same as calling FileSystemPath(foo).string(). The majority of
clients only care about canonicalizing a path, so let's have an easy way
to express that.
Replace the class-based snooze alarm mechanism with a per-thread callback.
This makes it easy to block the current thread on an arbitrary condition:
void SomeDevice::wait_for_irq() {
m_interrupted = false;
current->block_until([this] { return m_interrupted; });
}
void SomeDevice::handle_irq() {
m_interrupted = true;
}
Use this in the SB16 driver, and in NetworkTask :^)
This makes waitpid() return when a child process is stopped via a signal.
Use this in Shell to catch stopped children and return control to the
command line. :^)
Fixes#298.
In order to repaint the GUI after the sound thread has produced some sweet
new waves, we post a CCustomEvent to the main thread's event loop and then
wake up that event loop via CEventLoop::wake().
This patch generalizes the concept used in Piano to wake up the event loop
so it can react to something happening on a secondary thread.
Basically, there's a pipe who is always part of the file descriptor set we
pass to select(), and calling wake() simply writes a little to that pipe.