Commit graph

264 commits

Author SHA1 Message Date
Christopher Snowhill
5424e18f27 Audio: Fix more hangs and resume playback on start
Check for paused processing state in various places, so that startup
playback works properly, and resume playback at seek offset works
properly and doesn't hang the player.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-13 22:25:36 -08:00
Christopher Snowhill
94fcb68563 Rubber Band DSP: Fix error checking for output
The samples available function returns a signed integer, so it can
apparently return negative on error, and the DSP was incorrectly casting
this to an unsigned type, and thus attempting to buffer an inordinate
number of samples and crashing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-13 20:58:07 -08:00
Christopher Snowhill
b0e6ec98a9 Audio: Improve buffer signaling
This should stop the deadlocks which were occurring.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-13 19:55:39 -08:00
Christopher Snowhill
4cd5cb8fa7 Downmix: Move downmix to DSP chain and fix a bug
The downmix filter also had a bug related to the channel configuration
used by the HRTF filter.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-13 14:56:18 -08:00
Christopher Snowhill
d3778f92fc Audio: Make chunk merging abortable
The merge function should be able to tell when the caller has no audio
left to process, such as on end of stream.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-13 13:51:46 -08:00
Christopher Snowhill
f3132e0061 Equalizer: Fix to function properly
This was completely broken, oops.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-13 13:39:16 -08:00
Christopher Snowhill
8647f76a46 Audio: Increase buffering before FreeSurround
FreeSurround needs more buffering from its input, so increase buffering
of previous node to 100ms.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-13 06:35:26 -08:00
Christopher Snowhill
c3af7c3bdc Audio: General fixes and improvements
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-13 06:34:21 -08:00
Christopher Snowhill
c48a52cda3 Bug Fixes: Fix monotonically increasing timestamps
Fixes timestamps in several cases where they were being processed
incorrectly, which was causing some chunked audio files to mis-report
timestamps into the past or the future, which caused the seekbar to jump
around in an unpredictable way.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-13 03:26:59 -08:00
Christopher Snowhill
061eefee29 Audio Node: Revert timedWait usage
Timed wait for 500us is kind of stupid and makes the threads wake up way
too much, and use way more CPU time. Reduce this, as the semaphores are
signaled appropriately, and the waiter should not wake up constantly.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-13 02:23:44 -08:00
Christopher Snowhill
9dcc434992 Visualization: Reworked buffering system
Visualization now buffers in the audio output pipeline, and uses a
container system to delay multiple buffer chains from emitting
visualization data over top of each other. This should stabilize
display output significantly, while introducing minimal lag before
DSP configuration changes take effect.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-13 01:12:53 -08:00
Christopher Snowhill
b53ebc08fe Audio: General cleanup and empty chunk checking
Upstream functions which return empty chunks on error do not return nil,
so the caller should check for an empty duration instead.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-13 01:05:15 -08:00
Christopher Snowhill
3eec6d7700 Audio Chunk: Add interface to copy chunk
This is needed if audio is to be removed from the chunk without altering
the original chunk.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-13 01:01:52 -08:00
Christopher Snowhill
139ff3a2b8 HRTF DSP: Add gain correction to impulse resampler
Impulses should be gain scaled roughly based on the sample ratio
relative to the original impulses. Lower target sample rate means less
impulses means gain goes up, higher target sample rate means more
impulses so gain goes down. Somewhat simple, seems to work.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-12 21:08:25 -08:00
Christopher Snowhill
be177617d3 HRTF DSP: Support resampling impulses
This prepares the filter to be the same as the rest of the filters, in
that they support flexible sample rates to match the output device.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-12 20:59:55 -08:00
Christopher Snowhill
afd2ca2e2a Rubber Band DSP: Make it possible to disable it
And disable it by default in new installations, otherwise leave the
setting alone. The disablement setting is shared with the engine
setting, so the default should not really change anything, except for
new installs.

Also, the time/pitch shifting dialog disables itself and displays an
obvious notice button, which opens the Rubber Band settings.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-12 20:11:05 -08:00
Christopher Snowhill
eaaabafdd2 Audio Processing: Unify sample block merging code
Sample block merging code should not be duplicated across the DSPs that
require it, but instead should be a common function. Also added some
optimizations to the Float32 converter function, to bypass conversion if
the audio format needs no conversion.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-12 18:54:38 -08:00
Christopher Snowhill
6f6c08dc5b Rubber Band DSP: Process larger blocks at a time
Attempt to completely fill the input buffer of the Rubber Band library
between each call to the process function, instead of processing in
as small an increment as the source node provides. May reduce processing
power required.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-12 14:56:32 -08:00
Christopher Snowhill
ee7aae922d Audio: Add full timestamp accounting to playback
Audio Chunks now have full timestamp accounting, including DSP playback
speed ratio for the one DSP that can change play ratio, Rubber Band.
Inputs which support looping and actually reporting the absolute play
position now do so.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-12 14:08:17 -08:00
Christopher Snowhill
92dbe351af DSP: Add format change checking to FreeSurround
FreeSurround, like the Equalizer, which attempt to coalesce Audio Chunks
into larger blocks of 4096 samples, must check if the audio format has
changed between blocks, and stop stacking chunks together when a new
format is detected. They will continue processing with less sample data
than expected, as necessary.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 23:04:31 -08:00
Christopher Snowhill
ce2bedf478 DSP: Move Equalizer processor to DSP node chain
The last of the built-in processors is now in the threaded processing
chain, and all DSPs are marked high priority and with short buffers.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 23:04:26 -08:00
Christopher Snowhill
8769869aee DSP: Move HRTF filter to DSP class chain
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 23:04:22 -08:00
Christopher Snowhill
d8802bc0da DSP: Move FreeSurround to DSP chain
This will no longer be in the output implementation.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 23:04:18 -08:00
Christopher Snowhill
c19de448dc DSP: Move Rubber Band to its own DSP group
This is a project file structure change only, no code changes.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 23:04:13 -08:00
Christopher Snowhill
8f1ef5eb6b Audio: Adjust node buffering behavior a bit
Change one remaining semaphore wait to 500us, and change the buffering
so that it can always overflow the requested duration by one chunk, so
that at least one chunk will always fit in the buffer. This also allows
the DSP nodes to flush at the end of the stream without losing their
output.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 18:11:26 -08:00
Christopher Snowhill
108186450f Rubber Band: Handle end of stream flushing better
The end of stream flushing should only request remaining samples once,
as should the rest of the process. The problem with the Rubber Band code
in this case is that it will wrap the remaining samples pointer after it
has been flushed, and emit a really huge number.

Also, add code to try to equalize the samples output with the samples
input, relative to the tempo stretching, as Rubber Band seems to flush
entirely too much data at end of stream, which can create noticeable
gaps in the output. This solves that as well.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 18:09:04 -08:00
Christopher Snowhill
08b991a7c3 Rubberband DSP: Guard non-restart config function
This should be guarded, so that no other thread tries to free the DSP
while it is potentially writing to the Rubber Band instance.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 17:50:07 -08:00
Christopher Snowhill
ec7d936289 DSP: Stylistic change
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 17:45:05 -08:00
Christopher Snowhill
7e5c9c8f7c DSP: Whitespace changes
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 17:44:07 -08:00
Christopher Snowhill
8a468c08ce Cleanup: Remove stale comment from source code
This comment was copied by accident when duplicating the original
Converter Node class for the new DSP base.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 15:10:30 -08:00
Christopher Snowhill
9ef21d8185 DSP: Add thread priority control
DSP threads, such as the Rubber Band processing, and planned moves of
other processing to buffer threads, such as the Equalizer, FreeSurround,
HRTF, and Downmixing for output, because they all have small output
buffers. Since these buffers drain and fill fast, they should be
processed at a high priority. Hopefully, App Store doesn't complain
about the use of these APIs.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 15:06:59 -08:00
Christopher Snowhill
9df263e87b Rubber Band: Move default preferences
Move them to the main app instead of an external module.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 01:28:54 -08:00
Christopher Snowhill
4fefdc7ea3 Rubber Band: Move everything to a DSP class
This class can more flexibly process and emit varying chunk sizes than
the previous code could, solving the problem of wide tempo changes.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 01:23:06 -08:00
Christopher Snowhill
e5eeb987fa Implemented real pitch and time shifting using Rubber Band
I will implement the more complex setup of providing options for
most of the configuration that Rubber Band provides, at a later
date, when I feel like creating a complex configuration dialog
for it, and asking for help translating every option and setting.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-12-09 00:44:43 -08:00
Christopher Snowhill
27c5e50633 Speed Control: Implement simple speed control
Implements a simple speed control using a resampler
designed for real time changes. A rubberband speed
control will be implemented at a later date.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-09-20 22:23:59 -07:00
Christopher Snowhill
0f5f11a5a4
Fix crash on unaligned volume scale
Volume scaling would potentially crash when handling
unaligned blocks of samples, and also handled them
completely wrong. It should be counting up single
samples until the buffer is aligned to a multiple of 16
bytes, and it should not exceed the intended count.

BUG: It was not only counting the unaligned samples
backwards, it was ignoring the real sample count.

Fixes #380

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-11 20:22:17 -07:00
Christopher Snowhill
587b7900b5
Hopefully fix memory usage during playback
Shuffle around @autoreleasepool blocks, and also add one
to the audio processing code in the playback callback, so
audio memory is released during playback instead of
accumulating.

Fixes #379

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-11 20:22:14 -07:00
Christopher Snowhill
f52de150a7
Processing: Fix missing converter setup function
Oops, I was missing a function necessary for output format changes.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-04 16:07:20 -07:00
Christopher Snowhill
a37026dec2
Reduce audio buffering slightly again
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-03 19:46:11 -07:00
Christopher Snowhill
d221300fb6 Improve audio buffering situation
Buffer up to 20 seconds per stage, and buffer only up
to 2 seconds before starting the next stage.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-03 04:48:57 -07:00
Christopher Snowhill
f4f46942ec
Fix converter after output switchover
This was missing, too.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-02 10:58:04 -07:00
Christopher Snowhill
7ac32284ff
Revert to previous low latency output system
This reverts usage of the AVFoundation output to use
the previous lower latency CoreAudio output, and
paves the way for a change I am cooking up soon.

Fixes several issues with playback and seeking latency.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-02 10:57:47 -07:00
Christopher Snowhill
545a1e9632
Reduce inter-thread buffering a bit
This isn't needed so much now that the output buffers more.

Should reduce the problems of #370

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-29 01:31:26 -07:00
Christopher Snowhill
28b36dda66
Add an option to control halving DSD volume level
And default it to disabled. As was pointed out to me by a user, DSD is
apparently mastered to a level of -6 dB, so double its level on output
by default.

Also reorder all preferences dialog controls so they are instantiated in
display order, which should help screen readers, maybe.

Fixes #368

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-15 16:46:30 -07:00
Christopher Snowhill
c9ed3c4817
Fix lossless capability reporting for partial read
When reading partial chunks, and when returning partial data, it is
essential to maintain this lossless chunk status across either whole or
partial chunk reads. Otherwise, the converter chain sees the lossless
flag constantly changing on lossless files, such as PCM or DSD, and
causes the DSD decimator and/or resampler to be torn down and reset
repeatedly, causing glitches in the audio.

The glitch was not, in fact, with the decimator itself, and was
occurring to a degree without it, as it would be restarting the
resampler repeatedly as well.

Fixes #367

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-14 04:14:35 -07:00
Christopher Snowhill
24a3209682
Correct the decimator sample latency
The latency is half of the FIFO, or half the filter size, and each byte
is 8 samples, so return the value accordingly.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-14 04:14:30 -07:00
Christopher Snowhill
555b9f248d
Add an explanatory comment that got lost
This comment was in the original sample decimator code, I neglected to
include it in my port over to Cog. Doesn't really serve any functional
change, though. It would have clarified that I needed to reduce the gain
level much sooner, though.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-14 04:14:26 -07:00
Christopher Snowhill
eb26ab8be4
Update projects and source in prep for Xcode 15
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-06-08 04:12:29 -07:00
Christopher Snowhill
72ee38ad14
Audio Player: Only wait for unstopped input
Input thread now signals when it has stopped and is about to return, in
case the input thread returns before the BufferChain dealloc function
would be waiting for it to terminate. Somehow, even though the Semaphore
is being signaled at this point, the BufferChain still ends up waiting
the default of 2.5 seconds for the signal that apparently never comes,
delaying file stoppage. This prevents the wait action entirely. Must
have been some sort of race condition.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-12-09 21:18:56 -08:00
Christopher Snowhill
6daa0de425
Audio Player: Add new method of signaling stop
This new method should cause all stops to default to immediate stoppage,
and only stops that occur after an end of track signal should indicate
to play out the entire buffer.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-12-09 21:18:47 -08:00