Compare commits

...

3624 commits
r516 ... main

Author SHA1 Message Date
Christopher Snowhill
1a0ea3b5d3 Emergency Bug Fix: Fix loading individual tracks
Some checks failed
Check if Cog buildable / Build Universal Cog.app (push) Has been cancelled
And folders of tracks, too! The only thing that worked in 3117 was
playlist files. Hah!

Fixes #436

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-05-11 05:33:00 -07:00
Christopher Snowhill
7839f661a1 Sentry: Update sentry-cocoa to version 8.50.1
Some checks failed
Check if Cog buildable / Build Universal Cog.app (push) Has been cancelled
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-05-10 00:40:24 -07:00
Christopher Snowhill
30db270af3 VGMStream: Updated libvgmstream code base
Updated VGMStream to r1980-277-g72cb4b89

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-05-09 21:13:34 -07:00
Christopher Snowhill
ab7c0a0afd Track loading: Change file import and sorting
Files are now loaded to unique keys, and containers such as playlists
and CUE sheets maintain their file order. Deduplication now only applies
to top level files and not playlist contents. Sorting applies to top
level files, and playlist or container names, but not their contents.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-05-09 21:13:28 -07:00
Christopher Snowhill
69533e12c7 VGMStream: Updated libvgmstream code base
Some checks failed
Check if Cog buildable / Build Universal Cog.app (push) Has been cancelled
Updated VGMStream to r1980-268-gc32951e9

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-05-03 01:56:34 -07:00
Christopher Snowhill
048bc7c30d Converter Node: Change volume scale observer
This should fix an exception being thrown because the observer wasn't
registered, or known to be registered. Only register it when it will be
used, and only unregister it if it was registered.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-05-03 01:56:29 -07:00
Christopher Snowhill
5753c48245 HDCD: Stop dynamically halving the volume
Some checks failed
Check if Cog buildable / Build Universal Cog.app (push) Has been cancelled
Apparently, this doesn't work too well with real HDCD tracks, and causes
all sorts of weird volume issues. Just leave the volume alone, and let
HDCD decoding make tracks louder, possibly, rather than try to halve the
volume automatically on a detector that isn't terribly good.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-04-24 14:55:33 -07:00
Christopher Snowhill
3b4313d844 HDCD: Fix how unsigned audio may be processed
Unsigned will alter the input, so move it like the other integer sample
processors do.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-04-24 14:55:29 -07:00
Christopher Snowhill
a92973c6aa HDCD: Make HDCD extension processing optional
Some checks are pending
Check if Cog buildable / Build Universal Cog.app (push) Waiting to run
And disabled by default, at that. I can't actually hear the difference
of Peak Extension in the Rock track I have that claims to use it. And
Low Level Range Extension is more trouble than it's worth on tracks that
use it by mistake, or maliciously, if the case may be. I may add track
tag level control in the future.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-04-23 21:44:06 -07:00
Christopher Snowhill
91c4ed0c98 Maintenance: Touched by Xcode
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-04-23 21:44:01 -07:00
Christopher Snowhill
9e889399ec VGMStream: Fix memory leak
Some checks failed
Check if Cog buildable / Build Universal Cog.app (push) Has been cancelled
Thanks to upstream VGMStream for fixing this in the Audacious plugin,
which I derived this code from in the first place, which explains the
memory leak getting in.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-04-20 21:35:27 -07:00
Christopher Snowhill
47a749ace0 VGMStream: Add native support for 24/32 bps int
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-04-20 21:35:23 -07:00
Christopher Snowhill
4232fb3949 VGMStream: Updated libvgmstream code base
Updated VGMStream to r1980-242-gfccbb05f

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-04-20 21:35:18 -07:00
Christopher Snowhill
f96cfea2d3 Placeholder commit for Sparkle update
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-04-20 21:03:54 -07:00
Christopher Snowhill
1cd431019c Updated MASShortcut to fix crashes
I hope this works to fix the crashes from migration.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-04-20 21:00:58 -07:00
Christopher Snowhill
3f0c8d379a Path Suggester: Make font fixed size
Some checks failed
Check if Cog buildable / Build Universal Cog.app (push) Has been cancelled
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-04-07 14:14:49 -07:00
Christopher Snowhill
72608ecea0 Path Suggester: Touched by Xcode
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-04-07 14:14:42 -07:00
Christopher Snowhill
ac26a28f59 Bug Fix: Fix FFmpeg reporting timestamps for DSD
Some checks failed
Check if Cog buildable / Build Universal Cog.app (push) Has been cancelled
Raw DSD is counting frames in bytes, not bits/samples, so it needs to be
scaled up when dividing by the raw sample rate.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-28 20:26:36 -07:00
Christopher Snowhill
a19469325b MIDI: Add unstable configuration for AU players
Some checks are pending
Check if Cog buildable / Build Universal Cog.app (push) Waiting to run
It's regarded as unstable as some plugins randomly decide to overflow
the main thread queue and crash the player on the main thread check, but
only sometimes, and not always.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-28 16:18:51 -07:00
Christopher Snowhill
f4a382c67f Sandbox Security: Disable library validation
Apparently, this was preventing some signed plugins from being loaded
into the process, preventing their use as MIDI plugins. And this may be
needed for future AudioUnit DSP filter support, for third party plugins
there, as well.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-28 16:18:46 -07:00
Christopher Snowhill
25cd57a3cb MIDI: Move sample buffer from stack to class
Move the stack-based buffer, which is rather large, to the player class
instance, where it will be allocated on the heap.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-28 16:18:42 -07:00
Christopher Snowhill
40d9574015 MIDI: Fix Audio Unit player in several ways
Improve rendering functions of Audio Unit player, and also fix looping
for the Audio Unit player, and any other possible future players which
use blocked decoding with timestamped events.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-28 16:18:37 -07:00
Christopher Snowhill
8cfddb875c MIDI: Make BASSMIDI the visible default
Also hide the Apple plugins from settings so they don't get activated
unless there's no SoundFont configured.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-28 16:18:33 -07:00
Christopher Snowhill
54db6c17cb Dependencies: Update BASS and WavPack libraries
BASSMIDI: 2.4.15.3
BASSFLAC: 2.4.5.5
BASSOPUS: 2.4.3
BASSWV: 2.4.7.4

WavPack: 5.8.1

And updated the WavPack plugin to support threaded decoding, using up to
four worker threads, as detected from the host machine's CPU count.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-28 16:18:28 -07:00
Christopher Snowhill
104e959ea2 MIDI: Update BASS docs
This was the version of BASSWV previously bundled.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-28 15:26:22 -07:00
Christopher Snowhill
9a23ff9ff9 Audio Output: Optimize fader function
Now using Accelerate methods to calculate and multiply ramps per channel
and add the remainder if necessary.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-27 17:13:47 -07:00
Christopher Snowhill
6b23590ac8 Play Control: Previous track now also restarts
Some checks failed
Check if Cog buildable / Build Universal Cog.app (push) Has been cancelled
If the current track has played for more than 5 seconds, previous track
now restarts the current track, instead of jumping back to the previous
track.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-26 20:10:18 -07:00
Christopher Snowhill
2282538c42 Bug Fix: Fix inserting empty chunks on track ends
This code did not check the number of samples in a packet before adding
it to the output buffer, which apparently had the potential to cause the
output code to emit up to 512 samples of silence between tracks. This,
as one can guess, is a bad thing, and causes noticeable gapping between
tracks.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-26 20:10:13 -07:00
Christopher Snowhill
73951d6fe7 Bug Fix: Fix output logging, switch log method
Output logging, a debugging feature that is only enabled at build time
if I need to chase down some audio mixing or output bug, was not logging
anything at all. Change to use Cocoa file writing methods, and actually
implement the output writer function again.

This code is left disabled 99% of the time anyway, and especially in
release builds. Like the node logging code elsewhere, it has the
potential to be very noisy and consume massive amounts of disk space.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-26 20:10:08 -07:00
Christopher Snowhill
8c019c7302 Bug Fix: Include soxr latency in memory allocation
This should be included, for safety purposes, in case the rounding up to
the nearest multiple of 256 samples doesn't bump the buffer size enough.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-26 20:10:03 -07:00
Christopher Snowhill
f7b2c481e6 Bug Fix: Retry MP3 file a few times before failure
Some checks failed
Check if Cog buildable / Build Universal Cog.app (push) Has been cancelled
Give up after 10 tries.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-24 16:05:36 -07:00
Christopher Snowhill
2038a140ed Bug Fix: Fix minimp3 to deal with invalid files
Some checks are pending
Check if Cog buildable / Build Universal Cog.app (push) Waiting to run
If a file can't decode, there should not be a division by zero error.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-24 15:42:39 -07:00
Christopher Snowhill
18d3f76152 Bug Fix: Fix minimp3 streaming support
Some checks are pending
Check if Cog buildable / Build Universal Cog.app (push) Waiting to run
The streaming support was breaking because initial packet detection was
failing due to bit reservoir errors. Instead, detect consecutive sync
frames in the initial read buffer, then attempt to sync to a decodable
frame in the first block of data, otherwise give up.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-24 08:16:47 -07:00
Christopher Snowhill
2237863f08 FFmpeg: Fix HLS, HLS metadata, update FFmpeg
Add missing HLS MIME type: audio/mpegurl

Update FFmpeg to version 7.1.1, carrying the same patches, and one new
patch: Implementing support for HLS ID3 tags changing mid-stream.

We cannot do away with fdk-aac yet, because the USAC codec is missing
features that fdk-aac implements already.

Fixes #428

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-24 06:09:40 -07:00
Christopher Snowhill
ac93ff038e Bug Fix: Fix minimp3 seek position
Some checks are pending
Check if Cog buildable / Build Universal Cog.app (push) Waiting to run
Seek offset is scaled by the number of channels in the file. Oops again.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-23 20:22:27 -07:00
Christopher Snowhill
184e1f14c9 Bug Fix: Free memory buffers used by minimp3
Some checks are pending
Check if Cog buildable / Build Universal Cog.app (push) Waiting to run
This was being leaked when playing static, seekable files. Oops.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-23 20:04:00 -07:00
Christopher Snowhill
c24d914127 minimp3: Numerous buffering fixes, consolidation
Move minimp3 packet decoder state into the decoder_ex state structure,
instead of using the redundant duplicate structure. Also reduce input
buffer size for streams to 16KiB, and actually use the defined macro in
the header file to declare the streaming buffer size.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-23 20:03:55 -07:00
Christopher Snowhill
4b0f4a43fd minimp3: Fix seeking behavior
Some checks are pending
Check if Cog buildable / Build Universal Cog.app (push) Waiting to run
Seeking should clear the sample buffer if it contains anything, and non-
seekable files should return an error on an attempt to seek.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-23 16:18:44 -07:00
Christopher Snowhill
b67b2acd6a VGMStream: Update associated filename extensions
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-23 16:18:39 -07:00
Christopher Snowhill
90c5833fe9 VGMStream: Considerably rewrite plugin interface
It was about time to rewrite this anyway. Now adapted to the new public
interface API.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-23 16:18:35 -07:00
Christopher Snowhill
8b3a165d9a Bug Fix: Fixed several code signing issues
There were several issues which broke debug and possibly release
signing, and broke VGMStream in debug situations. Not sure if it was
also broken in release.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-23 16:18:29 -07:00
Christopher Snowhill
cbaacd35b1 VGMStream: Updated libvgmstream code base
Updated VGMStream to r1980-181-g10093db5

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-23 16:18:25 -07:00
Christopher Snowhill
9b683a9c56 Bug Fix: Reorder LPC scratch memory for alignment
The double members should be ordered first so they are aligned to an 8
byte boundary. The rest are fine as-is.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-23 00:05:19 -07:00
Christopher Snowhill
7ff653b48f MP3: Replace MAD with minimp3
libMAD had memory safety issues, possibly with corrupt files. Hopefully,
this will fix the problem.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-23 00:05:11 -07:00
Christopher Snowhill
31281197d4 Code Fix: Change visualizers to only copy FFT data
These two visualization components, SceneKit and Core Graphics based,
only use the FFT data. So now make the request drop the PCM data.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-13 19:51:27 -07:00
Christopher Snowhill
7cb010e337 Code Fix: Add nullability flags to Vis Manager
The Visualization Manager PCM/FFT copy function was already observing
these parameters for null input and only returning output to the ones
which were not null. This just makes it clear that they are both
optional parameters. This is useful for future visualization adventures,
allowing PCM copy without invoking the FFT processing, or requesting FFT
without also having to keep the PCM.

This is mostly only a compile time change, and has no noticeable effect
on the current runtime behavior, as the only consumers of the Visualizer
data currently request both PCM and FFT.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-13 19:51:22 -07:00
Christopher Snowhill
d97b1e788a Sentry: Update sentry-cocoa to version 8.47.0
This release is a bug fix against the Sentry integration from the
upstream project.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-13 19:51:16 -07:00
Christopher Snowhill
2401536e5c Crash Fix: Only selectively register observer
This affects User Defaults, but only has any effect on ChunkLists which
are being used for conversion, and only if they're processing DSD source
material. Thus, the observer should only be added on the one stream that
is converting DSD, and should definitely be removed when the object is
deallocated.

This fixes a serious crash bug that mostly appears to only affect Intel
Macs, and has no major side effects on Apple Silicon that I can tell.
It's a good thing I still own an Intel Mac or two to test on, even if
they are both trapped on older releases of macOS.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-13 19:51:12 -07:00
Christopher Snowhill
a1bbfbe3ac Bug Fix: Track advancing when Rubber Band disabled
Apparently I somehow didn't notice this situation because I still had
Rubber Band enabled, and existing users kept it enabled ever since I
introduced it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-11 14:30:09 -07:00
Christopher Snowhill
2cc7ff9c4a Core Audio: Implement proper fade on seek
Whew, what a mess! And this may pave the way for crossfading.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-10 23:09:03 -07:00
Christopher Snowhill
54c9f30e8a Bug Fix: Don't display notification on seek
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-10 23:08:57 -07:00
Christopher Snowhill
a09907ccd9 Metadata: Move encoding helper to CogAudio
Move this commonly used string decoding helper to the CogAudio framework
and import it in every plugin that uses it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-10 14:55:56 -07:00
Christopher Snowhill
5d73246926 Bug Fix: Handle invalid UTF-8 decoding errors
Apparently, stringWithUTF8String: just returns nil when the encoding is
not UTF-8, rather than throwing an exception.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-10 14:55:51 -07:00
Christopher Snowhill
532d22b9bb App Store: Add encryption attestation
Finally add this to Info.plist properties to save a few seconds on
submissions.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-09 23:50:35 -07:00
Christopher Snowhill
aee05d5503 Bug Fix: Change how pause stops unseekable files
Change the stop action slightly.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-09 23:45:01 -07:00
Christopher Snowhill
d4dcf29dd4 Bug Fix: Disable seeking hotkeys when unseekable
Disable the seek forward and backward actions when the current track
doesn't support seeking.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-09 23:44:26 -07:00
Christopher Snowhill
90a62821f4 Preferences: Touched by Xcode
Xcode really wants to add focusRingType="none" to everything now upon
opening with the editor, for some reason.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-09 23:19:17 -07:00
Christopher Snowhill
f889b34b1b Bug Fix: Add more constraints to general prefs
Add more constraints so the checkboxes are properly spaced again.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-09 23:13:18 -07:00
Christopher Snowhill
2733ee95f3 Playlist Loader: Add option to skip playlists
When parsing folders, add option to skip importing playlist files.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-09 23:01:47 -07:00
Christopher Snowhill
2042034868 Bug Fix: Remove missing outlet from preferences
This is a reference to the updates pane that doesn't exist in the App
Store version of Cog.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-09 22:30:51 -07:00
Christopher Snowhill
0a849fc1d9 FFmpeg: Handle multiple attached pictures properly
Now it handles multiple attached pictures and tries to pick out the one
which may be the front cover picture, or otherwise picks the first one.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-09 20:06:49 -07:00
Christopher Snowhill
b0fd359388 Crash Fix: Fix a serious bug in previous commit
Fixes commit 9c1c6d7130, where code was
treating a dictionary like an array.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-09 18:30:34 -07:00
Christopher Snowhill
318cfd71ea Bug Fix: Fix circular bind setter loop in hotkeys
MASShortcut had a potential circular loop in its bindings, let's fix
that right up.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-09 18:23:39 -07:00
Christopher Snowhill
9c1c6d7130 Bug Fix: Operation blocks should queue inputs
Operation blocks cannot expect their out of scope variables to be
present when the block executes, so design the block operation to pull
inputs from a queue array one at a time, like the rest of the blocks do.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-09 15:05:20 -07:00
Christopher Snowhill
cf77521bb7 Bug Fix: Handle possible null exceptions
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-09 15:05:15 -07:00
Christopher Snowhill
f8ee7e5e46 Core Audio: Fix pausing glitches
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-09 14:43:16 -07:00
Christopher Snowhill
e64c279e45 Disable global hotkeys again for macOS < 15.0
Clearly, NSUserDefaults bindings were not really meant to be used in
practice at all, as they do nothing but crash the app.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-09 14:26:07 -07:00
Christopher Snowhill
0de555c2fd Re-enable hotkeys and change preferences storage
Change hotkey storage system, hopefully this will fix the stability
issues that have been plaguing it for a while now.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-08 20:24:25 -08:00
Christopher Snowhill
442dfb726b Bug Fix: Disable hotkeys on macOS older than 15.0
Apparently even touching the NSUserDefaults with MASShortcut there is
crash inducing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-08 12:34:38 -08:00
Christopher Snowhill
afeb614481 Bug Fix: Actually perform a fade in
It doesn't fade if we don't advance the sample pointer. Ugh.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-08 00:38:56 -08:00
Christopher Snowhill
63a5239346 Core Audio: Slight change to audio fade in on seek
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-08 00:38:50 -08:00
Christopher Snowhill
0570ebedea Core Audio: Increase fade duration to 125ms
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-07 23:44:46 -08:00
Christopher Snowhill
1d8803e6f2 Core Audio: Shut off device after fade out
And resume playback before fade in.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-07 23:44:24 -08:00
Christopher Snowhill
46aac2fa91 Core Audio: Add a slight fading to operations
Add 10 millisecond fade to seeking, pausing and unpausing, and stopping
on command.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-07 23:22:29 -08:00
Christopher Snowhill
ff5a1c6c2c Bug Fix: Prevent hangs when starting paused
This happens when the player is resumed paused, sometimes near the end
of a track.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-07 20:14:39 -08:00
Christopher Snowhill
d99eda15b5 Bug Fix: Disable hotkeys configuration on macOS<15
MASShortcutView is apparently buggy on older macOS versions. So everyone
there gets hard coded shortcuts and nothing else.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-07 17:51:17 -08:00
Christopher Snowhill
d3f99f8987 Bug Fix: Simplification of chunk duration check
This only needs to check that the chunk is empty, not its exact
duration.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-07 17:28:09 -08:00
Christopher Snowhill
aafe817a1f Bug Fix: Correct playback of DSD formats
DSD formats were buffering incorrectly and terminating way too soon.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-07 17:28:04 -08:00
Christopher Snowhill
36a2d8efd5 Bug Fix: Restart converter on format change
The converter doesn't just require an output format call, it also
requires this input format change callback to actually signal it to
reopen the converter process with a new format setup.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-07 05:39:17 -08:00
Christopher Snowhill
17b8647052 Bug Fix: Ensure robust output format changes
Output format mostly requires stopping and restarting the output device,
and this also prevents us from using the latency function properly,
which apparently always returns 0 for output devices anyway. These
changes also prevent the output callback from hanging when resets occur.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-07 05:39:12 -08:00
Christopher Snowhill
a3385d1af9 Crash Fix: Change how default shortcuts are stored
It turns out that initializing NSUserDefaultsController like this is a
really bad idea, especially on older versions of macOS. This is probably
also why the equalizer was crashing for people on first activation.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-07 04:40:08 -08:00
Christopher Snowhill
9cc0b8be8d Cleanup: Remove unused code
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-07 04:40:04 -08:00
Christopher Snowhill
25d6f6ea7c Quality of Life: Make buildable with old Xcode
Make the code mostly buildable with Xcode as old as 13.2.1, for debug
testing on Big Sur.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-07 04:39:59 -08:00
Christopher Snowhill
d7681bda71 Translation: Missing string recently added
Translation provided.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-06 16:47:16 -08:00
Christopher Snowhill
355169475d Sentry: Replace deprecated SentryUserFeedback use
Replace with newer SentryFeedback.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-06 14:58:12 -08:00
Christopher Snowhill
918aa59920 Sentry: Temporarily disable app hang detection
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-06 14:51:59 -08:00
Christopher Snowhill
00d42d519e Translation: Properly support this string
Properly support translating the System Default Device name for sound
output devices. Pending a Spanish translation, but in its current state,
it's no different from where it was before this change.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-06 14:44:20 -08:00
Christopher Snowhill
b41fd74f31 Bug Fix: Default output device changes monitoring
Fix default output device logging, and also the preferences if no
default device happens to be set.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-06 14:41:28 -08:00
Christopher Snowhill
72bfe1c846 Bug Fix: Latency reporting for high latency output
Fixes visualization latency under virtual machines, at least. Not sure
which local or native systems would be reporting high latency here, but
this should fix them as well.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-06 13:14:41 -08:00
Christopher Snowhill
713241a94f Major Bug Fix: Volume control works again
Shouldn't have broken this again.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-06 10:18:13 -08:00
Christopher Snowhill
d06ee01a17 Feature: Add seeking hotkeys with defaults
Defaulting to ctrl+command+left/right arrows.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-06 10:18:08 -08:00
Christopher Snowhill
04db82d0ff Bug Fix: Move default hotkeys to main app startup
Instead of the Preferences plugin.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-06 10:18:03 -08:00
Christopher Snowhill
bb78d49f23 Sound Output: Move DSPs, restructure output buffer
Move the DSPs to the output node, so they don't get closed and reopened
across each file. Also restructure the output handler to buffer a little
on its own, to account for track switch activity.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-05 20:07:38 -08:00
Christopher Snowhill
428ffb1531 Sentry: Bump to version 8.46.0
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-05 20:07:30 -08:00
Christopher Snowhill
c89cc1cff4 Bug Fix: Add more guards to sound output block
These guards should prevent the one crash we saw logged.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-05 20:05:53 -08:00
Christopher Snowhill
4ccd1811b0 Bug Fix: Correct exception handling blocks
These should be catching NSException*, not generic `id`.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-05 20:05:48 -08:00
Christopher Snowhill
45352f9261 Bug Fix: Handle compile time warning
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-04 00:46:55 -08:00
Christopher Snowhill
68a146f6b8 Bug Fix: Handle gaplessness for headphone filter
The filter uses a pre-buffer of input audio, so extrapolate from the
actual input to fill the buffer. Fixes clicking on non-zero-crossing
track endings.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-04 00:46:50 -08:00
Christopher Snowhill
ea7eff40e0 Bug Fix: Restructure Rubber Band gapless handler
Change how samples are accounted for by the filter.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-04 00:46:45 -08:00
Christopher Snowhill
45cb841ec0 Bug Fix: Greatly improve audio buffer handling
Buffers were being treated as empty before they were actually processed,
due to races between the current node's end of stream marker and
actually feeding the output buffer.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-04 00:43:30 -08:00
Christopher Snowhill
e3b48bdc86 Bug Fix: Snap pitch and tempo settings to 1
Pitch and tempo weren't snapping to exactly 1.0 before, as a result of
various things. This fixes that.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-04 00:43:25 -08:00
Christopher Snowhill
462a509c85 Debugging: Implement buffer chain logging code
This optional code, disabled at compile time by default, allows finding
weird issues with the sample decoding chain.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-04 00:43:20 -08:00
Christopher Snowhill
c7a160a9e7 Improvement: Hopefully improve tag loading speed
Hopefully this works for most ASCII and UTF-8 tags, and continues to
work for weird tag encodings.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-04 00:43:16 -08:00
Christopher Snowhill
2f9d7fe66d Bug Fix: Fix .gitignore file
Oops, the "build" folder reference was incorrect.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-04 00:43:11 -08:00
Christopher Snowhill
cc12da5507
CI: Bump OS and Xcode versions
Bump to macOS 15 and Xcode 16.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-03 18:52:52 -08:00
Christopher Snowhill
b889586708 Playback: Implement Selection Follows Playback
Option to make selection follow the playback, within the lag of the
output buffer, including if Always Stop After Current or Repeat One is
enabled. Allows easily queueing up a list of tracks in Always Stop mode,
then hitting the Play button again to play the next track. Enabled by
default, but always optional to disable.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-03 18:37:31 -08:00
Christopher Snowhill
a8902b4ee6 Playback: Implement Always Stop After Current
A new menu option under the Control menu, disabled by default, which
stops playback after the current track completes.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-03 18:34:58 -08:00
Christopher Snowhill
5e324927c5 Miscellaneous: File touched by Xcode
Xcode sure does love to tweak the numbers randomly.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-03 18:34:51 -08:00
Christopher Snowhill
05e830c681 Bug Fix: Wait for output to shut down first
In case stop function called on another thread, wait for it to complete
first.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-01 15:18:26 -08:00
Christopher Snowhill
8c97f075cf Bug Fix: Remove observer cleanup
Apparently, this isn't needed, and on two users reporting crashes,
actually causes exceptions to be thrown somewhere.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-03-01 15:18:21 -08:00
Christopher Snowhill
83ba062010 Seeking: Restart output completely on track seek
This required some minor workarounds to deal with the play time counting
that works toward play count reporting.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-28 17:56:22 -08:00
Christopher Snowhill
10f8d0c2e1 Bug Fix: Attempt to solve a next track crash
This was attempting to retrieve the NSURL host object, possibly on a
file URL where the two did not match a previous check. Now we only pass
the full scheme/host/path check if both URLs are not file URLs.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-28 16:34:26 -08:00
Christopher Snowhill
9fc7c99022 Optimization: Perform container checks in queue
Perform the file container checks in an operation queue, since those are
a major bottleneck at this point, too.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-27 19:05:22 -08:00
Christopher Snowhill
00d861efc0 Bug Fix: Unregister observer correctly
Only unregister it if it was actually registered.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-27 14:39:21 -08:00
Christopher Snowhill
bfa9660437 Cleanup: Remove unused code
This is no longer needed.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-27 14:31:58 -08:00
Christopher Snowhill
24888a669b Bug Fix: Correctly set audio volume on play start
Play start was missing this somehow, after a specific commit removed
some code.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-27 14:31:53 -08:00
Christopher Snowhill
b05f428cde Feature: Add fractional track length tooltips
Add fractional track length tooltips, for extra verbose info goodness.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-27 00:59:06 -08:00
Christopher Snowhill
d5ca037943 Bug Fix: Playlist Loader now correctly sorts items
Playlist Loader was sorting only the non-container tracks, and not the
final track list. Move the sort operation to the end of the processing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-27 00:59:01 -08:00
Christopher Snowhill
bf5e6d85a3 Cleanup: Remove unused variable
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-27 00:58:56 -08:00
Christopher Snowhill
2be457f395 Bug Fix: Rubber Band should now flush last chunk
There is a race condition with the next Node in the chain and the End of
Stream marker, considering how tiny the buffering is for these DSPs. Set
End of Stream instead after inserting the end of stream flush chunk.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-27 00:58:51 -08:00
Christopher Snowhill
955b90280f Bug Fix: Do not perform cascading reset on DSPs
DSPs should not be performing a cascading reset when resetting just
their own buffers, for example, on init or shutdown of just that one
DSP filter.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-27 00:58:47 -08:00
Christopher Snowhill
1909b26671 Bug Fix: Clear counter correctly on reset
This reset was missing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-27 00:58:43 -08:00
Christopher Snowhill
fb5193ab62 FFMPEG: Optimize file reader access
Improve handling where FFmpeg may call the provided file reader with
AVSEEK_SIZE repeatedly, when file size is not likely to change between
repeated calls. This prevents repeated seek operations that would
otherwise be required to probe the file size each time.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-26 21:20:38 -08:00
Christopher Snowhill
6855449550 Sentry: Replace most of old logging, add traces
Add event traces to playlist loading and metadata processing queues.
Unfortunately, most of the old non-error events should not be logged,
because Sentry gets terribly spammy with captureMessage events. They
should only be used for error events, or other uncommon events which
do not already throw exceptions or NSError objects.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-26 20:29:04 -08:00
Christopher Snowhill
bde8f23ab1 Sentry: Enable profiling for issue debugging
Enable processor usage profiling for the app to gather information for
potential bottleneck tracking.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-26 02:37:17 -08:00
Christopher Snowhill
d47a96acaa Bug Fix: Fix CI building again
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-26 01:23:49 -08:00
Christopher Snowhill
4a0cca22b8 Feature: Replaced Crashlytics with Sentry
Crash logging is now handled by the Sentry service.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-26 01:17:56 -08:00
Christopher Snowhill
30d9eeec2b Cleanup: Massive code cleanup and reorganization
Cleaned up project settings to current defaults, except for the macOS
deployment version, which is still 10.13. Cleaned up a lot of headers
and such to include with angle braces instead of double quotes. Enabled
build sandbox in a lot of places. Disabled subproject signing in several
places, for libraries and frameworks which will be stripped and signed
when they are copied into place in the final build.

Also, while trying to solve compilation issues, the visualization
controller was reverted to the Objective C implementation, which is
probably faster anyway. Stupid Swift/Objective-C language mixing issues.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-26 01:15:03 -08:00
Christopher Snowhill
9f6134a588 Bug Fix: Attempt to make seeking more performant
Seeking should clear the buffers completely now, and will be nearly
instant, depending on how fast the input can decode.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-25 18:12:30 -08:00
Christopher Snowhill
375b019972 Bug Fix: Solve outstanding Equalizer bugs
This includes setting and unsetting the equalizer DSP chain objects on
track change and advancing on track playback end, and also bugs with
applying equalizer presets to the band configuration items when the
equalizer is disabled or when playback is stopped.

Fixes #420

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-23 21:16:46 -08:00
Christopher Snowhill
fa34d469df Bug Fix: Greatly improve seeking operations
Seeking now mutes properly, and will not leave the audio muted across
other operations. Audio output changes should also mute and destroy the
buffers of the input chain, so that the audio resets properly.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-23 19:59:13 -08:00
Christopher Snowhill
7c169f9ef1 Bug Fix: Stage seeking operation on main thread
This should not interact with the Audio Player object on a background
thread, but instead the main thread queue.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-23 19:59:06 -08:00
Christopher Snowhill
c02eabcf70 Bug Fix: Fix output volume from seeking
Fixes output volume setting on seek or audio output restart on format
change. Also safeguards these setters so they don't go off if the nodes
aren't actually allocated.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-23 18:58:55 -08:00
Christopher Snowhill
c45070138a Bug Fix: Playlist item out of range
This should never happen. But apparently it did.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-23 16:40:52 -08:00
Christopher Snowhill
c1665b6ee3 Crash Fix: Change background event to main thread
Two playback event items were set to queue a playback start to a
background thread, when playback should instead be queued on the main
thread. Fix this in a simple way.

This crash was easily reproducible by skipping through tracks rapidly.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-22 04:39:54 -08:00
Christopher Snowhill
e3209e8901 Bug Fix: Play Count data may be missing tags
Sometimes the play count data only includes the filenames, and thus will
fail a query for just the tags. Also, a file query may be stored without
the subsong fragment tag, which will also break the tags.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-20 01:27:16 -08:00
Christopher Snowhill
ff9bd89389 Bug Fix: Clean up input node class definition
Fix some missing items, and add nullability declarations.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-19 15:09:21 -08:00
Christopher Snowhill
e49ba8e3e0 Bug Fix: Crash fix sorting by several fields
Play Count sorting was entirely missing, and sample rate and bits per
sample sorting caused exceptions due to the capitalization of the fields
versus the column identifiers.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-19 15:09:16 -08:00
Christopher Snowhill
169c798bef Bug Fix: Hopefully fix pasting a list of paths
This should hopefully fix pasting from a list of file URLs.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-19 15:09:10 -08:00
Christopher Snowhill
122757b42a TagLib: Fix framework Info.plist again
The TagLib framework build process leaves several
key fields empty. This breaks App Store submission.

Fix it again. Dang.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-17 19:19:30 -08:00
Christopher Snowhill
0f1be5939d VGMStream: Clean up FFmpeg code somewhat
Remove deprecated functions, make use of free functions that clear the
pointers before returning, etc.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-17 18:33:29 -08:00
Christopher Snowhill
212ef0ffdf FFmpeg: Clean up code somewhat
Remove deprecated functions, make use of free functions that clear the
pointers before returning, etc.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-17 18:33:25 -08:00
Christopher Snowhill
1c92c56d75 Bug Fix: Adding tracks to playlist while in search
When adding tracks to the playlist, clear the search filter first, so
the playlist doesn't become all jumbled, or so we don't overflow the
playlist indexes.

Also add some bug fixes for reversing the arranged to disarranged index
lists, so if an arranged index is past the end of the arranged list, as
is the case for appending, we shift the indexes forward past the end of
the diarranged object list.

Extra exception handling was added as well, so these things will only
cause a failure to add playlist items at worst, instead of crashing the
player entirely.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-17 16:06:16 -08:00
Christopher Snowhill
2e884b9e85 TagLib: Implement preliminary writer class
This is not currently being used anywhere, but may function eventually.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-17 04:25:36 -08:00
Christopher Snowhill
7e23e80b24 TagLib: Update metadata readers
Update the readers to support the newly added tag fields, and also read
the supported format list from the library itself.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-17 04:25:30 -08:00
Christopher Snowhill
65e2da2d9e TagLib: Implement new field support
Implement the new fields into TagLib, pending contribution to upstream.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-17 04:25:24 -08:00
Christopher Snowhill
023d7e2ba7 Bug Fix: Hopefully fix flickering visualizations
Now buffer twice as much audio as would be requested for a single
visualization PCM/FFT chunk, which should hopefully prevent it from
flickering due to running out of audio because of too low latency.

Now it buffers up to two chunks at the current hard coded visualization
sample rate, which works out to about 186 milliseconds.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-16 14:20:02 -08:00
Christopher Snowhill
44b8aa0dd8 Minor Bug Fix: Handle Rubber Band buffer latency
We implement this function to return the current latency buffered,
regardless of how often this function may be called. In practice, it is
only called on track completion, to time the reporting of the next track
display. We also avoid using Rubber Band's latency function, as in most
cases, this function will be called from other threads, and also, it
currently only gets called after Rubber Band has been emptied out, so it
would otherwise calculate zero samples buffered. And thirdly, Rubber
Band's latency function doesn't account for the buffered samples already
removed from it and waiting to be fed out.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-16 14:06:30 -08:00
Christopher Snowhill
f251c91f02 Bug Fix: Rubber Band handles end of track gap
The code was polling the input chunk duration after emptying out the
chunk's samples, which resulted in an input duration account sitting at
exactly zero, so the end overrun flush would not be cut short properly,
resulting in gaps between tracks.

Correct the input sum to tabulate before emptying the input chunk, so
output remains properly gapless.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-16 14:06:25 -08:00
Christopher Snowhill
dd5be9b117 Bug Fix: Set seek position when resuming paused
And a minor reoder of seek time reset code.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-15 21:46:46 -08:00
Christopher Snowhill
b8698ea125 Bug Fix: Rework playlist setup again
In case playlist setup is reset or not, move the reset above the menu
setup code, so the menu is set up correctly if a reset occurs.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-15 20:23:42 -08:00
Christopher Snowhill
f239784bf2 Bug Fix: Change how bad playlist setup is handled
Reset to defaults if no columns are visible. Also log this situation in
Firebase events, in case it becomes relevant.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-15 20:10:09 -08:00
Christopher Snowhill
4face7d631 Audio: Unify playback setup of the converter
This code was being duplicated across three different playback functions
which basically did most of the same things.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-15 19:58:18 -08:00
Christopher Snowhill
04426d755c Bug Fix: Audio chain should do more error checking
Check all audio chain elements for allocation failures, and also dispose
of all of the previous handles in reverse order, including nulling the
final node handle so the output does not attempt to poll for audio while
the chain is being rebuilt.

Also set up output node to handle the new null finalNode state, and
return an empty chunk to the caller.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-15 19:58:12 -08:00
Christopher Snowhill
931da40b4d Bug Fix: Safeguard play count updates
Play Count cannot be updated for tracks which have been deleted before
the update was added to them. This was another cause of a rare crash.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-15 17:08:10 -08:00
Christopher Snowhill
0d289e47ab Bug Fix: Add safety checks to playlist columns
Playlist column setup needed a couple of safety checks to prevent
crashes from happening.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-15 14:09:35 -08:00
Christopher Snowhill
abf77a70d2 Bug Fix: Do not process format change on stop
We should not be processing a potential playback restart when the chain
is being torn down for shutdown.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-15 01:33:14 -08:00
Christopher Snowhill
923179c4eb Bug Fix: Significantly rework Rubber Band DSP
This should be perfectly safe to use in all situations now. It may have
been unstable due to mishandling return values, or not supporting
requesting more sample data from the library without feeding in more
input first.

Also, still signaling the End of Stream flag on chunk reading should be
correct, as downstream processors only react to it when the buffer runs
empty.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-14 19:43:24 -08:00
Christopher Snowhill
abd11ebc3b Opus: Boost priority of libopusfile decoder
This should take priority over the Core Audio and FFmpeg decoders.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-14 19:07:48 -08:00
Christopher Snowhill
632e53510c TagLib: Re-enable some file types
These may be handled by the Core Audio input, which does not read tags
on its own.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-14 19:04:14 -08:00
Christopher Snowhill
cdddcaecd8 Audio: Attempt to reduce glitching from seeking
Also applies to how output format changes are handled.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-14 18:51:36 -08:00
Christopher Snowhill
72a4a1c245 Bug Fix: Downmixer converter should update now
The Downmixer wasn't updating its output format correctly, so it was
prone to outputting the wrong format for a while, which could confuse
the output device and produce garbage output.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-14 18:51:31 -08:00
Christopher Snowhill
ab62de0fa2 Crash Fix: Fix HRTF resampler delay misuse
The delay value should be scaled by the resampling ratio, similar to
how it already is when allocating the impulse buffer. This went
undetected, as it scribbled over other memory without causing immediate
crashes, but instead later heap corruption.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-14 18:51:27 -08:00
Christopher Snowhill
75441bc5fa 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:27 -08:00
Christopher Snowhill
ae4c49ea68 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:17 -08:00
Christopher Snowhill
146dae216a Visualization: Optimize Swift code handling arrays
This looks a lot better than some ruddy for-loops.

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

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-13 19:58:30 -08:00
Christopher Snowhill
a40fcbca37 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:28 -08:00
Christopher Snowhill
aba5b8d120 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:55 -08:00
Christopher Snowhill
86ce3cf69b Equalizer: Fix to function properly
This was completely broken, oops.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-13 13:39:28 -08:00
Christopher Snowhill
fd8b20db86 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:42 -08:00
Christopher Snowhill
a0e68df0e2 Audio: General fixes and improvements
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-13 06:35:38 -08:00
Christopher Snowhill
5b8363c9ec 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:27:24 -08:00
Christopher Snowhill
d2284df683 FFmpeg Input: Fix stream timestamps
Stream timestamps were correctly being converted from the monotonically
increasing frame count, but the AudioChunk parameter was being set from
the frame count rather than the converted seconds count.

Fixes #418

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-13 03:27:11 -08:00
Christopher Snowhill
3ed6e8a6b9 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:52 -08:00
Christopher Snowhill
d9a08914df Visualization: Clean up Swift code a bit
Some of this is handled in simpler ways now.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-13 02:09:17 -08:00
Christopher Snowhill
81b7dcfc0c 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:13:15 -08:00
Christopher Snowhill
9701bd5421 Visualization: Do not increment latency on write
The latency should not be incremented when writing sample data to the
buffer, but rather be posted by the output.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-13 01:13:10 -08:00
Christopher Snowhill
3cc97b5574 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:13:06 -08:00
Christopher Snowhill
a78933ca80 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:13:03 -08:00
Christopher Snowhill
8790df1ef0 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:33 -08:00
Christopher Snowhill
9346a4edbd Audio: No longer force output sample rate
We were forcing a resampling ratio to match the HRTF filter supplied
with the app, now we resample the HRTF to match the input audio, which
will be resampled to match the output device settings.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-12 20:59:41 -08:00
Christopher Snowhill
b39882168b 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:57:22 -08:00
Christopher Snowhill
d17388ee95 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:13:53 -08:00
Christopher Snowhill
b913d423a2 Crashlytics: Add consent preferences defaults
These should have been defined already, but now they're the safe
defaults that should spring the dialog on startup, and doesn't grant
consent by default.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-12 20:11:22 -08:00
Christopher Snowhill
7543020291 Cleanup: Whitespace removal
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-12 19:01:29 -08:00
Christopher Snowhill
9fd393b64e Audio Output: Set higher priority on output thread
It's more like the output monitor thread, since it only monitors output,
rather than actually handing the output callbacks.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-12 19:01:25 -08:00
Christopher Snowhill
a82742e689 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 19:01:20 -08:00
Christopher Snowhill
2364a7d469 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:44 -08:00
Christopher Snowhill
7994929a80 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:43 -08:00
Christopher Snowhill
1e1ee2fbe2 Bug Fix: Fix resume playback on startup
In case multiple playlist entries are left marked as "current" in the
playlist database, resume playback on the first one, and unmark all the
rest of them.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 23:04:01 -08:00
Christopher Snowhill
b4c8c11218 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:02:55 -08:00
Christopher Snowhill
26efcda71a 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:01:13 -08:00
Christopher Snowhill
dc0a44067a DSP: Move HRTF filter to DSP class chain
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 21:17:58 -08:00
Christopher Snowhill
7179abe8ef 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 19:43:54 -08:00
Christopher Snowhill
724144accd 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 19:42:27 -08:00
Christopher Snowhill
0e608481d9 Output: Remove pointless scale value
This shouldn't have been applied, the problem with Rubber Band was the
flushing mechanism.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 18:12:51 -08:00
Christopher Snowhill
98bac743df 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:12:46 -08:00
Christopher Snowhill
cddfc3d1db 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:12:41 -08:00
Christopher Snowhill
cb8d873b5b 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 18:12:35 -08:00
Christopher Snowhill
9b3487b6e0 DSP: Stylistic change
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 18:12:30 -08:00
Christopher Snowhill
4890ee67a6 DSP: Whitespace changes
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 18:12:26 -08:00
Christopher Snowhill
9e82e2737e 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:42 -08:00
Christopher Snowhill
7d803a0211 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:10:38 -08:00
Christopher Snowhill
d6923781ef Preferences: Fix merge error
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 13:57:19 -08:00
d8d3265016 Changed term in Spanish translation
Yes, it's mostly used untranslated now...
2025-02-11 09:48:32 -03:00
Christopher Snowhill
7fc6361d6c Rubber Band: Fix preferences disabling items
The items not applicable to Finer / R3 engine were not being disabled
properly. Change the dialog to use a transformer to disable them on the
preferences value instead of coding it, since the code didn't seem to
work.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-11 01:28:42 -08:00
Christopher Snowhill
266da8cc07 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:27:28 -08:00
Christopher Snowhill
227ed0dfa3 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:25:26 -08:00
48d89d4496 Spanish translation for Rubber Band settings, and
for rubber band icon credits.
2025-02-10 20:07:21 -03:00
Christopher Snowhill
6f6773da09 Fix up team identifiers again
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-10 14:49:00 -08:00
Christopher Snowhill
ad074ec13e Rubber Band: Implement configuration dialog
Now there's a configuration dialog for tweaking the settings
in semi-real time. Everything that can be changed without
restarting is changed without restarting, otherwise the audio
pipeline is reset, which happens quickly enough anyway.

Awaiting translation to Spanish, other languages have been
removed pending their maintainers fixing most of their
problems, which includes me being lazy and AI translating
bits so I could rush updates.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-10 14:37:07 -08:00
Christopher Snowhill
e4b70f53ae Core Audio: Fix API header
Fix a function declaration that was missing its
parameter variable in the header.
2025-02-10 14:33:28 -08:00
Christopher Snowhill
5392a5fa91 Revert "Visualization: Tweak systems a bit"
This reverts commit 6c24ad8244.
2025-02-10 14:31:22 -08:00
Christopher Snowhill
591f3ceb18 Updated VGMStream to r1980-95-g551c0787
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-10 14:30:28 -08:00
Christopher Snowhill
6e53cebf5c Remove unmaintained translations
The Polish, Russian, and Turkish translations have
no active maintainers, so I was stupidly relying on
AI translation to fill in the newer things. These
translations will sit mostly idle until I get active
maintainers for them.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-10 14:12:42 -08:00
Christopher Snowhill
0b98c0ac98 Placeholder commit for Sparkle update
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-06 20:59:59 -08:00
Christopher Snowhill
6c24ad8244 Visualization: Tweak systems a bit
This should improve performance slightly. It's
still recommended to switch off SceneKit to
save CPU usage, or switch of vis entirely.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-01 15:08:56 -08:00
Christopher Snowhill
170fb06a62 Updated credits file and Patron list
Been a while since I did this. Oops.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-02-01 15:08:50 -08:00
Christopher Snowhill
f4cfad370d TagLib: Fix up project file
Gah, how in heck did Xcode end up inserting an absolute
path? Fix that, and some other leftovers.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-30 02:18:33 -08:00
Christopher Snowhill
dc81605343 TagLib: Fix framework Info.plist
The TagLib framework build process leaves several
key fields empty. This breaks App Store submission.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-30 01:45:41 -08:00
Christopher Snowhill
994d0e328e SID: Add exception handling
Exception handling was quite missing from this code
as well. Let's fix that too.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-30 01:17:56 -08:00
Christopher Snowhill
ffa46ae2d0 OpenMPT: Update exception handling
Make exception handling more robust and thorough. Never
know what may happen, make sure to handle most cases.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-30 01:17:49 -08:00
Christopher Snowhill
cd95cd68f8 MIDI: Add exception handling
Both the midi_processing and the various players may
throw exceptions, so we should check for these too.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-30 01:17:44 -08:00
Christopher Snowhill
d835c252fa Highly Complete: Add exception handling for NCSF
SSEQPlayer throws exceptions, there should be exception
handling to catch them and fail gracefully.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-30 01:17:39 -08:00
Christopher Snowhill
7777e50f03 TagLib: Add exception handling
The TagLib C++ code was missing generic try/catch handling
which could result in any generic errors throwing straight
to a full crash. Add exception handling and logging, which
will fix a logged crash regardless of whether the tags are
read correctly or not by the newer TagLib version.

Fixes #415

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-29 23:57:36 -08:00
Christopher Snowhill
b0414f4399 TagLib: Replace bundled copy with upstream 2.0.2
Include a Framework build, unmodified, RelWithDbgInfo.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-29 23:42:31 -08:00
Christopher Snowhill
a873441484 Updated VGMStream to r1980-54-g35c8283f
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-26 01:17:55 -08:00
Christopher Snowhill
dd4a0b7af3 Playlist View: Save column settings differently
You will need to reset your settings after this, but then it should
stay put for the indefinite future.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-26 01:17:47 -08:00
cfa4e078ea
Update bug_report.md 2025-01-20 19:18:40 -03:00
Christopher Snowhill
b0368a7010 Visualization: Fix race condition on first launch crashing
Due to a race condition with the visualization control racing with
the Crashlytics consent dialog, it was possible that the repaint
function would be called before the control was fully initialized,
which would cause the visualization drawing code to crash due to
division by zero error.

The fix is two-fold: First guards were added to the borrowed
code so that the draw functions won't run if they would later
divide by zero on an uninitialized width property. Secondly, the
top level visualization windows added a startup variable guard
so their drawing code will return immediately if setup has not
completed yet.

Note that this bug was only just noticed in a recent App Store
submission, but was unrelated to the recent commits to the code
base, and could have triggered much earlier in the development
cycle. Strangely, it did not.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-15 17:43:03 -08:00
Christopher Snowhill
458d0a3824 Playlist: Added play count column
It should also be possible to sort by the column, ascending or
descending. This also necessitated adding playlist row refreshing
for play count updates.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-14 23:38:22 -08:00
Christopher Snowhill
838d5ca9f7 Highly Complete: Fix crash on paths containing URL escapes
In the event of local paths containing not just UTF-8 characters,
but also un-decoded URL percent sequences, which will end up double
encoded in the player, code which reverses percent encoding should
later re-apply it.

Apparently, this whole time, since the last code overhaul, the
URL encoding was being stripped, then the file opener was converting
these paths back into URLs without re-encoding, which didn't break
until someone played an album in a folder containing a partially
decoded UTF-8 sequence. Thanks, Zophar's Domain, and whoever ripped
the Golden Sun GSF set for finding this bug!

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-14 21:25:52 -08:00
Christopher Snowhill
7e98a0398b Updated libOpenMPT to version 0.7.13
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-10 14:38:44 -08:00
Christopher Snowhill
e400fafa5d Dependencies: Updated mpg123 to 1.32.10
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-10 14:37:59 -08:00
Christopher Snowhill
8bc2d3cd38 Audio/HRTF: Make head tracking optional, add reset button
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-03 15:24:02 -08:00
Christopher Snowhill
68c334d96e Updated VGMStream to r1980-0-ged9a7202
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-03 02:31:11 -08:00
Christopher Snowhill
9f07f04ed6 Audio/extrapolator: Fix short prime length
When the input buffer has less samples in it than the LPC order,
it would crash reaching past the ends of the buffer. Now, it will
pad past the correct end of the audio with silence, while still
extrapolating a prime input minimum of the LPC order. Should fix
the last of the outstanding crashes.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-03 02:18:35 -08:00
Christopher Snowhill
0707c4bb71 Notification: Fix album date assignment
The NSCalendar assignment should have a placeholder month and day
of January 1st, instead of the invalid month/day of 0/0. Also,
even if this somehow fails, don't attempt to assign it if it
returns nil.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-03 01:28:07 -08:00
Christopher Snowhill
75ef35efa6 FileTree: Fix handling of metadata with multiple values
Goody, my metadata formatting comes back to bite me.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-03 01:19:24 -08:00
Christopher Snowhill
d89c9c852f Chore: Update copyright dates somewhat
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-01-01 01:31:10 -08:00
Christopher Snowhill
eb72b73e6c FFmpeg: Move some error buffers around
Since in one case, it probably wasn't combining them into one stack
allocation, it probably blew up the stack allocation quite a bit.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-12-09 18:04:56 -08:00
Christopher Snowhill
9c6915ecb2 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 18:04:34 -08:00
Christopher Snowhill
59f3f416ba Updated VGMStream to r1951-102-gf1483e22
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-12-04 23:14:53 -08:00
Christopher Snowhill
7e3112efc0 Updated libOpenMPT to version 0.7.12
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-12-04 23:14:47 -08:00
Christopher Snowhill
afe65df6c6 Minor corrections to Polish translation
mpan told me these were broken, oops. One of them
may as well not be translated until it gets a proper
translation.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-11-24 21:30:28 -08:00
Christopher Snowhill
f5be598311 Add support for custom Dock icons while running
The emoji labeled buttons will convert and save their respective
state icon to the settings folder, and refresh the current icon
as necessary.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-11-24 21:30:22 -08:00
Christopher Snowhill
aa491fe0bb Updated VGMStream to r1951-100-g73ef7c6c
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-11-24 15:09:07 -08:00
Christopher Snowhill
de43b1b226 Fix FreeSurround being broken by the speed control
It should be deriving its channel count from the file format,
since it's applied before any other filters.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-11-24 15:08:44 -08:00
Christopher Snowhill
db5b4e68c2 Updated libOpenMPT to version 0.7.11
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-10-30 23:58:46 -07:00
Christopher Snowhill
820a1dedfb Updated VGMStream to r1951-88-g02d3c3f8
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-10-30 23:58:13 -07:00
Christopher Snowhill
ef8dd958ae Reorder project file entries with a sort 2024-09-20 22:25:23 -07:00
Christopher Snowhill
eba9dc2c43 Remove unused variable 2024-09-20 22:25:17 -07:00
Christopher Snowhill
6a309a3075 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:25:12 -07:00
Christopher Snowhill
2e5140a321 Visualization: Make latency animation smoother
Compensate for latency by incrementing an offset
according to animation frame rate.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-09-20 22:25:02 -07:00
Christopher Snowhill
edbdc8d98e Update Github workflow
Update checkout and upload artifacts to latest versions
2024-09-17 02:42:04 -07:00
Christopher Snowhill
a3e6636731 VGMStream: Fix fade time configuration
Fade time was reading from some completely wrong
configuration field name, so fades weren't working.
2024-09-17 02:26:07 -07:00
Christopher Snowhill
389f56e392 VGMStream: Change render API, allocate off heap
Change to the future render api, hopefully float support
will be available eventually. Also change to allocate the
sample buffers from the heap instead of the stack.
2024-09-17 02:26:01 -07:00
Christopher Snowhill
de24bd4560 Updated VGMStream to r1951-50-g1d836a36 2024-09-17 02:25:20 -07:00
Christopher Snowhill
fcddcdce61 Updated VGMStream to r1951-0-g4b2dc01c
Updated to add one new extension, too.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-08-23 23:07:13 -07:00
Christopher Snowhill
ba91d2e5ba Downgrade SwiftPM pins format version number
Apparently Github's old ass version of Xcode can't handle a 3 instead
of a 2 here. Whatever.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-08-18 04:13:10 -07:00
Christopher Snowhill
b997a6d5dc Downgrade Firebase to version 10.x
Version 11.0 requires macOS 10.15, and I haven't raised the minimum
deployment version that far yet.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-08-17 15:36:31 -07:00
Christopher Snowhill
63264de462 Update Firebase SDK to version 11.0.0 minimum
This should fix the Framework packaging issues App Store noticed.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-08-17 15:31:20 -07:00
Christopher Snowhill
256c99badd Update Copyright year to 2024 manually
Including extending existing starting-2023 dates to ranges.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-08-17 05:08:02 -07:00
Christopher Snowhill
d3415a3a25 Updated libOpenMPT to version 0.7.9
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-08-17 03:34:02 -07:00
Christopher Snowhill
03b52685bd Update PluginController.mm
Add missing definitions to the Info.plist template generator.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-08-17 03:23:29 -07:00
Christopher Snowhill
4d11ba266e Update Info.plist.template
Clean up duplicate definitions.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-08-17 03:23:22 -07:00
Christopher Snowhill
6dd01e07c1 Updated VGMStream to r1917-201-g7ab622d3
Also updated filename extensions,  and the interface plugins.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2024-08-17 03:23:08 -07:00
Christopher Snowhill
b701a4d347 Placeholder commit for Sparkle update 2024-08-07 23:17:22 -07:00
Christopher Snowhill
9f0ef52fd4 Update FFmpeg to version 7.0 and rebuilt soxr
Rebuilt libsoxr, which now removes the dependency on libavutil.
2024-08-07 23:17:04 -07:00
Christopher Snowhill
42ea824972
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:42 -07:00
Christopher Snowhill
1c95771ed0
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:39 -07:00
Christopher Snowhill
bc330e75f6
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:33 -07:00
Christopher Snowhill
87684a7974
CI: Hopefully fix this time
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-04 02:10:34 -07:00
Christopher Snowhill
5e27f084e9
Add a cache shutdown guard
This appears to maybe be necessary as the prior join call doesn't seem to
be doing what it should.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-03 22:59:38 -07:00
Christopher Snowhill
8997ffa030
Update libFLAC to version 1.4.3
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-03 22:59:34 -07:00
Christopher Snowhill
2fc42ccb73
CI: Switch to Xcode 15
Apparently, the build images are broken or something.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-03 22:02:52 -07:00
Christopher Snowhill
1eee2fbf11
CI: Switch to latest macOS and latest stable Xcode
Switch the CI image to the latest stable OS version, and latest stable
Xcode version, selected by another action.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-03 21:29:59 -07:00
Christopher Snowhill
6b2964328a
Remove redundant track end checker
This is checked inside the audio thread, it isn't needed in the watcher
thread. Remove the second check.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-03 21:29:54 -07:00
Christopher Snowhill
1f497ee8bb
Added Usage Description translations
Spanish translation provided by Kevin López Brante.
Polish, Russian, and Turkish translations of specifically these messages
provided by GPT-4, to be replaced by human translations if our
translators offer them, but it's been a while since I've gotten an update
out and I didn't really want to wait so long.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-03 20:35:50 -07:00
Christopher Snowhill
73252a8928
Reduce audio buffering slightly again
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-03 19:46:30 -07:00
Christopher Snowhill
b07a6fd098
Visualization: Improve latency and buffering appearance
Adjust the buffering so if latency is too low, we fill the rest of
the output with silence instead of peeking at the oldest part
of the buffer. Also increase latency by half a buffer size so
that the requested sample is in the center of the buffer, which
improves the 4096 sample situation with the current low
latency output.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-03 19:35:20 -07:00
Christopher Snowhill
2102fc1c44
Visualization: Reset buffer on playback stop
Reset the visualization system when stopping playback.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-03 19:35:16 -07:00
Christopher Snowhill
09f7496d9a
Initial implementation of positional audio for macOS Sonoma
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-03 05:01:07 -07:00
Christopher Snowhill
4ced731194
Replace hard coded Pi constant with M_PI
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-03 05:01:03 -07:00
Christopher Snowhill
8c67b6c2f7
Significantly improve memory usage of loading tags
This especially helps with bad or brutal files.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-03 05:00:59 -07:00
Christopher Snowhill
d88a90e5b0
Fix a typo
Notifcation -> Notification

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-03 05:00:55 -07:00
Christopher Snowhill
122b6d6a6d
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 05:00:51 -07:00
Christopher Snowhill
fb72db74f8
Stop visualizer feed for stopped playback
A stopped instance of OutputCoreAudio should not continue to feed the
visualization system with stale audio, potentially while another instance
is already starting up and feeding its own audio output.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-03 05:00:47 -07:00
Christopher Snowhill
2987857b93
Fix a missing do on a do-while block
This should be looping on the condition, not sure
how the compiler missed this one.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-03 05:00:43 -07:00
Christopher Snowhill
df198110ed
Hopefully fix format change on end of track
This should keep the audio pipeline flowing either way.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-03 05:00:38 -07:00
Christopher Snowhill
4ddca15a8f
Simplify HRTF filter, change option to reflect it
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-02 10:57:11 -07:00
Christopher Snowhill
919661c9e8
Attempt to stabilize visualization flutter
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-02 10:57:06 -07:00
Christopher Snowhill
cfd5b1c6fb
Fix converter after output switchover
This was missing, too.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-02 10:57:01 -07:00
Christopher Snowhill
a2e4fa17b2
Fix further bugs with output switchover
Change some things I missed.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-02 10:56:56 -07:00
Christopher Snowhill
e59c7be0b8
Update BASS and friends for Xcode 15
This is needed for the Intel build target to work.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-02 10:56:44 -07:00
Christopher Snowhill
9e96bb2b75
Add missing Info.plist strings
These strings were added to the InfoPlist translations in a
previous commit, but likely need to be added to the
Info.plist file directly as well.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-02 10:56:39 -07:00
Christopher Snowhill
7ab2a8305a
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:56:33 -07:00
Christopher Snowhill
5e36affad8
Hopefully fix crashes from rapidly skipping files
Do this by serializing the background thread actions against
the AudioPlayer object, so we don't start playback multiple
times at once.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-10-02 10:56:28 -07:00
Christopher Snowhill
e85b5eea34
Privacy - Added Spanish translation
Translation provided by team member, Kevin López Brante.
2023-09-03 16:51:50 -07:00
Christopher Snowhill
f3d218fd3d
Privacy: Added purpose strings
The other translations currently have placeholders, awaiting translation.
I may end up using machine translation from Deepl just for Russian,
Polish, and Turkish, until I get human translations from a contributor.
Spanish will be provided by our team later tonight.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-09-03 16:39:04 -07:00
Christopher Snowhill
f54dd1c7b1
Playback: Start playback and seek in the background
Perform playback start and seeking operations in the background, instead
of on the main thread, which should help prevent them from stalling the
user interface.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-09-02 22:28:05 -07:00
Christopher Snowhill
d4196a5595
Updated Translations
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-09-02 21:42:05 -07:00
Christopher Snowhill
09c9711b50
Touched by Xcode
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-09-02 21:42:00 -07:00
Christopher Snowhill
40b5bf7e13
Updated VGMStream to r1866-46-g883d796d
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-09-02 21:41:56 -07:00
Christopher Snowhill
fb208b4cd5
MainMenu: Touched by Xcode
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-09-02 21:41:50 -07:00
Christopher Snowhill
57158da628
AppleScript: Implemented Composer field
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-09-02 21:41:46 -07:00
Christopher Snowhill
a01d9ee5b3
Info Inspector: Implemented Composer field
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-09-02 21:41:42 -07:00
Christopher Snowhill
9593902aff
Playlist: Implemented Composer column
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-09-02 21:41:37 -07:00
Christopher Snowhill
a3c8149612
Tags: Expose Composer tag through interfaces
Implement the composer field interface to playlist item tag
reading and writing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-09-02 21:41:33 -07:00
Christopher Snowhill
1bffcaa429
TagLib: Remove stray whitespace
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-09-02 21:41:29 -07:00
Christopher Snowhill
d62d5f1279
TagLib: Implement Composer tag support
Most of the reading was already there, it just didn't expose
it to the player.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-09-02 21:41:24 -07:00
Christopher Snowhill
11dcac6b04
ASF/WMA: Implement Album Artist tags (oops)
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-09-02 21:41:20 -07:00
Christopher Snowhill
5b9e5be295
Add a bitrate column to the playlist
Adds a bitrate column to the playlist view, which is fully sortable.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-08-20 23:48:22 -07:00
Christopher Snowhill
0f6b403b43
Fix rating sorting
This apparently fixes sorting by rating.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-08-20 23:48:17 -07:00
Christopher Snowhill
03e510fa92
Add missing column header translations
These column header names were missing from the strings
tables. Add them based on existing translations of the same
field names by our translators.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-08-20 23:48:12 -07:00
Christopher Snowhill
1dbaa61313
Touched by Xcode
Miscellaneous XIB changes automatically applied by Xcode
when editing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-08-20 23:48:07 -07:00
Christopher Snowhill
bfe2f03fbb
Fix sorting for missing columns
This should fix the sorting for rating, sample rate and bits per sample

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-08-20 23:48:02 -07:00
Christopher Snowhill
702a52a93e
Attempt to make project build with Xcode 15
This is supposed to fix running on macOS 10.13, but it doesn't.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-08-20 23:47:58 -07:00
Christopher Snowhill
eae6c96b5e
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:37:37 -07:00
Christopher Snowhill
fc2d96831d
Don't pause streams, stop instead
Do not bother to pause streamed files, instead stop playback when pause
is requested.

Fixes #372

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-29 01:37:33 -07:00
Christopher Snowhill
587ccd6a0d
Fix Repeat menu being disabled, change default
Default repeat mode should now be Repeat All, and the menu items should
now all function, fixed by removing a bunch of pointless attributes from
each affected menu item.

Fixes #371

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-29 01:37:29 -07:00
Christopher Snowhill
a4ff143600
Touched by Xcode
Resource scripts touched by Xcode again

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-29 01:37:24 -07:00
Christopher Snowhill
a49456f44b
Stash a Core Audio output, kind of glitchy
This output may prove to have lower latency, but the results are too
glitchy to really be usable. Not even visualization latency is handled
correctly.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-29 01:37:19 -07:00
Christopher Snowhill
f642a066f8
MIDI: Properly bundle the BASS Musepack plugin
This is imported by the player, though it doesn't fail when it's
missing, so that would explain why I didn't spot this error sooner.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-21 02:41:26 -07:00
Christopher Snowhill
fa1b632a59
MIDI: Stop linking BASS plugins directly
They'll be imported by the plugin on startup anyway, and they don't
really have any exported functions we can use.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-21 02:41:21 -07:00
Christopher Snowhill
d3ca6c390c
Disable dead code stripping
No idea why this was enabled, no idea if I should disable it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-21 02:41:14 -07:00
Christopher Snowhill
99578a333e
APL+CUE: Revert pointless change
This change served no purpose, other than to confuse me. I must need
some sleep already.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-21 00:25:11 -07:00
Christopher Snowhill
c3070e5f39
APL: Stop on the correct sample
This should stop before the specified end point, not one sample later.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-21 00:20:04 -07:00
Christopher Snowhill
dd7340d6d5
APL: Fix position handling for DSD
Correctly scale the AudioChunk frame counts. This more and more makes me
think I should be scaling this in the AudioChunk code instead, but then
code may not know about the special case of every 8 frames only being
one byte per channel.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-21 00:18:53 -07:00
Christopher Snowhill
e7d6ab88ce
APL: Round bits per sample to an even byte
Round this variable up.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-21 00:18:49 -07:00
Christopher Snowhill
16072b3af3
CUE: Fix playback position tracking for DSD
DSD wasn't tracking the correct sample count, because DSD
Audio Chunks store the byte count, rather than the bit count.
This may be changed in the future, so I'll have to remember.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-21 00:18:44 -07:00
Christopher Snowhill
440ba24c57
CUE: Stop on the correct sample
Stop before the end, rather than on it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-21 00:18:40 -07:00
Christopher Snowhill
37fc054739
CUE: Round up bits per sample
Round bits per sample to an even byte.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-21 00:18:36 -07:00
Christopher Snowhill
8ad84c3aed
Add status messages to updater script
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-21 00:18:31 -07:00
Christopher Snowhill
2d7a7480d9
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:39 -07:00
Christopher Snowhill
09aa0d96e1
Work around rounding error with resampler flush
Resampler flush may indefinitely produce 1 sample if there is a rounding
error with the buffering calculations. Work around this.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-14 05:16:34 -07:00
Christopher Snowhill
3d24168ba7
Fix clipped sample rate changing between files
When the clipped sample rate changes, the resampler needs to be
restarted. This was previously failing because the target sample rate
wasn't changing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-07-14 05:16:30 -07:00
Christopher Snowhill
323a554832
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:14 -07:00
Christopher Snowhill
ffbc571660
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:11:04 -07:00
Christopher Snowhill
efd1349a59
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:10:10 -07:00
Christopher Snowhill
728ae813c5
Updated libOpenMPT to version 0.7.2
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-06-30 23:32:01 -07:00
Christopher Snowhill
0be8dbe7c5
Updated VGMStream to r1843-92-g740a4048
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-06-30 23:31:49 -07:00
Christopher Snowhill
270cf79bb7
Change default open to enqueue and play
Instead of clear playlist and play. This was confusing people,
apparently. I should have changed it sooner, since this is what
I use normally anyway.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-06-30 23:31:34 -07:00
Christopher Snowhill
0efc3d4ad7
Add fade global shortcut
Defaulting to ctrl-cmd-O, though I may change this if
someone has any better ideas for a default.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-06-30 23:31:10 -07:00
Christopher Snowhill
0fb28001f9
Touched by Xcode
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-06-30 23:30:48 -07:00
Christopher Snowhill
207fee1a50
Change "Spam" to "Copy now playing"
Change the not-obviously-named shortcut to something more
obviously named after its purpose.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-06-30 23:30:03 -07:00
Christopher Snowhill
a366cbadee
Remove a saucy option
Nobody was likely to be using it, much less even know what it was.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-06-13 22:42:13 -07:00
Christopher Snowhill
3c91aab9d8
Updated BASS and company
Also included missing BASS_MPC, which was still being imported
even though it wasn't actually included.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-06-12 17:29:01 -07:00
Christopher Snowhill
3689fb51f8 Update MASShortcut for Xcode 15
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-06-08 04:40:44 -07:00
Christopher Snowhill
e1e5c22b8a Touched by Xcode
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-06-08 04:40:32 -07:00
Christopher Snowhill
cb0ae6db6c
Organya: Fix deployment target for 10.13
Oops, it was somehow still set to 13.0, from when I created it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-06-08 04:15:41 -07:00
Christopher Snowhill
39459b89cb
Update projects and source in prep for Xcode 15
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-06-08 04:14:45 -07:00
Christopher Snowhill
5aaea62b54
About Dialog: Move logo to asset catalog
Also convert it to a supported HEIF format, making it much smaller.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-06-08 04:14:38 -07:00
Shoh Sewell
baf9797907 Volume slider changes
Makes volume slider logarithmic when limited to 100% to allow easier changing of volume towards the bottom of the slider.
The tooltip remains as the slider location instead of the logarithmic value of the actual volume.
2023-06-08 02:10:15 -07:00
Christopher Snowhill
dd630ba394
File Tree: Reduce monitoring to limited changes
Only track new, removed, or renamed files. Tracking Xattr changes was
apparently causing the tracker dialog to crash on things like the user
changing file type associations, which either added or removed a per-
file association xattr, or when clicking Change All, removed this xattr
from all associated files tracked by Spotlight.

Fixes #361

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-06-04 01:37:46 -07:00
Christopher Snowhill
a640627fe1
Playlist: Add a workaround for AppleStript URLs
AppleScript is apparently such a legacy system, that when it sends URLs
to your app to open, they're in the old Carbon format. So we need to
translate these to proper URL strings for the rest of the app to deal
with them at all.

The format of these URLs is as follows:

/method/::

Followed optionally by:

username/password@

Where the slash and password are optional.

Followed by:

hostname

Followed optionally by:

/portnumber

And finally, followed by:

:path:on:server:filename.ext

So, in hostname field, we must swap slashes to colons. And in the path
field, swap colons to slashes. What a bizarre world.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-06-01 21:34:34 -07:00
Christopher Snowhill
5550af7e64
HTTP Input: Do not hang if transfer completes
If transfer completes quickly, do not hang waiting for it to achieve
reading state. Also add some comments indicating what we're doing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-06-01 21:34:29 -07:00
Christopher Snowhill
e0a1cf49e7
Metadata: Fixes metadata reading
metadataBlob may be null, so create dictionary in that case.

Fixes #360

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-06-01 15:15:36 -07:00
Christopher Snowhill
391b9cf6dc
Update feed updater script for R2
Update to use rclone with out of tree config to upload

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-06-01 00:15:03 -07:00
Christopher Snowhill
689010b714
Playlist: Fix merging dynamic metadata dictionary
Merge the existing metadata entry dictionary with new values, because
sometimes, the caller may pass us a dictionary with some fields missing.

Fixes stream metadata for many HTTP streams.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-05-31 22:36:04 -07:00
Christopher Snowhill
c88c9e9aa0
HTTP: Support a stream title hack
Support a stream title hack employed by some iHeartRadio streams

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-05-31 22:36:00 -07:00
Christopher Snowhill
90eb2ded1d
HTTP: Support much larger metadata blocks
Support icy metaint data blocks up to 4KiB in size

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-05-31 22:35:45 -07:00
Christopher Snowhill
7640c869de
Updated VGMStream to r1843-0-gb158e812
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-05-31 22:35:40 -07:00
Christopher Snowhill
1ef7853488
FFmpeg: Fix AAC streaming
Fix AAC streaming by adding the correct audio/aac MIME type.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-05-31 22:35:36 -07:00
Christopher Snowhill
e7692dc40b
Touched by Xcode
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-05-04 18:23:06 -07:00
Christopher Snowhill
b9768e8100
Updated Turkish translation to near completion
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-05-04 18:22:53 -07:00
Christopher Snowhill
d2adf39e04
Updated VGMStream to r1831-27-ge6883cbd
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-05-04 18:22:08 -07:00
Christopher Snowhill
dfa5f41984
Updated libOpenMPT to version 0.7
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-05-04 18:20:54 -07:00
C.W. Betts
49bfd5053f Move most image assets to Xcode assets.
AboutCog.jp2 isn't moved because Xcode/Xcode assets doesn't recognize jp2 files as images.
2023-05-03 17:59:50 -07:00
Shoh Sewell
9c5a7d0e3e
Adds decimal digits to volume slider tooltip (#356)
* Adds decimal digits to volume slider tooltip

Modifies the volume slider tooltip so that:
-If the volume slider falls below 10%, the volume tooltip will display one decimal digit of precision (e.g. 3.4%).
-Else if the volume slider falls below 1%, display one decimal digit of precision (e.g. 0.34%).
-Otherwise display the volume slider tooltip as normal.

This helps show changes in volume between 0% and 10% where a change in volume isn't shown in the UI but is heard (especially when the "Limit volume control to 100%" option is unchecked in the "Output" Preferences submenu.

* Update VolumeSlider.m

Fix variable declaration

---------

Co-authored-by: Christopher Snowhill <chris@kode54.net>
2023-05-03 17:59:24 -07:00
Christopher Snowhill
07680673f8
Translation: Added Turkish language support
This translation is mostly complete.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-02-23 22:44:43 -08:00
Christopher Snowhill
37de4dc447
Translation: Updated Spanish translation
Added the new Lyrics window strings.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-02-23 22:44:38 -08:00
Christopher Snowhill
55e28973d1
Main Menu: Add new Lyrics item to strings tables
Add item to strings tables for translations of the menu item. English is
already done as the base language, awaiting Spanish at least, will await
Polish and Russian when the respective translators get to it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-02-23 18:25:46 -08:00
Christopher Snowhill
e7b0b8bbb1
Lyrics Window: Added localization templates
Awaiting localizations of the window name in currently supported
languages.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-02-23 18:18:50 -08:00
Christopher Snowhill
3347cbf1da
Lyrics Window: Touched by Xcode
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-02-23 18:18:03 -08:00
Christopher Snowhill
48f339f25b
Info Window: Reorder header imports
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-02-23 17:47:32 -08:00
Christopher Snowhill
420d706979
Lyrics: Implement Lyrics window display and hotkey
Implement Lyrics window display into main app as a popup window panel,
with a main menu hotkey.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-02-23 17:47:27 -08:00
Christopher Snowhill
8eaafe8f9b
Tags: Implement unsynced lyrics in Vorbis plugin
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-02-23 17:47:23 -08:00
Christopher Snowhill
7b98a64035
Tags: Implement unsynced lyrics in Opus plugin
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-02-23 17:47:19 -08:00
Christopher Snowhill
403f02f961
Tags: Implement unsynced lyrics in Flac plugin
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-02-23 17:47:15 -08:00
Christopher Snowhill
abbb2fece7
Tags: Implement unsynced lyrics in FFmpeg plugin
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-02-23 17:47:11 -08:00
Christopher Snowhill
e66b01b6db
Tags: Implement unsynced lyrics into TagLib plugin
Implement unsynced lyrics reading into TagLib frontend plugin.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-02-23 17:47:08 -08:00
Christopher Snowhill
a21242db55
TagLib: Implement unsynced lyrics tag support
Implement unsynced lyrics tag reading and writing into TagLib.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-02-23 17:47:04 -08:00
Christopher Snowhill
7e2a286b83
Tags: Added unsynced lyrics tag interface
Added an unsynced lyrics tag interface to the PlaylistEntry class

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-02-23 17:46:59 -08:00
Christopher Snowhill
ed281eb743
Update copyright year in various places
Update these things a bit for the next release.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-02-05 16:46:31 -08:00
Christopher Snowhill
d5720e3944
Updated VGMStream to r1810-97-g408cada5
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-02-04 23:52:34 -08:00
Christopher Snowhill
66338e2c83
Updated libOpenMPT to version 0.6.8
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-02-04 23:51:44 -08:00
Christopher Snowhill
4617654b57
Repair SceneKit project definition
Repair the SceneKit container definition in the Xcode project file, so
that the Visualization scene gets copied properly on project build.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-02-04 23:48:04 -08:00
Christopher Snowhill
d4785e0c74
Replaced r8brain with libsoxr
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2023-02-04 23:47:54 -08:00
Christopher Snowhill
e1fb7b9bd7
Playback Controller: Fixed title bar updating
This change had several components. For one, the delay of the dispatch
was increased from 5 milliseconds to 50 milliseconds. Two, the post to
the notification center was included in the delayed dispatch, so that
retains the PlaylistEntry object. Finally, the playlistController's
currentEntry object is reassigned from the input PlaylistEntry object,
which facilitates all watchers which are observing that variable for
updates. This final step also retains self for the callback, which
should be fine, since it's a quick dispatch with a short delay.

Fixes #335

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-12-09 22:34:47 -08:00
Christopher Snowhill
9822dcc4c0
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:17:45 -08:00
Christopher Snowhill
447a60afd9
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:14:45 -08:00
Christopher Snowhill
4f942ac890
Playback Controller: Remove "stopping" status use
This should not really be necessary for proper player operation any
longer, and can safely be removed.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-12-09 21:13:12 -08:00
Christopher Snowhill
02c5ccaae1
Sandbox: Rework several blocking actions
Several actions have been reworked to be non-blocking, as their
operation should still occur in the main thread, but should not block
the thread they are called from, as they are not required to continue
processing there.

End of secure access has also been made non-blocking, as it is usually
only called when an input is done accessing a given file or folder, so
it should be important to return quickly, as the input is likely about
to terminate, and other things are waiting for it to return.

Also remove a nested block call for the storage access, as it is within
an existing serializing block, so it shouldn't need to be nested.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-12-09 21:12:33 -08:00
Christopher Snowhill
e8caede273
Update script: Purge cache of manifest files
Purge the manifest files from the Bunny CDN cache before starting
the update of the site.
2022-12-05 23:18:29 -08:00
Christopher Snowhill
1c09694f1b
Decoders: Implemented Organya decoder
Based on the C++11 code by Joel Yliluoma / bisqwit, which in turn is
based on information from NX-Engine. I have also taken the liberty of
bundling the required wavetable bank and PixTone drums. Contrary to the
documentation provided with the code, my version of dou_1006.zip, as
downloaded over a decade ago, had the wavetable bank at offset 635,816
bytes into the file, not 1,115,748 bytes. Possibly a difference of
having applied the translation patch? My copy is the original version,
so I had to use a real resource parser to locate the waveforms.

The player will obey the configured sample rate, loop count, and fade
time for synthesizers, and also obey Repeat One to play indefinitely.
The code should be quite robust to minor abuses, though I can't imagine
how well it would hold up to random bad files, other than playing
outright garbage.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-12-04 03:03:45 -08:00
Christopher Snowhill
6023acc10e
Sandbox: Fixed another outstanding sync bug
Releasing sandbox access was incorrectly synchronizing on the object,
but still running code in the calling thread. It has been updated to
match the rest of the interface, which serializes all access through the
main thread only. This should prevent the sandbox from carrying stale
handles to already-released objects.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-12-03 22:13:14 -08:00
Christopher Snowhill
466d07dccb
Resampler: Update r8brain-free-src to v6.2
This should improve performance significantly for downsampling.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-12-03 22:10:50 -08:00
Christopher Snowhill
547f4ea012
Fix SceneKit visualization
Must always remember to have xcode-select set to Xcode.app and not
the Command Line Tools when archiving the app myself, as otherwise
Xcode will fail to package the SceneKit objects into the resulting
bundle.
2022-11-30 01:12:15 -08:00
Christopher Snowhill
d7d6014789
Sandbox Broker: Fixed a potential reference crash
The code which looked up Sandbox handles for a given path had a bug
where it would re-add the handle to the in-memory cache storage even if
it already had just retrieved the current handle from the cache. I hope
this will fix the crashes which have been plaguing people adding a lot
of files to the playlist all at once from a single folder.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-11-29 00:54:16 -08:00
Christopher Snowhill
ecd46cfa3c
Updated VGMStream to r1800-25-g599326a3
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-11-29 00:54:05 -08:00
Christopher Snowhill
cd55a0b08c
Dependencies: Update libVGM release and debug
Update from 0e34925..fd7da37, with the following changes:

- C140: simplify update loop, add unbanked mode
  - It resembles MAME's code more closely now.

- OKIM6258: make more tolerant against late writes

- enforce "discrete YM3438" mode for YM3438 VGMs

- Update emu2413 to v1.5.9

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-11-29 00:49:43 -08:00
Christopher Snowhill
56ea4a5428
Update Script: Change feed upload to Bunny CDN
Change upload script to use curl to upload to Bunny. The access
key is stored in the system keychain, with confirmation on access.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-11-07 00:00:19 -08:00
Christopher Snowhill
c850d7752f
Vorbis Plugin: Remove unnecessary shell script
Remove shell script that was modifying the import path of a framework,
as we are no longer using libvorbis like that.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-11-06 00:50:01 -07:00
Christopher Snowhill
1d1babd2bb
Add display name and category to project
Add display name and category fields to project. Thanks, Apple, for
adding those to Xcode all of a sudden.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-11-05 00:48:57 -07:00
Christopher Snowhill
08f2dabc81
Info plist: Add newly required keys
For some reason, Xcode isn't adding these now. No idea what Apple
has done to cause this.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-11-05 00:43:43 -07:00
Christopher Snowhill
445b1bb295
Sandbox Broker: Fix hang with synchronization
Synchronize with dispatches to the main thread instead of using
synchronization primitives. This prevents the main thread from
hanging another thread as a result of other threads entering the
sync block, then dispatching a callback to the main thread, which
also tries to lock on the sync block.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-11-04 21:14:19 -07:00
Christopher Snowhill
4bed0af868 Core Data Store: Handle concurrency properly
All concurrency from other threads should pass through the viewContext's
performBlock or performBlockAndWait functions, and no other way. So now,
all access to Core Data is either happening on the main thread, or by
using these code blocks, all of which will wait for their access to
proceed.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-10-30 16:54:52 -07:00
Christopher Snowhill
e3ae28369f MIDI Plugin: Fix Secret Sauce memory leaks
Needed some autoreleasepools in there.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-10-28 00:17:08 -07:00
Christopher Snowhill
48056a9a2e Touched by Xcode
Xcode updated the Preferences xib.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-10-28 00:17:03 -07:00
Christopher Snowhill
5011f59b34 Sync commits 2022-10-28 00:02:46 -07:00
Christopher Snowhill
052a77d2cc MIDI Plugin: Add a little Secret Sauce
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-10-27 23:06:14 -07:00
Christopher Snowhill
bcd5ab0dd2 Amend MIDI Audio Unit player a bit
This should fix some potential initialization errors it may have had
before, but this doesn't fix the broken Sound Canvas VA plugin. Roland
says it's supposed to be broken on macOS 12+ and/or Apple silicon
anyway, so I guess there's no dodging that.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-10-21 16:37:14 -07:00
Christopher Snowhill
5882affd3f Always create new ContentViewController for volume
This is needed to re-parent the VolumeSlider window, as there is only a
single VolumeSlider, but two different VolumeButtons and their
respective NSPopover windows. So, always recreate the view on open,
which doesn't appear to have a noticeable impact on performance.

Fixes #331

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-10-20 21:28:20 -07:00
Christopher Snowhill
034863ee38 Fix Spectrum View in toolbar customizer
It was referencing the old SpectrumView class, when it should have been
referencing the safe SpectrumViewCG class, which will software render a
single frame of spectrum data when the customizing dialog is opened.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-10-20 21:28:15 -07:00
Christopher Snowhill
b5e096180a Updated FFmpeg to n5.2-dev-1305-g3bd0bf76fb
Among other things, fixes CVE-2022-2566.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-10-17 03:55:49 -07:00
Christopher Snowhill
54f46d6380 Ignore unnamed audio devices on enumeration
This was crashing trying to assign a nil CFStringRef from mystery audio
devices to the NSString passed to the enumerate block function, which
was predictably crashing. Ignore such devices instead.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-10-16 15:23:14 -07:00
Christopher Snowhill
ab512e5086 Handle external artwork with .heic extension
External artwork already supported the HEIC format, just not the correct
filename extension for the format.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-10-16 15:00:06 -07:00
Christopher Snowhill
e4bc5853ad Fix a crash with embedded cue sheet handling
Tag reading can read cue sheets as either a single NSString, or an
NSArray of NSStrings, so handle either case.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-10-16 14:59:19 -07:00
Christopher Snowhill
cddf9fb9ba Sync commit count 2022-10-16 00:19:32 -07:00
Christopher Snowhill
ee5231f567 Only process visualizations when visible
Stop visualization processing when the host window is completely
occluded, thus reducing background CPU usage levels significantly

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-10-15 23:19:36 -07:00
58a3c3aeeb
Merge pull request #329 from gitter-badger/gitter-badge
Add a Gitter chat badge to README.md
2022-10-13 21:13:37 -03:00
The Gitter Badger
29f20c60c1 Add Gitter badge 2022-10-14 00:07:50 +00:00
Christopher Snowhill
fba0775ebd Update associated file type extensions
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-10-11 23:17:54 -07:00
Christopher Snowhill
3a98f3f5a1 Formatting fixes
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-10-11 23:09:09 -07:00
Christopher Snowhill
c9181f571f Better locking behavior for playlist storage
This should fix up potential locking issues with maintaining a copy of
the results set while certain other background actions may happen, such
as the player updating play counts while playing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-10-11 23:09:05 -07:00
Christopher Snowhill
e54d05a907 Updated libraries and libraries debug set
Updated:
- libFLAC from 1.3.3-235-g772efde6 to 1.4.1
- libvgm from 001ca75 to 0e34925
- libid3tag from 0.16.1 with patch to 0.16.2

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-10-11 23:09:01 -07:00
Christopher Snowhill
894aada3d2 Updated libOpenMPT to version 0.6.6
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-10-11 23:08:56 -07:00
Christopher Snowhill
929ab11738 Updated VGMStream to r1776-97-g845961bb
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-10-11 23:08:51 -07:00
Christopher Snowhill
7ad895b95c Updated VGMStream to r1776-46-gc0c2c3c7
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-09-06 21:57:24 -07:00
Christopher Snowhill
9a7ecd98ea Update translations
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-08-21 16:50:34 -07:00
Christopher Snowhill
dffd09e6f7 Updated VGMStream to r1776-16-g7e4f5dc6
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-08-21 16:31:05 -07:00
Christopher Snowhill
d03afd6bf8 Updated libOpenMPT to version 0.6.5 final
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-08-21 16:31:01 -07:00
Christopher Snowhill
58453a6b7d [Cog Audio] Rename Semaphore.h to CogSemaphore.h
This magically fixes the stupid header maps that were pulling the system
semaphore.h into Swift projects, when they shouldn't have been doing
that in the first place. This is the same reason that the FLAC library
has its assert.h renamed to FLAC_assert.h.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-08-05 22:18:40 -07:00
Christopher Snowhill
be87e5433c [Cog Audio] Make the Swift Vis Controller work
And this is the actual meat of getting it to work properly, the changes
the Swift code needed to actually be fully functional.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-08-05 21:38:58 -07:00
Christopher Snowhill
e630b34981 [Cog Audio] Add a Swift bridging header
This makes the Swift version of the Visualization Controller usable.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-08-05 21:38:54 -07:00
Christopher Snowhill
8db5386053 [Cog Audio] Change a couple of imports
These imports needed to be changed so that Swift bridging didn't import
the system's semaphore.h instead of CogAudio's Semaphore.h, which is a
completely different thing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-08-05 21:38:50 -07:00
Christopher Snowhill
cbeba3fa0e First module converted to swift, but broken 2022-08-05 21:38:44 -07:00
Christopher Snowhill
a8fea3f657 [GME Input] Correct old comment in the code
There has been an API in GME to detect tracks ending for quite some time
now, and this just adds a little bit to the existing comment, which
previously noted that there was no way to detect if a track had ended,
which may have been true several major versions of GME long past.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-08-04 18:03:04 -07:00
Christopher Snowhill
5ac279e289 [GME Input] Fix decoder output sample count
The output has been assigning twice as many samples as it was supposed
to ever since commit 8d851e5bda, which
ended up generating the correct 1024 samples (2048 per GME parameter),
but assigned 2048 to the AudioChunk, which resulted in over-reading the
audio buffer, and thankfully not crashing, but instead causing an awful
sound distortion effect as random memory contents were played as PCM
audio.

Fixes #320

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-08-04 18:03:00 -07:00
Christopher Snowhill
4480eeefbe [CUE Sheet Container] Allow other containers
Allow .mp3 and such to fall back to the FFmpeg container handler, in
case there are chapters in a renamed file.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-08-03 21:21:22 -07:00
Christopher Snowhill
4d1d799f98 [MAD Decoder] Do not close source ourselves
The input isn't supposed to close its own sources, as it did not open
them itself, and they should be cleaned up automatically when they are
released to zero reference count.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-08-03 21:21:18 -07:00
Christopher Snowhill
ad8c59be2a [MAD Decoder] Drop RIFF files to the next input
Let the FFmpeg decoder handle RIFF files, if they happen to be named
.mp3 and not something like .wav.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-08-03 21:21:14 -07:00
Christopher Snowhill
545385da59 [Update Script] Add new JSON generator
Source is included here:

https://github.com/losnoco/sparkle-to-JSON
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-08-03 21:21:11 -07:00
Christopher Snowhill
59ab4ccdb5 Fix update script
This fixes the update URL and parameter handling. Seems there
was an extraneous newline returned by the security command.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-31 23:44:12 -07:00
Christopher Snowhill
4d3274362c [AdPlug Input] Fixed seeking
Looks like I never tested this, meh.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-31 22:52:13 -07:00
Christopher Snowhill
233dc424cb Update update_feed.rb with new parameter
New parameter for update title for the site generator.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-31 21:51:25 -07:00
Christopher Snowhill
3a64cdd5cc Updated AdPlug with a crash fix for RAD2
Fixed RAD2 files referencing instruments not present in the
file, which caused the player to reference uninitialized memory
and usually crash.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-31 21:51:21 -07:00
Christopher Snowhill
0bae420e6b Updated libbinio
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-31 21:51:16 -07:00
Christopher Snowhill
a4327579fa [Playlist Menu] Disable actions on empty selection
These actions should not be invoked when there is no selection.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-29 01:43:04 -07:00
Christopher Snowhill
ff1afdb63c [Playlist Queue] Save queue state change to disk
Save queue state changes to disk, rather than leaving it for later.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-29 01:43:00 -07:00
Christopher Snowhill
e0c1e338e4 [Playlist Queue] Hopefully prevent a crash state
This removal was causing crashes for some people. It should not get this
way, however.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-29 01:42:56 -07:00
Christopher Snowhill
b60a5462b7 [SID Input] Add static initializer for residfp
The SID builder needs a static initializer, otherwise multiple instances
created simultaneously, such as during populating info on adding a lot
of tracks, will race and crash the player.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-27 21:38:33 -07:00
Christopher Snowhill
3ff9d079d7 [File Tree] Only free Smart Folder query if used
Only free the query if it was successfully allocated.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-27 06:35:45 -07:00
Christopher Snowhill
9113051840 [File Tree] Ask Sandbox for access to Smart Folder
Ask for access to Smart Folder dictionary file, to read its query.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-27 06:35:04 -07:00
Christopher Snowhill
a2dacc067b [Playlist View] Prevent assigning nil textField
Prevent somehow assigning nil textField contents, as well as the
tooltip text.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-25 19:55:54 -07:00
Christopher Snowhill
03c498c0fc [Playlist Loader] Extend deduplication to CUEs
CUEs will now deduplicate playlist entries based on their dependencies,
and prevent loading redundant tracks if you add an entire directory, or
use the option to add a directory when adding single files from it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-25 19:35:11 -07:00
Christopher Snowhill
59ac5769ad [Sandbox] Add Sandbox grants to places missing it
The subdirectory parser, the CUEsheet reader, and the legacy XML
playlist reader were missing grants for Sandbox access.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-25 19:33:51 -07:00
Christopher Snowhill
9752cb725e Spanish translation of new option.
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-24 23:23:28 -07:00
Christopher Snowhill
f36ec30cb3 Clarified folder add message to correct button
Clarified the button name to "Open", which is what the button actually
says, not "OK". Also used double quotes around the other button name.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-24 23:23:24 -07:00
Christopher Snowhill
77b3d74948 [Sandbox Paths] Automatically clean up old paths
Clean up redundant paths automatically, and on startup. Also refresh the
preferences dialog path list every time it is opened.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-24 23:14:52 -07:00
Christopher Snowhill
7e06aef932 [Playlist Loader] Deduplicate loaded items
Deduplicate loaded tracks, to prevent duplicate items when adding a
folder that happens to contain playlists or CUE sheets referencing the
very same files.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-24 23:13:03 -07:00
Christopher Snowhill
e6bafa0b38 [Playlist Loader] Add option to load more files
Add option to load every file in a folder when opening just one or more
files in that folder.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-24 23:12:11 -07:00
Christopher Snowhill
72350a8b4c [Playlist View] Change truncation behavior a bit
Change the truncation behavior to only truncate if the length exceeds
1024 code points.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-24 19:35:57 -07:00
Christopher Snowhill
5f87475f2d [Playlist View] Add Sample Rate and BPS fields
Add Sample Rate and Bits Per Sample columns, hidden by default.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-24 19:35:10 -07:00
Christopher Snowhill
92b02c20db [Sandbox Dialog] Fix removing newly added paths
Newly added paths weren't adding all of the necessary data to the list
storage to make it possible to remove them without restarting the
player. Oops.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-24 19:17:04 -07:00
Christopher Snowhill
ddbc38c7fe Move most large stack using buffers to the heap
This should solve most potential future stack overflows.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-24 18:32:47 -07:00
Christopher Snowhill
eec8bf9f1c Enable warnings to track stack overuse
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-24 17:50:28 -07:00
Christopher Snowhill
699bdbada3 [Sandbox Notification] Add Spanish translation
Add the Spanish translation of the new dialog.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-23 18:39:26 -07:00
Christopher Snowhill
d4ce000dc3 [Sandbox Notice] Change single to double quotes
Change the quotes.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-23 18:39:22 -07:00
Christopher Snowhill
de710ef402 [Libraries] Fixed OpusFile debug library
It was linking to the wrong filename for libogg.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-23 18:39:17 -07:00
Christopher Snowhill
df17e1c788 Updated VGMStream to r1745-79-g449bb5e0
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-23 18:39:13 -07:00
Christopher Snowhill
5c3b876c04 [File Permissions] Add warning dialog
Added a warning dialog to notify the user of the purpose of the add
folder dialog that will pop up after it. Otherwise, they may get the
idea that the dialog is a glitch and should be cancelled.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-23 18:04:13 -07:00
Christopher Snowhill
f9aa56b18a [Playlist Loader] Only ask permission for local
Only ask permission for container folders if the container has local
files, and not for purely remote files, such as stream playlists.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-23 18:00:18 -07:00
Christopher Snowhill
9ced34a87c [Playlist Insert] Add a further bodge fix
I wish people would stop adding files to the playlist while there's a
search filter in place.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-21 04:16:36 -07:00
Christopher Snowhill
8f7b26cb5d [FFmpeg Input] Buffer up to 5ms each read call
Buffer up to 5 milliseconds of audio, or at minimum 1024 samples, each
call. Also pre-allocate the buffer, rather than using a stack buffer.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-21 04:03:21 -07:00
Christopher Snowhill
bb307a64b6 [FFmpeg Input] Do not subtract first block length
This is an unnecessary step, and results in the offset being off by the
duration of the first pre-read block. This is incorrect.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-21 03:54:08 -07:00
Christopher Snowhill
59d54f3190 [Inputs] Severely reduce metadata update intervals
The Vorbis, Opus, MAD MPEG, and especially the FFmpeg inputs needed to
have their metadata update intervals severely reduced, to reduce CPU
usage, especially on files with lots of tags. Interval reduced to only
once per second.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-21 03:53:14 -07:00
Christopher Snowhill
0b8a850086 [Chunk List Converter] Fix repeated initialization
Oops, this compare blunder resulted in DSD decimation breaking every
1024 samples or so, owing to block sizes, and caused ticking sounds as a
result. It would also cause HDCD decoding to break completely.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-19 23:05:40 -07:00
Christopher Snowhill
7e03f423c3 [Chunk List Converter] Minor changes
Neither of these two changes is really important, but they do simplify
things, and the division on that one function makes the non-decimating
DSD support actually functional, as the caller expects a specific number
of samples, and that was otherwise octupling the input sample count.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-19 23:04:25 -07:00
Christopher Snowhill
d9a09bff40 [Audio Output] Eliminated another stack buffer
Another large stack buffer was at play here. Consolidated it into an
existing buffer that can perform double duty here, since neither place
it's used conflicts with each other.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-19 23:03:00 -07:00
Christopher Snowhill
afa992189d Add a lock around access to output PTS variable
This locking should help, but I don't know why visualization jumps
around now.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-19 07:31:04 -07:00
Christopher Snowhill
5314eda5ab Reconfigure default toolbar layout
Now things are a little more understandable.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-19 07:29:38 -07:00
Christopher Snowhill
8ae271c511 [FLAC Decoder] Fix reading CUESHEET tags
It already supported reading the CUESHEET metadata block, but I managed
to break reading and processing CUESHEET Vorbis comments, which broke
CUE tagging, as well as files that didn't have both tags.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-19 04:53:46 -07:00
Christopher Snowhill
5280cd3aa3 [Playlist Pasteboard] Rewrite row pasteboard
Playlist View pasteboard copier function should only be generating URLs,
and it should verify that the entry has a valid URL to begin with.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-16 06:10:16 -07:00
Christopher Snowhill
7f4459c41c [Repeat Album] Add a safety test to repeat list
In case the current track isn't part of an album, or is otherwise not
matching any albums in the playlist. Though the Album filter predicate
wasn't working for a while due to changes.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-16 05:59:27 -07:00
Christopher Snowhill
0f003fcefd Update all localizations
This includes the base English strings, Spanish, Polish, and Russian.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-16 05:46:34 -07:00
Christopher Snowhill
72ed975d56 [Audio Output] Remove renderer from synchronizer
Remove the renderer from the synchronizer on stop, before releasing the
objects, if possible.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-15 22:52:46 -07:00
Christopher Snowhill
76d612faf4 [Audio Output] Only unregister listener if used
Only unregister the listener if it actually has been registered, and
clear the handle upon doing so.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-15 22:51:59 -07:00
Christopher Snowhill
dc536eef3d [MAD Decoder] Don't crash on bad files
The local and seekable file scanner could crash on bad MPEG files if
they failed to decode any frames and broke due to either end of file or
other unrecoverable errors, due to a division by zero error attempting
to calculate the file bitrate. Now correctly return error state if this
occurs, bailing early.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-15 22:51:04 -07:00
Christopher Snowhill
47258b02b1 [Core Data] Add access locking
Apparently we need this to prevent Core Data from stomping on itself
when another thread accesses it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-15 07:00:11 -07:00
Christopher Snowhill
7d46ac42b6 [Playlist Storage] Properly force migration
Old version users needed this, but it wasn't performed correctly.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-15 06:18:39 -07:00
Christopher Snowhill
498d85a0f4 [Dependencies] Fix libogg version number
Apparently, the autotools package uses a different versioning scheme
than the CMake build. Also rebuilt and re-versioned libvorbis and
libvorbisfile.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-15 06:18:28 -07:00
Christopher Snowhill
187ee602d6 [libid3tag] Updated to avoid crash bug
Already updated to 0.16.1, but this fixes a crash bug in 0.16.1.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-15 06:18:18 -07:00
Christopher Snowhill
de9b09251d [Audio Output] Greatly improve sample rate changes
Sample rate changes will now occur on exact sample boundaries, like they
are supposed to. Also, FreeSurround accounts for its output latency.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-15 06:18:08 -07:00
Christopher Snowhill
4df50c7fc3 Fix the Spotlight search panel
It was previously crashing horribly on adding search results. This makes
it actually functional, and renders it using a view-based table instead.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-15 06:18:01 -07:00
Christopher Snowhill
96304dbb17 Significantly reduce stack memory usage
Oops, there were a lot of large local buffers in use here.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-14 17:28:24 -07:00
Christopher Snowhill
b60646a1fc Remove obsolete helpbook document
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-14 16:12:04 -07:00
LennyLip
ed6f0d8f52 ru FreeSurround pref string 2022-07-14 16:11:58 -07:00
Christopher Snowhill
b742fb6659 Sync with sparkle branch 2022-07-14 16:06:20 -07:00
Christopher Snowhill
d417d245f4 [Audio Output] Make toggling DSPs safe
The DSPs should not be deinitialized from another thread, possibly while
they are currently processing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-14 03:16:21 -07:00
Christopher Snowhill
dd58a540a8 [FreeSurround] Add configuration option to enable
It now needs translation of the new string.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-14 03:02:08 -07:00
Christopher Snowhill
10272ca7a4 [Audio Processing] Increase thread stack size
Apparently, all these new changes with FreeSurround have pushed the
default 512KB thread stack size to the limit. And I'm not even using
stack variables, really, except for maybe the autoreleasepools.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-14 02:42:21 -07:00
Christopher Snowhill
7de0792b97 [FreeSurround] Actually make it work
Apparently, the LFE channel is not being initialized at all if bass
redirection isn't enabled, and even if it is, it's uninitialized for a
great portion of the spectrum. Clear it all on every iteration.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-14 02:41:06 -07:00
Christopher Snowhill
eb0c1a8463 [Audio Output / Debugging] Fix sample logging
Fix the sample logging function that is optionally compiled into debug
versions.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-14 02:39:25 -07:00
Christopher Snowhill
38832d9ce9 [Audio Processing] Update for new API
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-14 02:38:04 -07:00
Christopher Snowhill
b0bef40386 [FreeSurround] Change another variable to const
This should be const anyway, as it's not written to.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-14 01:47:02 -07:00
Christopher Snowhill
8b418004eb [FreeSurround] Further improvements
Still not working, though.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-14 01:47:02 -07:00
Christopher Snowhill
60429490b3 [FreeSurround] Fix surround block size
The output implementation has a block size of 4096, so the class
implementation should also use that.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-14 01:47:02 -07:00
Christopher Snowhill
11413ef3db [FreeSurround] The rest of the implementation
This is the code that actually needs to be added to make it process
audio. This insertion makes the whole app crash when processing audio at
all. Weirdly, simply reverting these two files makes the audio code work
again. I can't explain it.

Also, commenting out CMAudioFormatDescriptionCreate makes it work, too.
There's something weird going on with that function.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-14 01:47:02 -07:00
Christopher Snowhill
85db95befd [FreeSurround] Experimental implementation code
This is a working implementation of FreeSurround, but I can't get it to
work in the Cog code base, as the whole project crashes head over heels
if this code is inserted into the output chain.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-14 01:47:01 -07:00
Christopher Snowhill
04d394c65c [Audio Processing] Move float32 converter
Move the Float32 converter to a different location, for any future plans
to support decoding audio files to common data for any other purpose.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-14 01:45:49 -07:00
Christopher Snowhill
58be4a40fc [FLAC Decoder] Change maximum buffer size
This should be more correct, especially considering that the library can
handle 32 bit files now.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-14 01:43:33 -07:00
Christopher Snowhill
f4bbeaec77 [libFLAC] Remove debug overlay
There's a bug in the debug version of the library which does not occur
in the release build.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-14 01:42:57 -07:00
Christopher Snowhill
27a1153b91 [FLAC Decoder] Correctly handle zero length frames
Apparently, the decoder is capable of returning zero length frames
without having hit the end of the stream.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-14 00:01:59 -07:00
Christopher Snowhill
32ec11a42e Updated the help document a bit
Oops, it's been a while since I've touched this.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-13 04:56:03 -07:00
Christopher Snowhill
30bff0b52d [Translations] Tweaked the Preferences dialog
Now the Preferences panels are 110 points wider, and most things are
shifted around in ways to make the current set of translations fit into
the dialogs.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-13 04:37:16 -07:00
Christopher Snowhill
f17fc3708d [Polish translation] Fixed total time formatter
Please do not translate the token names, they are used by the code to
look up which value to insert into the string.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-13 03:50:34 -07:00
Christopher Snowhill
a9002a616e [Polish Translation] Fix the MainMenu strings file
The MainMenu.strings file had several mistyped quotation marks, and
several strings outside of quotation marks or comments, breaking the
menu translation entirely. This makes the translation actually work.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-13 03:43:08 -07:00
Christopher Snowhill
fc5c3c5441 [Polish translation] Activate localized strings
Template was missing from the project declaration. Oops.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-13 03:42:08 -07:00
Christopher Snowhill
3adc30477d XIB touched by Xcode
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-13 03:41:27 -07:00
Christopher Snowhill
c8c2bb909a [Ogg Vorbis/Opus] Fix tag clobber on play
Fixed the tags being overwritten by an "update" on non-streaming files.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-13 00:12:35 -07:00
Christopher Snowhill
0fa2d0110c [Ogg Vorbis/Opus] Fix picture metadata handling
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-13 00:11:51 -07:00
Christopher Snowhill
13fb6bb141 [Playlist Insert] Add a special case for filtered
Insertions which occur when the playlist is filtered can try to add past
the end of the playlist. Let's try to dodge that.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-12 23:47:03 -07:00
Christopher Snowhill
8d231d34d4 Update several of the dependencies
- Updated libFLAC to the latest Git commit, post 1.3.4.
- Updated libid3tag to 0.16.1.
- Updated libopus to the latest Git commit.
- Updated my FFmpeg libfdk-aac patch. Previously was overwriting
  memory when it was supposed to be skipping samples.

Also added debug versions of several of the libraries, and changed
the library extractor script to unpack the debug libraries over the
release set to add the particular matching debug versions when
building a debug build.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-12 23:40:53 -07:00
LennyLip
4a5d21836a
Russian translation: new strings (#310)
* Update MainMenu.strings

* Update Preferences.strings
2022-07-11 19:58:58 -07:00
Christopher Snowhill
67f05bad27 [MAD Decoder] Fix streamed MP3s not working
Due to a change designed to stop playback when the end of the file is
reached, which should not be checked for unseekable files, which are
web streams that only stop when the connection drops, or when the user
stops playback manually.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-11 19:44:19 -07:00
Christopher Snowhill
fc1a226791 [HTTP Reader] Fix reading small static files
The reader was previously returning a failure state on open if the read
completed and fit entirely into the read buffer, which broke most remote
M3U or PLS playlists.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-11 19:44:19 -07:00
Christopher Snowhill
32940d3277 [Sandbox Broker] Only pop suggester for local URLs
Only pop up the path suggester and check on local file URLs, not remote
URLs, which shouldn't be checked, since they don't require sandbox
permission grants or bookmarks.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-11 19:44:19 -07:00
Christopher Snowhill
749e92694e Update About Window logo
The previous version was from an old render. Also apply some minor
tweaks to the scene.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-11 19:44:19 -07:00
Christopher Snowhill
a81ed64915 [Shuffle] Fix Shuffle Album mode
Oops, I should have remembered that the data structure changes would
break this search predicate. Now apply the search predicate to the
playlist representation, which allows searching against the data blocks
using the PlaylistEntry property implementation.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-11 19:44:19 -07:00
70db08cf07
Update README.md
Third's the charm.
2022-07-11 19:10:50 -04:00
2619eff6ad
Update README.md 2022-07-11 19:09:46 -04:00
847f96c13e
Update README.md 2022-07-11 19:09:13 -04:00
af8cfc1c02
Added Lokalise logo and instructions. 2022-07-11 19:08:25 -04:00
Christopher Snowhill
7763269af8 Add missing strings to new translations
Still in need of translation from their respective authors.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-11 15:26:25 -07:00
LennyLip
7504300d9e Russian lang fixes 2022-07-11 15:19:25 -07:00
LennyLip
0ac17fe543 Russian translation 2022-07-11 15:19:20 -07:00
Christopher Snowhill
26f903ab77 Fix missing Polish declarations in project
There were still missing things.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-11 15:03:19 -07:00
Christopher Snowhill
8244eb0bb8 Activate Polish translation
The declarations for the translation were missing from the project files
so that it wasn't being used. Also added the missing strings to the
files that were already added to the translation.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-11 14:40:32 -07:00
Christopher Snowhill
18824e0e18 [Visualization Controller] Minor guard check
Guard check in case visualization controller is called before any data
is posted to it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-11 14:39:23 -07:00
Christopher Snowhill
9f03b72b69 [Headphone Filter] Minor changes
Change a variable type, to avoid a warning.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-11 14:38:52 -07:00
Christopher Snowhill
8d8b508d09 [Audio Converter] Minor change for format changes
This should also seal up any potential hole for problems if there's an
audio format change and no audio buffered.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-10 16:36:31 -07:00
Christopher Snowhill
f8a8a57cf0 [Audio API] Repair the damage to the input chain
The input chain could hang up indefinitely, and MAD decoder didn't
indicate end of file properly.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-10 16:24:21 -07:00
pax
e595dbd525 first(really basic) open url panel translation. 2022-07-10 15:23:45 -07:00
pax
f5aa7401b6 translated equalizer strings, as well as the spotlight thing. 2022-07-10 15:23:45 -07:00
Christopher Snowhill
3c351f6968 [Input API] Change input readAudio method
readAudio now returns an AudioChunk object directly, and all inputs have
been changed to accomodate this. Also, input and converter processing
have been altered to better work with this.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-10 15:14:47 -07:00
Christopher Snowhill
8bc9738ccb [Downmixer] Only downmix to stereo if not stereo
When downmixing to mono, only downmix to stereo first if the source is
not already stereo.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-10 15:08:56 -07:00
Christopher Snowhill
000a2e0cb6 [Project Files] Change most to enable modules
Most projects needed to be changed to enable C or Objective C modules.
Hopefully, this improves debugging.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-10 15:07:39 -07:00
Christopher Snowhill
abd557943c [Cuesheet Input] Don't repeatedly open file
The input file has already been opened for decoding by an earlier step
in the testing process, reuse the decoder from that. Spares a decoder
open cycle on all embedded cuesheet supporting formats.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-10 14:57:22 -07:00
Christopher Snowhill
39d3f7edfe [HRTF] Force filtering of odd channel formats
Apparently, Apple's Spatial Audio processor doesn't really support weird
configurations like this. So we need to filter them down to stereo.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-09 18:42:38 -07:00
Christopher Snowhill
57719a038c [HRTF] Reverse Z axis of speakers above listener
Apparently, positive elevation is above, negative is below.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-09 18:42:32 -07:00
Christopher Snowhill
0e1bf0abf2 Update some strings from Polish translation
Update missing strings, including one which was translated already in
the comments.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-09 16:22:06 -07:00
f2b9d9d84e [Spanish Translation] New strings
Signed-off-by: Kevin López Brante <kevin@kddlb.cl>
2022-07-09 16:16:55 -07:00
bfd363df5d [Translation] Privacy policy URL can now be loaded from strings files
Signed-off-by: Kevin López Brante <kevin@kddlb.cl>
2022-07-09 16:16:55 -07:00
Christopher Snowhill
30789c608e Add two missing strings from the Sparkle branch
Oops, those were missing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-09 16:16:55 -07:00
a7290aedee [Spanish Translation] Updated string for new HRTF filter. 2022-07-09 16:16:55 -07:00
Christopher Snowhill
349ab57afe Implemented all new HRTF filter
This filter replaces the old one, and uses OpenAL Soft presets. Since
there aren't that many of those, I've left off configuration for now,
except to turn it on or off.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-09 16:16:55 -07:00
pax
85d46bc1b3 The Polish translation is mostly ready. 2022-07-09 15:56:02 -07:00
pax
f682378cf7 *added Polish translation, not fully ready, but there ya go. 2022-07-09 15:56:02 -07:00
Christopher Snowhill
291b1e1253 Truncate text in playlist to a reasonable length
1024 characters aught to be enough for any playlist view.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-08 16:34:50 -07:00
Christopher Snowhill
02f49093a3 Remove the meta string cache
It wasn't helping anyway.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-08 16:34:50 -07:00
564a8739d0 [Spanish Translation] Added strings for new Info Inspector fields 2022-07-08 16:34:50 -07:00
Christopher Snowhill
dad9275a30 Ditch the data compression
It just wasn't working out.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-08 16:34:50 -07:00
Christopher Snowhill
6222e25adc Experimental tag support redesign
This redesign completely changes how tags are stored in memory. Now all
arbitrary tag names are supported, where possible. Some extra work will
be needed to support arbitrary tags with TagLib, such as replacing it
with a different library.

Translation pending for a couple of strings.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-08 16:34:50 -07:00
Christopher Snowhill
bea7d8e651 [Playlist] Increase default font size to Regular
Regular control size ends up being 13 points, rather than the previous
default of Small control size, which ended up being 11 points.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-07 17:56:47 -07:00
Christopher Snowhill
39ab0eaf45 Updated VGMStream to r1745-58-g828c6b09
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-07 16:44:01 -07:00
Christopher Snowhill
b29d19966f [Path Suggester] Only process local file URLs
Playlist entries for non-file URLs should be ignored.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-07 16:38:56 -07:00
Christopher Snowhill
63ca187aa7 [Table Views] Add a safety check to cell creation
Cell creation may create some other type of view, somehow. No idea how.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-07 16:38:48 -07:00
Christopher Snowhill
da053d7282 [File Tree] Significantly improve the watcher
- Switch to fine grained folder and file watching responses
- Navigate the PathNode tree using a fast dictionary of path components
- Quickly refresh the file tree by locating parent nodes to refresh

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-06 22:39:47 -07:00
Christopher Snowhill
1c3717eb84 [File Association] Correctly play files on open
When opening files from external association, such as opening files, or
opening folders with Cog, correctly obey the configured clear and play
or enqueue and play actions, by playing the new additions.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-06 17:04:15 -07:00
Christopher Snowhill
a03e519c61 [Playlist Loader] Fix Clear and Play action
Clear and Play was broken by the previous update. This fixes it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-06 16:04:03 -07:00
Christopher Snowhill
2754a9fca3 [CI Scripts] Update to use command -v
Instead of `which`.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-06 14:44:36 -07:00
Christopher Snowhill
b4e3c05c87 [Playlist Loader] Load files in the background
Load new playlist entries in the background, asynchronously.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-06 14:28:14 -07:00
Christopher Snowhill
c54062f4bf Attempt for one last time to fix Xcode Cloud
This should hammer fix it. That'll show them for forcing a shallow
commit on me.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-06 04:37:59 -07:00
Christopher Snowhill
016bc9a45b Attempt to fix Xcode Cloud again
This time, run the git fetch tags and genversion in the pre
xcodebuild script.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-06 04:22:26 -07:00
Christopher Snowhill
df74f5ebe7 Fix Xcode Cloud CI script to fetch tags
The script needs to fetch repository tags to function properly.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-06 04:14:24 -07:00
Christopher Snowhill
333392f284 Change Crashlytics symbol upload script
Script should not fail an otherwise successful build.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-06 03:38:42 -07:00
Christopher Snowhill
c48d55ba9a [Playback] Prevent erroneous file from repeating
Prevent Repeat Single from locking up the player on an unplayable file.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-06 02:20:05 -07:00
Christopher Snowhill
6ee0d8a267 [Sandbox Broker] Greatly speed up path resolving
The fragment remover need not detect whether the given path is a folder
or a file, as it is only removing hash marked fragments, not actually
removing the entire filename if it's only a file and not a folder like
the old versions used to. This greatly speeds up access, especially on
network shares.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-06 00:04:58 -07:00
Christopher Snowhill
d834819f79 [Path Config] Allow multiple selection
This more easily allows removing multiple paths at once.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-06 00:04:52 -07:00
Christopher Snowhill
60964a00b2 [Path Config] Remove exact items by token id
Should use the exact token object to remove them, rather than doing a
path comparison.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-06 00:04:45 -07:00
Christopher Snowhill
d03fb11f4c [Path Config] Properly prune the database
When cleaning up the path list, actually remove the pruned entries from
the Core Data storage, so they don't end up resolving to broken
bookmarks in the player, breaking playback on migrated configurations.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-05 23:47:05 -07:00
Christopher Snowhill
0e2bfeb671 [Path Config] Properly report broken bookmarks
Broken bookmarks weren't reporting as isStale, but rather, were failing
to resolve at all, and without this change, they were impossible to
detect in a migrated configuration.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-05 23:45:46 -07:00
Christopher Snowhill
ab285417ae [Album Art] macOS Ventura natively supports AVIF
Disable the compiled in AVIF support there, as the OS supports it
natively. Keep the libraries for older OSes.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-05 23:44:35 -07:00
Christopher Snowhill
02e1276df8 [FFmpeg Decoder] Further improve Matroska tags
Matroska defaults the date field to "date_recorded".

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-05 18:11:45 -07:00
Christopher Snowhill
a8b13748d6 [FFmpeg Decoder] Better handle Matroska tags
Matroska files use the "TITLE" field for the album when there are
chapters. Also, Matroska container uses shorter gain field names for
album and track gain, differentiating them by either being global or
specific to each chapter.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-05 17:40:57 -07:00
Christopher Snowhill
fadebd39ea [FFmpeg Decoder] Enable Metroska and WebM videos
Enable playback of video file extensions. Like other video formats
handled by the FFmpeg decoder, video streams are dropped in decode and
only the first audio stream is played.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-05 14:25:49 -07:00
6439c82eb6 [Spanish Translation] Updated strings in Appearance preferences
Signed-off-by: Kevin López Brante <kevin@kddlb.cl>
2022-07-05 16:48:48 -04:00
Christopher Snowhill
472272129b [FLAC Decoder] Safety decoding for tag reader
Use tag string encoding guessing for tag decoding, just in case there
are invalid files with non-standard encoded strings inside the tags, or
if there are streams with such tags. We don't want any crashes.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-05 13:44:44 -07:00
Christopher Snowhill
d4b434a68f [Spectrum] Enable switching style at runtime
It is now possible to switch the display style at runtime, while the
views are open.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-05 13:43:21 -07:00
Christopher Snowhill
f4926cf569 Interface builder touched by Xcode
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-05 13:40:54 -07:00
Christopher Snowhill
d3256f3c54 Reformat spaces to tabs
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-05 12:52:53 -07:00
Dzmitry Neviadomski
0dc31808e7 Add preference to choose between SceneKit and DDB spectrum. 2022-07-05 12:49:09 -07:00
Christopher Snowhill
45ec7b6263 Greatly improve tag reading performance
Improve tag reading performance for Ogg, Opus, FLAC, TTA, and TAK, by
eliminating TagLib from the equation in those cases and just using the
respective file inputs to do the tag reading, which is apparently a lot
faster anyway.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-05 00:55:48 -07:00
Christopher Snowhill
22cd16bb46 [Audio Player] Eliminate an avenue of lockups
Prevent the player from locking up in certain circumstances, by not
locking chainQueue the entire time this function is processing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-05 00:55:41 -07:00
Christopher Snowhill
42b2142ab7 Remove unnecessary files from build and copy steps
Remove a single .inc include from CogAudio build phase, as it's included
but not compiled as Pascal like Xcode thinks. Also remove a bunch of
files from being copied into the resulting .framework and .bundle files
during link stage, as we don't need to distribute that stuff.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-04 23:58:06 -07:00
Christopher Snowhill
2c698304ca [Playlist Loader] Revert background loader
This reverts most of 802a86a3d8, since it
didn't work anyway.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-04 18:09:01 -07:00
Christopher Snowhill
af82399f37 [Playlist Loader] Fix background queue post action
Post action now returns the files.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-04 17:37:32 -07:00
Christopher Snowhill
1145bca042 [Equalizer] Fix support for arbitrary channels
The deinterleaved format was being specified incorrectly. Now it asks
for the correct format, which is deinterleaved, and the bytes per frame
or packet sizes are relative to a single channel's buffer, not all
buffers. Oops, that could have been more clear in the documentation.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-03 22:40:40 -07:00
Christopher Snowhill
e6c3fcaa0d [Equalizer] Remove unnecessary code
This code is obsolete, remove it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-03 22:40:33 -07:00
Christopher Snowhill
3c86758cb5 [Sandbox] Ask for permission for container folders
Ask for permission to access the folders containing container files,
such as .CUE sheets, or .M3U or .PLS playlists.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-03 22:40:26 -07:00
Christopher Snowhill
b3e0da6fe9 [M3U Playlist] Reformulate safety checks
Apparently someone managed to crash this with their playlists. No idea
how. Added more safety checks.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-03 14:30:29 -07:00
Christopher Snowhill
7f1c337ee8 [Tag Reading] Moved external cover art reader
Moved external cover art reader to a place where it can be used for any
format, even formats unsupported by Metadata Reader interfaces.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-02 14:59:47 -07:00
Christopher Snowhill
b72d5a4c26 Update Info.plist.template
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-02 04:37:32 -07:00
Christopher Snowhill
a32a8718d7 [Plugin Loader] Unregister loader callback
This callback should be unregistered when plugin loading completes,
otherwise we could end up processing bundles loaded by external stuff,
like Audio Units loading for MIDI playback.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-02 04:31:22 -07:00
Christopher Snowhill
9839f51ee1 [FFmpeg Input] Add .m4b and .m4r extensions
Add support for more file name extensions, so we don't fall back on
Core Audio Input for these files.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-02 04:22:34 -07:00
Christopher Snowhill
74bb2527a9 [FFmpeg Input] Implement SoundCheck tag support
Implement support for the Sound Check tag format.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-02 04:21:28 -07:00
Christopher Snowhill
cfcb7c041d [TagLib] Disable MP4 tag reader, as it can crash
This MP4 tag reader is buggy. Disable it in favor of FFmpeg decoder's
metadata reader.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-02 04:20:01 -07:00
Christopher Snowhill
a847cbde3b [MIDI Input] No longer crash when seeking to the end
When seeking to the end of a file, no longer crash due to out
of range std::vector access, because it was using at() with an
offset of the array size. Instead, offset from the begin()
iterator return value, which allows offsetting to end().

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-02 03:19:24 -07:00
321e3382f4 [Spanish Translation] Added new strings for synthesis settings
Signed-off-by: Kevin López Brante <kevin@kddlb.cl>
2022-07-02 01:25:24 -07:00
Christopher Snowhill
b025a21e13 [Synthesizers] Implement default overrides
Default time, fade, loop count, and sample rate may now be overridden.

Synchronized preferences strings tables. Spanish translation of new
options pending, new releases won't be pushed until they're complete.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-02 01:25:24 -07:00
Christopher Snowhill
34513f3b38 [Translation] Widen the Path Suggester column
Widen the enable column, for the Spanish description of the column
header.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-01 14:31:16 -07:00
Christopher Snowhill
cb007d62a1 [Translation] Fix translation of Path Suggester
Also fix the fact that the XIB wasn't embedding the XIB/NIB in the app
as a result of the translation move.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-01 14:31:10 -07:00
Christopher Snowhill
a53a8ecb82 [Audio Output] Fix equalizer support
Equalizer was copying the output of the equalizer repeatedly to the
first output channel, instead of copying each channel correctly. This
had the effect of making the equalizer output adjusted audio to only the
left channel in stereo output, and possibly render the stream sounding
weird.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-01 14:11:46 -07:00
Christopher Snowhill
70b01a7cf1 [Plugin Controller] Add Cue sheet safety check
If somehow a plugin doesn't load, skip cuesheet should skip it anyway,
as we don't want any recursive loops.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-01 13:39:06 -07:00
Christopher Snowhill
99f15679a6 [Audio Output] Remove unnecessary variables
These variables weren't being used anyway, so remove them.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-01 12:42:21 -07:00
dd20073a9b [Translation] The Big Translation Commit
- Plugs the Total duration text to macOS's localization technology
- Adds a proper Spanish translation
- Adapts certain dialogs to make them more suitable for translation

Signed-off-by: Kevin López Brante <kevin@kddlb.cl>
2022-07-01 12:37:30 -07:00
Christopher Snowhill
189999b7c2 [libOpenMPT] Remove unnecessary compile option
ENABLE_ASM isn't even used anywhere in the library any more.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-01 01:03:13 -07:00
Christopher Snowhill
904ce1c4cd Move all dialog XIBs for translation
Make it easier to translate the relevant dialogs now.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-01 00:38:25 -07:00
Christopher Snowhill
c69433bf0b Updated credits file with Patron preference
Oops, missed that Patreon message, because Patreon did not email me.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-01 00:17:55 -07:00
Christopher Snowhill
23fa3c5e8e Update Credits.html in Spanish placeholder
Spanish translation really needs doing some time soon, maybe.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-01 00:12:03 -07:00
Christopher Snowhill
731e52c440 Build libOpenMPT from source once again
Bundle libOpenMPT as a dynamic framework, which should be safe once
again, now that there is only one version to bundle. Also, now it is
using the versions of libvorbisfile and libmpg123 that are bundled with
the player, instead of compiling minimp3 and stbvorbis.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-30 22:57:30 -07:00
Christopher Snowhill
919497148a Updated libOpenMPT to version 0.6.5-pre.1+r17609
This allows us to eliminate the requirement to continue bundling version
0.5.x of libOpenMPT for compatibility with macOS 10.13 through 10.14.x.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-30 21:28:28 -07:00
Christopher Snowhill
0832a8ea34 Restore the File Tree, now with a chooser button
Revert "Remove the file tree, as Sandbox does not permit"

This reverts commit 02ec735687.

This also changes how the File Tree choosing works.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-30 16:57:51 -07:00
Christopher Snowhill
830d3bf3be [Info Inspector] Improve formatting of sample rate
Sample rate now has a locale independent formatting, and no longer uses
scientific notation for large numbers.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-30 00:28:03 -07:00
Christopher Snowhill
ff56b757e6 [Play Counts] Fix reporting play counts
Play counts are guaranteed to be reported on the correct track now.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-29 23:26:30 -07:00
Christopher Snowhill
608483ae60 Update libVGM and BASSMIDI, SF3 support
BASSMIDI now includes SF3 support, as well as several other changes.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-29 23:25:59 -07:00
Christopher Snowhill
ee5b6be4bb [Sandbox] Synchronize write accesses to storage
Synchronize writing to the bookmark storage to the main thread.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-29 19:41:24 -07:00
Christopher Snowhill
ad7574be59 [Sandbox] Fix URL fragment removal function
This should be deleting from the #, including the #.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-29 19:41:20 -07:00
Christopher Snowhill
14a1157508 [Context Menu] Hook up Reset Play Counts item
Actually hook up the Reset Play Counts menu item so it actually does
something instead of just sitting there looking pretty.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-29 12:41:46 -07:00
Christopher Snowhill
7e2dda750e [Sandbox Config] Correctly test paths for files
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-29 12:11:22 -07:00
Christopher Snowhill
170310d7e5 [Sandbox] Remove startup folder consent prompt
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-29 12:02:59 -07:00
Christopher Snowhill
82179a5f10 [Sandbox] Support bookmarking individual files
Individually added files, directly opened by the user, may now store
bookmarks in settings.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-29 11:56:50 -07:00
Christopher Snowhill
02ec735687 Remove the file tree, as Sandbox does not permit
The Sandbox does not permit such controls to exist.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-29 11:56:01 -07:00
06739eb001 [Info Inspector] Made fields selectable, and fixed blending issue with
album art

Signed-off-by: Kevin López Brante <kevin@kddlb.cl>
2022-06-29 14:14:27 -04:00
bd8cfd300a [About Window] Fixed appearance for systems without Dark Mode
Signed-off-by: Kevin López Brante <kevin@kddlb.cl>
2022-06-29 14:13:40 -04:00
Christopher Snowhill
3ef6a4204f [Sandbox] Handle file tree path config better
Handle the configuration better, by adding the path to the grants list
if it is newly configured.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-29 00:31:34 -07:00
Christopher Snowhill
f5bde75eda [Sandbox] Automatically save folder bookmarks
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-28 23:13:42 -07:00
Christopher Snowhill
6f126f4857 [Sandbox] Reduce entitlements granted by default
Since App Store approval decided these suddenly matter.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-28 22:58:57 -07:00
Christopher Snowhill
22085d94f1 [Sandbox] Show grant dialog on launch if empty
If there are no configured paths, show the grant page on every startup.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-28 22:58:13 -07:00
Christopher Snowhill
de7afad3d4 [Playlist Loading] Process messages while loading
Process main queue messages by handling the loading in a background
queue, and sync it to the main thread periodically, while pausing to
wait for the results. This allows the file open dialog to return
immediately, and display loading progress on the status bar.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-28 20:26:55 -07:00
Christopher Snowhill
bf6a28a95e [Playlist View] Change ratings column to variable
The ratings column needs to be made variable width, for variable font
sizes. If anyone knows how to force the width to fit the current text,
I'm open to suggestions.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-28 20:23:43 -07:00
Christopher Snowhill
e491de0a93 [Crash Handling] Enable exceptions for debugging
Debug builds should have exceptions enabled, rather than crashing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-28 20:22:51 -07:00
Christopher Snowhill
f5412fbfec [About Dialog] Add needed WebKit framework
This is needed for macOS older than 11.0? 10.15? to open the About
dialog without crashing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-28 04:28:33 -07:00
Christopher Snowhill
44fb1efc73 [Play Info] Implement track rating system
The track ratings are stored in the same stats table as the play counts.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-28 01:59:36 -07:00
Christopher Snowhill
2d7c3b51c7 [Audio Output] Restart correct track
When restarting playback on the current track, restart the correct
track, in case restarting near the end of it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-28 01:59:23 -07:00
Christopher Snowhill
8fc981cb92 [Play Counts] Add option to (mass) reset counts
Add option to reset counts for all selected tracks on the playlist.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-28 01:59:10 -07:00
Christopher Snowhill
de43192453 [Play Counts] Commit play count edits to storage
Was calling commitEditing rather than commitPersistentStore, whoops.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-28 01:59:00 -07:00
Christopher Snowhill
0515a63645 Resource templates touched by Xcode
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-28 01:58:31 -07:00
Christopher Snowhill
3b1eefaabb [Play Counts] Track play counts of correct track
Track play counts for the correct track, even on short tracks. Also
correctly track the play count of the last played item in the play queue
which stops with bufferChain set to nil, so the previous iteration was
not tracking it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-28 01:57:00 -07:00
Christopher Snowhill
f1dd55b29e [File Tree] Pop permission grant on setting root
Setting the root path should now pop up a permission grant dialog.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-27 16:17:54 -07:00
Christopher Snowhill
9411e7bd45 [Sandbox Broker] Synchronize full access operation
Full access should be synchronized, otherwise rapid access to the same
path from different threads will cause crashes.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-27 01:00:56 -07:00
Christopher Snowhill
dc02404184 [Metadata Cache] Actually run cleanup thread
Previously, the cleanup thread was not being run. Also, only reset the
metadata deduplication store when the cache is first emptied.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-27 01:00:48 -07:00
Christopher Snowhill
bb11567948 [Audio Output] Change converter back to Obj-C
Change converter source file back from Objective-C++ to Objective-C.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-27 01:00:42 -07:00
Christopher Snowhill
cacdc13d15 [Sandbox Broker] Bypass entitled paths
Include entitlement granted user folders in the permission check, so
that if the file or folder is nested under one of them, it allocates a
static permission object, rather than querying the list of configured
paths every time. This also prevents the player from popping open the
path grant / suggester dialog every time a default path is in the file
set listed, which should provide some relief to most users.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-26 23:53:06 -07:00
Christopher Snowhill
824648321c Attempt to fix Xcode Cloud CI
Try to generate the Info.plist before xcodebuild runs.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-26 23:00:18 -07:00
Christopher Snowhill
ee79935a8a Update versioning setup
Versioning now happens before building Cog itself, and goes
into the Info.plist in the project directory. The original
file became a template file which is altered any time a
build occurs.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-26 22:10:17 -07:00
Christopher Snowhill
b3591867e7
Update debug.yml
Switch to building on macos-12
2022-06-26 21:12:27 -07:00
Christopher Snowhill
bf03119373 Add Package.resolved back to repo
Guess we can't use Github actions now, because this file breaks those.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-26 20:27:09 -07:00
Christopher Snowhill
fc296bda77 Add CI scripts for Xcode Cloud
Add a post clone script for Xcode Cloud

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-26 20:23:40 -07:00
Christopher Snowhill
cc45750c0c Automatically unpack libraries before building
This required adding the included script in every project that links to
one of the bundled libraries. The script is designed to sleep for a
while if another thread is already extracting the libraries. The script
uses a temporary file as an extraction step lock, so other instances
sleep, and then detect the libraries.updated file, which is created
before the lock is removed.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-26 20:12:06 -07:00
Christopher Snowhill
05960b1da1 Updated VGMStream to r1745-47-gfa55119d
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-26 15:12:00 -07:00
Christopher Snowhill
f516658a5e [Equalizer] Prevent crash on stop
Wait for the equalizer to be shut down properly by the main thread
before destroying it. Otherwise, the main thread could crash on stop,
due to accessing the equalizer handle while it's being torn down in the
output thread.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-26 14:48:02 -07:00
Christopher Snowhill
db181bde4d [Visualization System] Change API a bit
Now the API makes both PCM and FFT data optional, and will do nothing if
neither are requested. Also, it now supports a latency offset in seconds
with floating point precision. The two built-in visualizations currently
request zero larency. Increasing the latency asks for even older samples
while specifying a negative count requests samples from the "future"
relative to what the listener is hearing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-26 05:40:06 -07:00
Christopher Snowhill
8068a506b9 [Play Events] Don't bug on end of playlist
Don't bug out on end of playlist, when didBeginStream will receive a nil
track pointer, which should result in unsetting the current track in the
player, and not send a DidBegin notification to everything, including
the visualization views' event handlers.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-26 05:40:00 -07:00
Christopher Snowhill
5c4cfb4053 [Play Counts] Fix counts for tracks with subsongs
Fix counts for tracks with subsongs from piling all the counts onto the
first subsong seen, by using the URL fragment in the filename check and
storage.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-26 04:38:18 -07:00
Christopher Snowhill
f04761ff42 [Audio Output] Fix for previous commit
This fixes the problem caused by the following commit:

050aaaf852

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-26 03:58:10 -07:00
Christopher Snowhill
adbf8aa7d1 Fix compilation
Oops, that last suggester change broke compilation.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-26 03:08:39 -07:00
Christopher Snowhill
1e03df2aab [Sandbox] Don't try to grant access to container
Do not try to grant access to the app's container folder when searching
for paths to add.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-26 03:00:00 -07:00
Christopher Snowhill
0e4ff8a55c [Sandbox] Compare to the actual user paths
Remove the sandbox reference, because the user will add folders outside
the sandbox, and we have entitlements to access these folders.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-26 02:59:49 -07:00
Christopher Snowhill
bc309fe725 [Sandbox] Suggest URLs that are contained in CUEs
Cuesheets can now expose which URLs they contain, which may help with
sandbox path configuration. That is, if the CUE sheets are already
readable.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-26 02:59:37 -07:00
Christopher Snowhill
378f710cee [Visualization] Resample more audio if present
If upsampling the audio by a significant factor, it may be necessary to
process more than one buffer at a time, rather than lose input.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-26 02:59:27 -07:00
Christopher Snowhill
aa3673ed33 [Audio Output] Better handle latency oddities
The visualization buffer now holds up to 45 seconds of loop, and the
latency measurement code now caps this at 30 seconds, and restarts the
output if latency exceeds 30 seconds, such as if a sound output is
reset.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-26 02:59:20 -07:00
Christopher Snowhill
c489d7ca91 [Audio Output] Play last track and stop correctly
Play last track up until it actually ends, and stop on command.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-25 06:43:16 -07:00
Christopher Snowhill
99fad892f0 [FFmpeg Decoder] Don't post redundant meta event
Don't post a metadata event on open, because inputs will relay it to the
player as an early notification bubble, which is unwanted.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-25 06:05:35 -07:00
Christopher Snowhill
8d10aa7e80 [Audio Output] Fix serious memory leakage
For one thing, the example code I followed was Swift and handled auto
releasing handles in the background, while Objective-C requires manual
handle reference management.

For two, there was no autoreleasepool around the block handling the
input audio chunks, which need to be released as they are pulled out and
disposed of. This also contributed to memory leakage.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-25 06:00:34 -07:00
Christopher Snowhill
f2dee9e0a7 [fdkaac] Update libfdk-aac to 2.0.2 with patches
Update fdk-aac library in dependencies package.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-25 05:14:09 -07:00
Christopher Snowhill
a1a084aabb [Audio Output] Fix serious deadlock issue
There was a serious deadlock issue. Now it is fixed. Whew.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-25 05:14:04 -07:00
Christopher Snowhill
cca447ca5e [InputNode] Syntax code fix
This code was misformatted.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-25 05:13:57 -07:00
Christopher Snowhill
4bc4b38489 [Play Count Info] Tabulate first seen info later
Tabulate first seen information when loading the metadata, rather than
when first adding the tracks to the playlist. This should fix first seen
information when metadata is available, as the information will be
useless without track titles.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-25 02:40:49 -07:00
Christopher Snowhill
ed8c8acc89 [Cuesheet] Greatly improve loading performance
Cuesheets were invoking a seek operation on open, rather than on first
playback, and this has a heavy toll on FFmpeg audio formats, apparently.
Defer the initial seek to the first readAudio call, and do not invoke it
if a seek was already called on that input session.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-25 02:40:43 -07:00
Christopher Snowhill
b3be8f9d11 [FFmpeg] Fix chapter handling and seeking
Fix chapter startup, and chapter seeking.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-25 02:40:36 -07:00
Christopher Snowhill
3852fab64b [FFmpeg] Seek including skip samples
This is essential for chapters, as otherwise, we would be skipping an
awful lot of samples every chapter, or every seek within a chapter.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-25 01:43:57 -07:00
Christopher Snowhill
65fd9c71c6 [FFmpeg] Support files with chapters
Support file chapters, including metadata reading for each chapter.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-25 01:35:34 -07:00
Christopher Snowhill
43c709cd9f [FFmpeg] Deduce the length from the container
Determine the length of the file from the container, rather than the
individual audio stream. The former is more likely to be set than the
latter is.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-25 00:07:54 -07:00
Christopher Snowhill
a6b6c8120b [FFmpeg] Update FFmpeg library and decoder plugin
Update based on newest changes from upstream.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-25 00:07:41 -07:00
Christopher Snowhill
d79275b285 [Audio Output] Correctly configure WAVE layouts
Correctly configure AVFoundation with the channel layouts supported by
WAVEFORMATEXTENSIBLE speaker position flags, which includes varied
formats supported by FFmpeg and Core Audio inputs.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-25 00:07:31 -07:00
Christopher Snowhill
27924e246d [Audio Output] Correctly delay layout updates
Channel layout updates should be delayed when resampling, just like
sample format changes are.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-25 00:07:20 -07:00
Christopher Snowhill
94de049184 [FFmpeg] Update minimum platform for x86_64
Update minimum platform version to macOS 10.13.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-25 00:07:04 -07:00
Christopher Snowhill
43180640f2 [FFmpeg] Enable TrueHD decoder and demuxer
Oops, somehow I didn't enable TrueHD support.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-25 00:06:54 -07:00
Christopher Snowhill
67b6a3606f [FFmpeg] Update libfdk-aac fixed point patch
Update this patch to the latest FFmpeg master source, and update to use
fmtconvert instead of a naive for loop.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-25 00:06:48 -07:00
Christopher Snowhill
d563617998 [Audio Output] Stop immediately, and fix deadlocks
Stop output when requested, except on natural completion of the last
track in the play queue. Also fix deadlocks with stopping and
restarting.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-24 19:14:48 -07:00
Christopher Snowhill
6592144584 [Vorbis / Opus] Do not assume text encoding
Stream metadata encoding may not be UTF-8, even though the Vorbis
Comment specification clearly calls for this.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-24 19:12:38 -07:00
Christopher Snowhill
26ac2b09fb Move static and dynamic libaries to archive
Please remember to unpack the archive before building, and
if it is updated by a future version.
2022-06-24 17:09:29 -07:00
Christopher Snowhill
156e25ed6a [Sandbox] Change preference dialog descriptions
Make the descriptions more apt to what they do.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-24 17:09:25 -07:00
Christopher Snowhill
f9490c1329 [OpenMPT / OpenMPT Legacy] Fix include paths
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-24 17:09:21 -07:00
Christopher Snowhill
93736565cb [mpg123] Fix include paths 2022-06-24 17:09:15 -07:00
Christopher Snowhill
431849414f [Sandbox Broker] Fix deadlock and crash
The crash was because we weren't copying the results array before
iterating over it, and the deadlock was because this was forced to go
through the main thread, rather than going through its calling thread,
which could lock up if the main thread was busy working with the Sandbox
Broker object.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-24 17:09:11 -07:00
Christopher Snowhill
ec91f61403 [Metadata] Commit first seen date for whole batch
Commit only once the entire batch is loaded and processed. Also commit
using the correct function.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-24 17:09:06 -07:00
Christopher Snowhill
32a595222d [OpenMPT / vgmstream] Made libraries pre-built
Made the OpenMPT / legacy OpenMPT and mpg123 libraries pre-built.
Changed the OpenMPT and vgmstream plugins to import the libraries as
they are now. Made mpg123 embedded and imported by the main binary,
since it's now shared by two plugins.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-24 17:09:02 -07:00
Christopher Snowhill
4540b88094 [Sandbox Broker] Copy results array
Hopefully this heads off a crash elsewhere.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-24 17:08:57 -07:00
Christopher Snowhill
0cc084b58b [Audio Output] Properly handle end of playlist
Handle audio on the end of the playlist, flushing playback until all
output stops.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-24 03:47:41 -07:00
Christopher Snowhill
858f446597 [Audio Output] Synchronize access, report latency
Report resampler latency properly, and synchronize access to the
resampler objects.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-24 03:47:33 -07:00
Christopher Snowhill
3a9db65b53 [Visualization] Resample all visualizer audio
Visualizer audio is now resampled to 44100 Hz, for consistency across
the system.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-24 03:47:27 -07:00
Christopher Snowhill
2e45deb8d3 [Audio Output] Resample unsupported sample rates
These rates are too high for Apple's output routines, for some reason.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-24 03:47:19 -07:00
Christopher Snowhill
6d772562ca [Core Data Store] Fix startup playlist pruning
The playlist was being pruned of entries marked for deletion, but they
were not being pruned from the set that was then added to the player.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-24 00:52:33 -07:00
Christopher Snowhill
ba33218ddf [Path Suggester] Automatically pop where required
The Path Suggester will now automatically open when new files are added
to the playlist and a given path is not in the sandbox settings. It will
also pop for both the File Tree and MIDI SoundFont path configuration
settings being changed.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-24 00:52:03 -07:00
Christopher Snowhill
b6621da410 [Sandbox Broker] Synchronize storage access
Synchronize storage access to main thread only, to prevent enumeration
from hitting a case of the main thread writing to the storage.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-24 00:46:45 -07:00
280b58dfd8 [Sandbox] Fixed path suggester window
Added a title to the window, make the table view resize properly, and
remove the font size inheritance from the main window.

Signed-off-by: Kevin López Brante <kevin@kddlb.cl>
2022-06-23 23:25:29 -07:00
Christopher Snowhill
dccb7f8b47 Replace Core Audio output with Core Media runtime
The output now uses AVSampleBufferAudioRenderer to play all formats, and
uses that to resample. It also supports Spatial Audio on macOS 12.0 or
newer. Note that there are some outstanding bugs with Spatial Audio
support. Namely that it appears to be limited to only 192 kHz at mono or
stereo, or 352800 Hz at surround configurations. This breaks DSD64
playback at stereo formats, as well as possibly other things. This is
entirely an Apple bug. I have reported it to Apple with reference code
FB10441301 for reference, in case anyone else wants to complain that it
isn't fixed.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-23 23:23:13 -07:00
Christopher Snowhill
2c2a058126 Cog now requires macOS 10.13 as a minimum version
All optional fallback code for older versions has also been removed, and
everything now assumes 10.13.0 or newer. Some cases are still included
for point releases, such as 10.13.2.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-23 23:23:07 -07:00
Christopher Snowhill
27b2e8584d Updated VGMStream to r1745-37-g776c4d8c
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-22 19:33:06 -07:00
Christopher Snowhill
b2c354a32c Serialize persistent store update to main thread
This needs to be called on the main thread, as something may or may not
be enumerating over the data while this thread decides to call it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-22 19:11:06 -07:00
Christopher Snowhill
6867ef1e9a [Playlist Info Loader] Do not clear if loading
Do not clear the progress indicator if a loading task is already running
in the background, but instead return without doing anything.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-22 19:06:10 -07:00
Christopher Snowhill
71d8cb6246 Comply with App Store policies
Remove the stale Updates check preferences pane, and remove the donation
option from the menu, as it is considered In App Purchases.

Consider adding actual App Store In App Purchase options of "Buy me a
coffee" or similar, with no guarantee of return for the purchase, other
than furthering development. Make them repeatable purchases.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-22 16:27:51 -07:00
5e6c0a4c52
[About Window] Fix
Pull request #281 by @nevack.
2022-06-22 18:39:36 -04:00
e46dc12efc [About Window] Reorganized credits and added @nevack and myself in them
Signed-off-by: Kevin López Brante <kevin@kddlb.cl>
2022-06-22 18:38:14 -04:00
Dzmitry Neviadomski
45345b810c Fix runtime warnings in Window/AboutWindowController.xib
Fix typo in File Owner class name and remove absent outlet.
2022-06-23 01:34:17 +03:00
9c371b8181
Merge pull request #280 from losnoco/nevack/about-window
AboutWindow adjustments
2022-06-22 18:28:54 -04:00
Dzmitry Neviadomski
43467b6978 AboutWindow adjustments
Allow opening links in default browser
Close window on Esc
Add rounded corners
2022-06-22 19:01:42 +03:00
Christopher Snowhill
05eb1c38a0 Changed updater script to handle new version strings
New version strings are in a different place, and Sparkle will no longer
be including the Git hash in the CFBundleVersion query, so we must get
it from the ZIP filename.
2022-06-22 01:17:02 -07:00
Christopher Snowhill
90b064fd3a Empty commit to sync version number 2022-06-21 23:52:21 -07:00
Christopher Snowhill
5cd39b919b Update README to add App Store information
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 23:51:50 -07:00
Christopher Snowhill
4db0fc1f5f One last attempt to fix CI
This should fix building. I don't know how I missed those.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 23:50:12 -07:00
Christopher Snowhill
73ad7901b0 Assign blank development team in project files
Hopefully this blank assignment will spare these files from being
touched by Xcode again in the future, when the variable in question is
imported from a developer supplied configuration file.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 23:29:17 -07:00
Christopher Snowhill
d3e069ddc0 Remove developer supplied configuration file
This file should not be referenced directly by projects, otherwise it
will be expected to exist, even in CI.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 23:29:07 -07:00
Christopher Snowhill
4a0d4bb093 [Volume Control] Only initialize view once
Only initialize viewController once, the first time the volume control
is opened. Re-initializing it can cause an error assigning it as first
responder to the volume slider popover view.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 22:52:52 -07:00
Christopher Snowhill
60523b985a Completely overhaul code signing practices
Redesign the code signing from the ground up. Now all bundles and their
embedded frameworks import the Shared.xcconfig file and enable its
settings, so they may be signed with Apple Development instead of sign
to run locally. This apparently isn't necessary for frameworks which are
embedded in the main app bundle directly, only for the bundles and their
frameworks.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 22:43:04 -07:00
Christopher Snowhill
82a1a400d9 Remove deep forced code signing option
This option should no longer be needed for anything.
2022-06-21 19:39:36 -07:00
d78b31d34e [Main Menu] Added Privacy Policy link in App Menu
Signed-off-by: Kevin López Brante <kevin@kddlb.cl>
2022-06-21 22:30:30 -04:00
0679b146a3 [About Dialog] Switched to WebView for credits
Signed-off-by: Kevin López Brante <kevin@kddlb.cl>
2022-06-21 22:20:18 -04:00
Christopher Snowhill
2821cb36b5 [Crashlytics] Require asking user consent
Require asking user consent for data transmission on first launch, or
otherwise disable sending crash reports by default.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 19:03:37 -07:00
Christopher Snowhill
eadac4c033 [Info Plist] Auto format XML escapes
Automatically format any XML escapes of file type association names.
Adjust Info.plist to account for this change.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 18:59:57 -07:00
Christopher Snowhill
cc46c5a5ee [Sandbox Configuration] Do more checks on test
When testing the path for whether it's in storage, run more tests to
make sure we only care about valid paths, and a path that actually has
a string.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 16:16:47 -07:00
Christopher Snowhill
3d8f470206 [Sandbox Configuration] Delete from storage later
Only delete from storage after deleting it from the UI list.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 16:15:50 -07:00
Christopher Snowhill
51f8536943 [Sandbox Configuration] Do not delete path on fail
Do not delete path from storage when save fails.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 16:14:45 -07:00
Christopher Snowhill
bc23ed6c24 [Sandbox Configuration] Fix nil pointer issues
Solve some nil pointer issues with the Sandbox configuration code being
set with invalid paths.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 16:12:28 -07:00
Christopher Snowhill
5d3077963a [Core Audio Output] Guard against nil pointer
Guard against nil refcon in the renderCallback function.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 09:37:29 -07:00
Christopher Snowhill
bacbf52e2d Update Patreon credits
Update credits with latest additions.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 09:26:25 -07:00
Christopher Snowhill
5ea6c9dde7 Remove stray entitlement from Sparkle
In preparation for submission to the App Store.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 07:24:23 -07:00
Christopher Snowhill
69f076a293 Update Info.plist
In preparation for submission to the App Store.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 07:08:05 -07:00
Christopher Snowhill
26a20db383 [Sandbox] Update Info.plist generator
Plist generator now emits the output to the temporary folder, which we
have write permission to.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 07:07:42 -07:00
Christopher Snowhill
1a4d66a773 Change the product install path to /Applications
In preparation for submission to the App Store.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 06:41:20 -07:00
Christopher Snowhill
59176ef9ec Change version numbering system
In preparation for submitting to the App Store.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 06:27:29 -07:00
Christopher Snowhill
b54ee58ec3 Removed Sparkle
Removed Sparkle in preparation for App Store release.
2022-06-21 06:05:45 -07:00
Christopher Snowhill
c958bb89e4 Add Sandbox notice to README
Add Sandbox help to the README, for new users to notice when glancing at
the repository.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 05:58:30 -07:00
Christopher Snowhill
8b2ce33813 [MAD Decoder] Better handle VBRI header frame skip
Skip the frame during decode, which will likely incur a BADDATAPTR error
on the first frame, as has already been logged in the development
process. Instead, skip the first frame, then proceed to the next one.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 05:48:58 -07:00
Christopher Snowhill
93ebedbcd9 Revert "[MAD Decoder] Patch ... libmad"
This reverts commit 453e29b2f5. Also it
applies a different workaround for VBRI headers, which doesn't require
patching libmad to work.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 05:33:15 -07:00
Christopher Snowhill
e8dacdabda [Sandbox] Add Playlist Path Suggester
Add a dialog for suggesting sandbox paths to the Preferences general
page, in the context menu.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 02:45:45 -07:00
Christopher Snowhill
5cb08291bf [Sandbox / Core Data] Refine global variable usage
Refine the global variable usage, eliminating double underscore prefixes
and trusting that static global variables will exist in the object where
the class was created. Got rid of that nasty NSApplication extension
hack that was previously in use.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-21 00:01:07 -07:00
Christopher Snowhill
4ac566c308 [Sandbox Broker] Allow to be passed directory URLs
Allow opening directory URLs as-is, rather than treating them like
files. Return the full path if the caller requests opening on a
directory.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-20 23:39:07 -07:00
Christopher Snowhill
a1ab3deec4 [File Tree] Implement Sandbox support
Implement Sandbox Broker support for the File Tree root path, in case it
is needed to enumerate files from within it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-20 23:32:40 -07:00
Christopher Snowhill
d20df5164f [Metadata Loading] Make metadata loading smarter
Metadata loading now filters the request list down to unique file paths
that don't have metadata loaded, makes sure that another instance of the
loader isn't already loading the same files, and waits for previous
instances to complete before beginning another metadata load task. It
also will update the playlist entries for all affected tracks, even if
they were not explicitly selected for loading or reloading.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-20 23:22:07 -07:00
Christopher Snowhill
4330226776 [Core Data Store] Fix empty URL filtering
Empty URL filtering was implemented incorrectly. Fix that.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-20 23:18:37 -07:00
Christopher Snowhill
f948b8ff7e [Cog Decoder Multi] Add dealloc function to close
Add dealloc function to close the file container, in case the caller
neglected to do so on its own.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-20 22:31:03 -07:00
Christopher Snowhill
2716ca41b0 [Core Audio Output] Refine output function a bit
Refine the output function a bit, including adding some minor safety
checks, in case the caller requests zero samples, or requests a format
with zero channels.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-20 22:26:35 -07:00
Christopher Snowhill
ca6a2f41df [Core Audio Output] Move output function block
Move the Core Audio output function block to its own declarative
function, so that its block variables are isolated, and so that debug
traces show up in a more sensible place.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-20 22:24:56 -07:00
Christopher Snowhill
8dddf6a115 [Sandbox] Refine broker to return handle to token
Sandbox Broker now returns a handle to the exact path object that was
retained by the caller, so it will be released correctly, regardless of
what happens to the list of bookmarked paths.

Also refined the bookmark path comparison function. For existing paths,
it will find the first match. For new paths, it will prefer the longest
path instead, to try to find the deepest matching bookmark.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-20 22:10:43 -07:00
Christopher Snowhill
dbdcad6c04 [Dock Icon] Refuse to update if plaque didn't load
Refuse to update the dock icon image if the dock icon plaque image fails
to load somehow. Really weird case.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-20 21:34:05 -07:00
Christopher Snowhill
c89837c0f8 [Play Count] Remember added count across sessions
Remember if play count was already tracked for the current file across
restarts, if resume playback after restart is enabled.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-20 19:13:33 -07:00
2ce719c7fa [About Dialog] Implemented new About dialog
Signed-off-by: Kevin López Brante <kevin@kddlb.cl>
2022-06-20 21:58:22 -04:00
Christopher Snowhill
6fb991f95e [Sandbox / Sparkle] Update entitlements
Entitlements needed to be updated to allow updating within the sandbox.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-20 17:13:54 -07:00
Christopher Snowhill
9d559481d3 [Sandbox] Disable distributed iTunes notification
This notification can't escape the sandbox anyway, and I forgot to
remove it after adding the app sandbox code again.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-20 16:43:21 -07:00
Christopher Snowhill
9dbe0a0d3e Updated VGMStream to r1745-33-gbb2a6624
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-20 16:22:07 -07:00
Christopher Snowhill
3153159658 [Sandbox] Make Sandbox prefer the longest path
The Sandbox Broker should prefer the token with the longest matching
path, not the shortest.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-20 16:16:04 -07:00
Christopher Snowhill
f85c86c5ba Fix update_feed.rb for new Sparkle
New Sparkle appcast generator stores the version string in the item
rather than as an attribute of the entities.
2022-06-20 05:18:38 -07:00
Christopher Snowhill
08107f4a41 [Sparkle] Updated to version 2.1.0 for Sandbox
Sandbox requires Sparkle version 2 or newer anyway, so upgrade it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-20 03:46:36 -07:00
Christopher Snowhill
c23bece62c Reintroducing App Sandbox, and more
- Implemented App Sandboxing in a more friendly manner.
- All sandboxed paths will need to be set in Preferences. Set as loose
  a path as you want. The shortest path will be preferred.
- Removed Last.fm client support, as it was non-functional by now,
  unfortunately. Maybe something better can come in the future.
- Added support for insecure SSL to the HTTP/S reader, in case anyone
  needs streams which are "protected" by self-signed or expired
  certificates, without having to futz around by adding certificates to
  the system settings, especially for expired certificates that can't
  otherwise be dodged this way.

If you want to import your old playlists to the new version, copy the
contents of `~/Library/Application Support/Cog` to the alternate sandbox
path: `~/Library/Containers/org.cogx.cog/Data/Library/Application `...
...continued...`Support/Cog`. The preferences file will migrate to the
new version automatically.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-20 03:35:29 -07:00
Christopher Snowhill
8009d911c2 [Crashlytics] Remove unnecessary extra log sending
The log sending should be automatic, this is unnecessary.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-19 21:48:33 -07:00
Christopher Snowhill
e071b4d913 [Crashlytics] Remove AppCheck from debug builds
Remove the AppCheck code from the debug builds, as it's not even enabled
on the project in Firebase anyway.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-19 21:46:30 -07:00
Christopher Snowhill
071d23b1c6
[SceneKit Visualization] Refine blocklist again
* Remove exception variable setter

Remove SceneKit crash variable setting exception
handler from NSApplication delegate.

* Restrict SceneKit to 10.13, 10.14, and 11.0+

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-19 21:42:39 -07:00
Christopher Snowhill
385335b37c [Core Data Storage] Refine deleted/empty items
Remove empty items also with empty URL fields.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-19 20:04:30 -07:00
Christopher Snowhill
2563125ec5 [SceneKit Visualizer] Refine blocklist
The blocklist wasn't actually blocking the requisite GPUs properly.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-19 20:03:47 -07:00
Christopher Snowhill
a2a75d6565 [MAD Decoder] Add support for FhG VBRI headers
This header type was missing, causing some Fraunhofer VBR MP3 files to
decode the wrong length information.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-19 19:40:40 -07:00
Christopher Snowhill
453e29b2f5 [MAD Decoder] Patch a slight bug in libmad
There was a slight bug with handling Xing/LAME headers with main data
pointers indicating data preceding the header frame. This should allow
decoding their information properly.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-19 18:26:18 -07:00
Christopher Snowhill
163ae5c864 [Core Data] Optimize queue and shuffle loading
Optimize queue loading code, and add shuffle list reading code.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-19 02:05:26 -07:00
Christopher Snowhill
8962403e2a [Playback Controller] Remove blank line
Remove a blank line in the code, for no real reason, other than
tidiness.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-19 01:43:35 -07:00
Christopher Snowhill
8306bd31f4 [Playback Controller] Reformat metadata handler
Metadata notifier should have been reformatted to use the properties as
dotted members, and also check for empty strings.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-19 01:43:08 -07:00
Christopher Snowhill
7fcfdb373b [Playback Status] Remember last play position
Remember last play position in the playlist, rather than using an index
variable to store its position and play time. Still store whether the
player was last playing in a configuration variable, though.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-19 01:42:27 -07:00
Christopher Snowhill
cd14377dcd [Now Playing Spam] Don't crash if nothing playing
Don't crash on now playing spam hotkey if no track is currently playing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-19 00:20:40 -07:00
Christopher Snowhill
c2388d2659 [Localizations] Remove or rename obsolete files
Remove or rename obsolete English.lproj files, renaming where
en.lproj does not already exist, or removing if en.lproj has
already replaced it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-19 00:03:09 -07:00
Christopher Snowhill
636fefaf6f [ReplayGain Info] Info strings are now localized
The strings are now part of the localized strings storage, which is
still awaiting a volunteer to add more translations to the app.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-18 23:45:18 -07:00
Christopher Snowhill
a0a5106e51 [Play Counts] Now correctly reports last seen time
Correctly reports last seen time, instead of reporting the first seen
time twice.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-18 23:44:29 -07:00
Christopher Snowhill
1c36869e57 [Audio Threads] Remove unused code
This code turned out to be somewhat of a mistake to employ, so it's now
being removed, and shall not be re-added, as it doesn't really work.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-18 23:02:24 -07:00
Christopher Snowhill
84d0cbee3c [Playlist Controller] Remove unused function
Remove a leftover function from previous code.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-18 23:01:11 -07:00
Christopher Snowhill
901ba8d218 [AppleScript Automation] Rename Playlist member
Rename this class member to match the current interface design.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-18 23:00:49 -07:00
Christopher Snowhill
a2d8e0ec42 [Track Info] Add play count tabulation and display
Add play count data collection, including first seen times for every
file first added to the playlist. Data is indexed by album, artist, and
title, or by filename, whichever matches first. Add interfaces to
AppleScript automation definition as well.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-18 23:00:08 -07:00
Christopher Snowhill
404d354918 [Playback Notifications] Fix empty hyphen on tags
This change needed to be applied in two places, oops, forgot the modern
macOS case.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-18 19:03:25 -07:00
Christopher Snowhill
3a1599d22e [Playback Notifications] Oops, fix breakage
That change broke notifications. Reverting.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-18 19:02:10 -07:00
Christopher Snowhill
8cb46b4f15 [Legacy SQLite Store] Handle errors with database
Handle missing track items in the databse more gracefully, by deleting
the track entries before passing them on to the caller, so problems do
not occur later.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-18 18:41:14 -07:00
Christopher Snowhill
7cad442b73 [Localization] Fix another unlocalized string
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-18 18:26:42 -07:00
Christopher Snowhill
20904cf2c4 [Playback Notification] Prevent sending blank tags
Prevent the notification balloons from displaying empty hyphens or tags
if either album or artist is empty but not nil.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-18 18:20:12 -07:00
Christopher Snowhill
b01924e10e [SceneKit Spectrum] Added device name to logging
Device name logging is essential in determining if crashes are on
specific device models that haven't been blocklisted.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-18 18:14:25 -07:00
Christopher Snowhill
41d4c7458e [Translations] Load PlaylistEntry error messages
These error messages should be loaded from the main bundle, where the
class is located.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-18 16:16:43 -07:00
Christopher Snowhill
ecb30dd734 [Translation Support] Update strings a bit.
Update the strings, and remove the comments where they won't be used.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-18 16:10:18 -07:00
Christopher Snowhill
1c2ecc1c7c [Playlist] Handle invalid files in a better way
Invalid files may include nil URLs, which should be skipped or stop
playback altogether. Invalid files will be marked as an error, and
stop playback.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-18 16:09:41 -07:00
Christopher Snowhill
54b102f09e [Playlist] Fix refresh handling range
Apparently, somehow, indexes in obscene ranges hit this code, and cause
exceptions. Strange.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-18 15:50:25 -07:00
Christopher Snowhill
4a269f05a1 [Audio Threads] Remove workgroup code
As it doesn't seem to work properly on Intel machines, anyway. It just
leads to pointless crashes, and doesn't seem to serve any purpose.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-18 15:43:40 -07:00
Christopher Snowhill
3156aad9e1 [Audio Threads] Restrict workgroup use to macOS 12
Restrict the use of workgroup joining and workgroup intervals to macOS
Monterey or newer, as it seems the way I use it, it's completely broken
on macOS Big Sur, which was the original minimum target for the API.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 22:39:00 -07:00
Christopher Snowhill
88b7cd6352 [Crashlytics] Added logging of track events
Added logging of track metadata load and track playback events, to aid
with crash logging.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 22:34:51 -07:00
Christopher Snowhill
fe0c388ec7 Touched by Xcode
This resource file was touched by the resource editor and altered.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 22:16:45 -07:00
Christopher Snowhill
711c18a3bd [SceneKit Spectrum] Add device block list
Currently blocking all Radeon cards up to and including Polaris cards.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 22:16:20 -07:00
Christopher Snowhill
cbcbdf893d [Spectrum Visualizer] Add crash check for SceneKit
The SceneKit visualizer now has a crash check, which will trigger if an
exception is thrown by the app.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 22:15:14 -07:00
Christopher Snowhill
fda16cc401 [Mini Window] Remove NSToolbar subclass definition
The Mini Window had its toolbar set to a non-existent class. Removed.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 22:00:26 -07:00
Christopher Snowhill
8acd7fb8f6 [Crashlytics] Add AppCheck for debugging builds
Enable Firebase AppCheck in debugging builds, so that more info may be
logged.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 19:18:41 -07:00
Christopher Snowhill
82e3f7bd9a [Crashlytics] Enable data collection by default
Enable data collection by default, so crashes are hopefully logged.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 19:18:05 -07:00
Christopher Snowhill
fa177fe96c [Audio Threads] Make work interval name unique
Work interval names should be unique. Apparently they are deduplicated
based on their names?

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 18:04:42 -07:00
Christopher Snowhill
e334d8a017 [Audio Threads] Apply changes to workgroup handler
Apply changes to exit the thread if workgroup initialization or joining
fails, instead of attempting to continue executing the thread.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 18:02:32 -07:00
Christopher Snowhill
4b4776fbc0 [Shuffle Function] Make album predicate exact
Make the album match predicate an exact match, rather than using the
"like" operator, in case there's a speed up from doing so.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 17:25:42 -07:00
Christopher Snowhill
e9b02d54f4 [Core Storage] Apply index sort to fetch request
Apply the index sort to the fetch request itself, rather than applying
it to the resulting array afterward.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 17:20:45 -07:00
Christopher Snowhill
cad6ddac02 [Shuffle Function] Greatly optimize list generator
The list generator now selects only a list of unique album names, which
may include empty string as well as NSNull, so filter those as well.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 17:03:50 -07:00
Christopher Snowhill
9820571a94 [Shuffle Function] Rewrite query for Core Data
Rewrite the album filter function to apply the filter predicate against
Core Data directly, which also requires filtering out deLeted entries so
they don't end up in the results, and also requires sorting the results.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 17:02:24 -07:00
Christopher Snowhill
dad2dbf236 [Audio Threads] Add extra guard to workgroup exit
Add an extra step to the workgroup exit call, so that it only calls to
leave if the join token is valid, or at least initialized.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 17:00:59 -07:00
Christopher Snowhill
9cc5ba7c0e [Crashlytics] Enable much earlier sending reports
Sending reports is now handled synchronously on the startup path, so
that unsent reports can be sent before a startup crash causes further
crashes to occur. This is apparently needed to help one particular user
catch whatever is causing the app to crash for them.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 15:43:12 -07:00
Christopher Snowhill
0931686a78 [Ogg Vorbis / Opus Inputs] Fix streaming titles
Fix streaming metadata titles being overridden by the Icecast stream
strings. Now the Icy metadata only overrides missing strings, so Vorbis
Comments take priority.

Fixes #275

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 10:27:17 -07:00
Christopher Snowhill
a0761a41c9 [Playlist Metadata] Safety check for deletion
Apply a safety check in case the update comes for a deleted track.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 10:25:27 -07:00
Christopher Snowhill
c7cd9b6daf [Playlist Metadata] Apply metadata correctly
Apply dynamic metadata update refreshes to the correct track index.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 10:24:45 -07:00
Christopher Snowhill
ab32365c45 [PlaylistEntry] Fix a single warning
Fix a warning about nullability of a class member.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 10:22:31 -07:00
Christopher Snowhill
5a6295be1e [Core Audio Output] Fix possible bug in enumerator
Fix a potential bug where the device enumerator would return a nil
device name string, which would result in a crash. Instead, report an
unknown numbered device.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 08:24:19 -07:00
Christopher Snowhill
7cf6a7e03b [Crashlytics] Move the crash handler initializer
Move the initializer to a function that will be called earlier in the
startup stage. Mainly to catch crashes in the playlist importer for
legacy playlist formats.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 07:24:12 -07:00
Christopher Snowhill
f696dc2205 [Highly Complete Input] Reject unsupported systems
Reject system identifier numbers that aren't supported, outright, rather
than waiting until the decoder is initialized.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 06:39:46 -07:00
Christopher Snowhill
39f4d09c1a Use NSNumber Literals as much as possible
Replaced a bunch of [NSNumber numberWith...] with NSNumber Literals.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 06:39:02 -07:00
Christopher Snowhill
67f6c931bb [Highly Complete / MIDI] Fix numeric tag reading
The new Core Data interface is especially stringent with receiving
NSNumber for the numeric types rather than NSString as was mistakenly
allowed before. Fix that to prevent exceptions.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 05:48:03 -07:00
Christopher Snowhill
3eca088cc7 Update .gitignore to block Package.resolved
Apparently my Xcode version generates files which are incompatible with
whatever Xcode build environment that Github CI runs.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 05:46:31 -07:00
Christopher Snowhill
109baf4dea [Packages] Delete Package.resolved
Apparently, my Xcode is too new for Github CI to handle this file.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 05:08:27 -07:00
Christopher Snowhill
d972a6eaf5 [Playlist] Correctly handle deleted items
The member that I set myself to indicate deletion has one capital letter
to differentiate it from the built-in "delete" property of managed
objects, which doesn't do what I want, so I had to dodge it with that
capitalization thing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 04:34:17 -07:00
Christopher Snowhill
0b3e7e3ac3 [Crashlytics] Fix symbol upload script
Use a custom script found on Stack Overflow, with some minor changes for
a little more sanity, such as using find -print0 / xargs -0 to support
paths with spaces in them.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 03:35:36 -07:00
Christopher Snowhill
277e52906a [Musepack Library] Fix capitalization of headers
Header include paths are named after the framework, which is all lower-
case, not uppercase like the source folder is named. The header include
paths inside the project are lowercase as well, so this fits.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 02:24:12 -07:00
Christopher Snowhill
1661093521 [TagLib] Completely overhaul import paths
Change most, if not all, possible import paths to use the full header
directory paths instead of relative or "assume include paths" settings.
This should fix building with the CI.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 02:19:52 -07:00
Christopher Snowhill
90b06850d0 [TagLib Plugin] Fixed some mislocated headers
These header files were imported from the wrong path. I really have no
idea why Xcode didn't catch these already with my build tree.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 02:05:48 -07:00
Christopher Snowhill
f2f71d0c9b [SID Decoder] Fix capitalization of header file
Header file name is Event.h, not event.h. Newly discovered bug on case-
sensitive file system.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 00:19:30 -07:00
Christopher Snowhill
95df58dd75 [Crash Reporting] Replace Bugsnag with Crashlytics
It was a fun ride, but I think I want to try something different. Users,
please be sure not to have DNS blocking for Crashlytics if you want me
to have any useful bug reporting info if it crashes on you, or otherwise
blows up. Otherwise, I don't get any useful data to help me fix crashes.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-17 00:11:48 -07:00
Christopher Snowhill
4e782807d8 [ReplayGain / Volume] Fix default volume value
Fix the default volume scale reading for newly added tracks, as this
value should be 1 for any files which do not have tags. Also add an
override to the tag applying function, to reset the default on tag
re-read operations.

Please reload the tags or re-add your files to fix them playing
silently.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-16 23:31:34 -07:00
Christopher Snowhill
3e01312265 [Audio Formats] Fix handling unsigned formats
This only affects the FFmpeg input, currently.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-16 23:29:52 -07:00
Christopher Snowhill
7044a9a852 [Core Audio Output] Add more event listeners
Sound output format changes should now happen instantaneously instead of
with a delay.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-16 23:28:25 -07:00
Christopher Snowhill
7bc49ccb80 [Event Handler] Fix observers for reused classes
Fix class handling so it cleans up observers if the InputNode is reused.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-16 18:16:09 -07:00
Christopher Snowhill
789e8e432e [Playlist Storage] Add another compatibility hook
Add a compatibility getter/setter for URL, which was renamed to url, due
to Core Storage having a requirement of all attributes starting with a
lower case letter.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-16 17:43:48 -07:00
Christopher Snowhill
333c6c7e8b [Spotlight Panel] Fixed to work with new Core Data
Fixed the implementation to work correctly with the new Core Data
storage system. Tracks will be garbage collected later.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-16 17:37:11 -07:00
Christopher Snowhill
c71021fc9b [Metadata] Fix assigning Unsigned property
The PlaylistEntry class needs a compatibility wrapper for the Unsigned
member, as it is assigned by all of the inputs. Case sensitivity and all
that is. And unfortunately, Core Data requires all model members to
start with a lower case letter.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-16 17:05:52 -07:00
Christopher Snowhill
72c4dddf18 [Clipboard] Add textual data to clipboard on copy
The copy action now includes formatted text of the selected entries when
copying, in addition to the supported file and URL types.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-16 07:18:28 -07:00
Christopher Snowhill
4c95c943ef [Playlist Storage] Rewrite to use Core Data
Completely rewrite the playlist storage once again, this time with a
much faster Core Data implementation. It still uses a little magic for
Album Artwork consolidation, but string consolidation doesn't seem to be
needed to reduce the disk storage size. Works much faster than my silly
implementation, too.

Old implementations are still kept for backwards compatibility with
existing playlists.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-16 07:14:33 -07:00
Christopher Snowhill
0997ca2c93 [Core Audio Output] Improve safety on stopping
Synchronize audio setup and audio stopping on the object's own pointer,
to hopefully prevent race conditions with out of sync calls to the stop
function from both the main and the audio thread.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-15 22:46:58 -07:00
Christopher Snowhill
e9230a080c [Audio Threads] Change workgroup code for safety
The changes include no longer leaving the workgroup for seeking or for
converter format changes, and also still leaving the workgroup on thread
termination if there was an error with intervals starting or finishing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-15 21:44:03 -07:00
Christopher Snowhill
02d2ab01a7 [Notifications] Prevent crash on deleted tracks
Prevent an unhandled exception when a notification is sent on a track
which has been deleted from the playlist.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-15 19:55:29 -07:00
Christopher Snowhill
8db2e41049 [Event Handling] Add context to all observers
Add context field to all observers that support it, in case it's useful.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-15 16:47:43 -07:00
Christopher Snowhill
5bca70d141 [Job Queue] Prevent multiple jobs from stacking
Jobs are meant to be serialized, so prevent multiple jobs from queueing
simultaneously, as they are not designed to interact with each other.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-15 01:10:53 -07:00
Christopher Snowhill
92573ec088 [Job Queue] Overhauled long action handling
Long actions, such as file opening, playlist loading, metadata loading
and refreshing, etc, are now handled through NSProgress. Additionally,
a new status bar change displays the progress of the task instead of
the total duration of the playlist. Finally, app quit is blocked by a
running task, and if the app is quit while a task is running, it will
be delayed until the task completes, at which time the app will
terminate cleanly.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-15 01:01:45 -07:00
Christopher Snowhill
6c7a3e581c [Playlist/Metadata] Prevent a race condition
Prevent a race condition with deleting playlist entries while their
metadata is still being loaded by the player.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-14 21:27:51 -07:00
Christopher Snowhill
9d558a89ab [Playlist] Guard Open in Finder against empty set
Guard Open in Finder against being called on a playlist with no
selection, which may happen if the action is triggered on an empty
playlist, which would cause an array out of bounds access error.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-13 16:28:29 -07:00
Christopher Snowhill
686cf95795 [Playlist] Guard entry selection against empty set
Guard the playlist entry retrieval function against being called on an
empty playlist, because an empty playlist would result in a division by
zero error to occur here.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-13 16:27:32 -07:00
Christopher Snowhill
e5ff6cd23d [Position Slider] Fix invalid duration setting
Fix NaN condition occurring when an invalid file is played.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-13 02:01:26 -07:00
Christopher Snowhill
55c623c9a0 [Legacy XML Playlist] Fix import if queue missing
If there is somehow a legacy XML playlist, and there is no queue entry
in the plist, then it should not throw an exception from trying to add
a nil object to the return dictionary.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-13 01:46:44 -07:00
Christopher Snowhill
6825d15f68 [HRIR Filter] Employ impulse cache
An impulse cache reduces any glitching from format channel count changes
to near insignificant levels, resulting in a more pleasant experience
when there are different mixed formats playing, or even a file which
changes format mid-playback.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-12 22:21:01 -07:00
Christopher Snowhill
120a93465e [Metadata Handling] Fix dynamic info updates
Ensure that dynamic info updates, even on static files, only update the
exact track they apply to, by atomically assigning the userInfo property
before opening the decoder, so that callbacks to the player indicate the
correct track and don't assume it's the one that's currently visibly
playing. Fixes start of track metadata notifications from overwriting
the previously playing track.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-12 19:43:41 -07:00
Christopher Snowhill
e84065ff5c [libOpenMPT] Updated to version 0.6.4
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-12 19:40:39 -07:00
Christopher Snowhill
b675ced77b [MAD Input] Don't do full file scans on CBR files
Only do a rough estimation on files without Xing or LAME or iTunes
headers. This is much faster, even if less accurate, and may include
the footer tag if present.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-12 16:09:56 -07:00
Christopher Snowhill
a4f40971dd [SQLite Store] Every schema upgrade should process
Every schema upgrade process should fall through to the next highest
version number, so they should all run, if the user has somehow upgraded
their database from such an old version.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-12 01:57:47 -07:00
Christopher Snowhill
aaade58842 [Cuesheet Input] Fix metadata handling by merge
The inputs now have their own metadata function, so it should merge in
the track tags from the Cuesheet, and not just forward it to the
decoder.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-12 00:55:37 -07:00
Christopher Snowhill
ab16c43c85 [Translations] Re-sync incomplete Spanish translation
Re-sync the placeholder Spanish translation from the English one.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-11 17:04:38 -07:00
Christopher Snowhill
d875be0454 [Project Files] Add possibly missing framework
Bugsnag framework was possibly missing from the config files, so
it's been added properly on older Xcode.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-11 17:01:42 -07:00
Christopher Snowhill
854431b784 [MAD Input] Initialize state variable, fix crash
This should prevent a crash if the input is recycled for another file,
which would cause the output buffer to be freed, but the output size to
contain a count on first call to readAudio, which would cause a memory
access crash.

Possibly fixes #269

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-11 14:21:43 -07:00
Christopher Snowhill
90b83f8f51 [Various] Clean up various warnings
Various warnings related to uninitialized variables, or setting values
to variables that would not be used later or would be overwritten by per
loop initializers.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-11 13:42:42 -07:00
Christopher Snowhill
f02a36fd08 [Highly Complete Input] Fix possible crash on OOM
If one condition returned memory successfully, but the other did not, it
would result in the cleanup code accessing an uninitialized pointer and
iterating over it, crashing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-11 13:41:26 -07:00
Christopher Snowhill
b03fdeaf7a [File Tree Browser] Fix resource leak
These two objects were or could have been leaked previously.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-11 13:40:08 -07:00
Christopher Snowhill
da8288eeee [Converter] Change utility function for safety
Surprised I didn't catch this sooner. This could have resulted in a
division by zero error if either sample rate somehow was zero.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-11 13:39:14 -07:00
Christopher Snowhill
7c8a270ed2 [Dialogs] Renamed HDCD toolbar items to be unique
The two toolbars seem to require unique identifiers for each of their
items, even when they're separate toolbars in separate windows.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-11 13:37:51 -07:00
Christopher Snowhill
8d8089a8e9 [Dialogs] Template touched by Xcode
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-11 13:36:03 -07:00
Christopher Snowhill
f22a74ab3a [Translation Support] Fix several string constants
Several string constants were not fetching from the translation strings
table. Fixed this.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-11 13:34:57 -07:00
Christopher Snowhill
f38f38ee4a [libOpenMPT Legacy] Updated to version 0.5.18
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-11 07:27:02 -07:00
Christopher Snowhill
dd307d27a7 [libOpenMPT] Updated to version 0.6.3
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-11 07:26:39 -07:00
Christopher Snowhill
af0a2436fc [FFMPEG Input] Support reading more metadata
Now read all metadata and signal it, and also support pre-buffering
a small block of sample frames if there is embedded artwork, since the
embedded artwork must be handled by the sample decode function.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-11 06:39:00 -07:00
Christopher Snowhill
4828b7f1c1 [FFMPEG Input] Metadata reader supports "genre"
Add support for plain "genre" tag, in addition to the previously
supported "icy-genre" field for streams, this one is for static files.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-11 06:37:31 -07:00
Christopher Snowhill
d89edfb979 [FFMPEG Input] Add .dsf filename extension
This format is already supported, but the extension was mistakenly left
out of the format list.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-11 06:35:58 -07:00
Christopher Snowhill
7cac6625d9 [Visualizer] Align memory allocations for DFT
DFT should use aligned memory blocks for best results. Also allocate one
extra sample for DFT output, just in case DFT zop is as bad as zrop.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-11 03:33:42 -07:00
Christopher Snowhill
6c733762d3 [HRIR Filter] Add safety margin for DFT
DFT float happens to clobber one extra sample on forward translate, so
allocate one extra for every complex buffer.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-11 03:32:38 -07:00
Christopher Snowhill
040a61e1ed [HRIR Filter] Replace implementation with vDSP
Work back to a vDSP implementation, this time using overlap-save instead
of overlap-add, also accumulating the results as complex values, only
inversing them once at the end, and finally, replacing the FFT method
with the newer DFT API.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-11 02:25:40 -07:00
Christopher Snowhill
7b18a9f398 [Visualizer] Add PFFFT implementation for example
The PFFFT implementation is actually slower than Apple's float DFT code.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-11 02:21:17 -07:00
Christopher Snowhill
b3b4d728f9 [Legacy Visualizer] Customizable colors, labels
The legacy 2D visualizer now supports customizable bar and peak dot
colors, and renders a grid and labels in the windowed mode.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-10 22:38:46 -07:00
Christopher Snowhill
b821896560 [Visualizer] Constrain SceneKit visualizer events
Constrain observer events to the exact context requested, and remove
them with the same context specified.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-10 22:35:51 -07:00
Christopher Snowhill
10f0644407 [Core Audio] Conditionally uninitialize equalizer
Only uninitialize the equalizer if sound output was successfully started
and the equalizer AudioUnit was successfully ininitialized.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-10 18:43:56 -07:00
Christopher Snowhill
d390febe72 [Core Audio] Remove redundant initialization
These variables will be zero initialized by the class already.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-10 18:42:37 -07:00
Christopher Snowhill
2c7285382c [SQLite Store] Add type checks to add string/art
String and art adder functions now perform type checks, in case of
memory errors that somehow result in classes changing type. Which in
itself is a strange thing to happen.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-10 18:26:45 -07:00
Christopher Snowhill
e69ddb3578 [SQLite Store] Restructure add art/string code
Restructure the add string or art functions so they don't take a pointer
to a pointer, which may have caused issues when receiving a nil string
from the caller. Instead, take a plain pointer, and return the object,
returning the ID of the object to a pointer to an int64_t.

Also change several prototypes and functions to use _Nonnull or
_Nullable where appropriate.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-10 18:10:47 -07:00
Christopher Snowhill
f23f8970cc [VGMStream] Change libvgmstream optimization level
Optimization level bugs now affect Apple Silicon release builds, so
reduce optimization level there as well.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-10 16:43:27 -07:00
Christopher Snowhill
ef2ba385f2 [Audio Threads] Clear workgroup token on exit
When leaving the workgroup, clear the token, as the join call requires
the token to be uninitialized.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-10 16:42:33 -07:00
Christopher Snowhill
22a41e71d3 [Audio Threads] Add further safety gating on error
Errors should stop all attempts to further use the audio thread priority
code, so there won't be debug breakpoints called on older OSes.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-10 15:20:07 -07:00
Christopher Snowhill
1c9887053c [MAD Decoder] Fix crash on invalid files
The properties function should not be dereferencing an invalid index
into the layer codec name array if layer is not set to 1 through 3. This
could happen if, for instance, an MP3 file has an invalid ID3v2 tag.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-10 02:55:13 -07:00
Christopher Snowhill
ffdb6262c2 [MAD Decoder] Fix sample count calculation crash
This condition would underflow when skipping a bunch of samples on the
start of playback, or otherwise seeking, and could cause an unsigned
underflow, which would cause the subsequent vDSP_vflt32 to overread into
the MAD sample buffer and crash.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-10 02:44:02 -07:00
Christopher Snowhill
fe82b5ed65 [DSD] Reduce volume level of decimator output
As the decimator has shown to be twice as loud as it should be, the
volume should be reduced by half when converting DSD to PCM with it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-10 02:14:04 -07:00
Christopher Snowhill
4537a72275 [DSD] Add pure downsampling path, disabled
Pure downsampling is slower, but may or may not be more accurate. Though
probably not worth it. It did help me realize a minor error, though.
The decimator's volume is twice as loud as it should be.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-10 02:13:10 -07:00
Christopher Snowhill
92f6c38db0 [Playlist View] Fix constraints for status image
Status image should be positioned properly in the playlist, this minor
change was needed again.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-10 02:11:10 -07:00
Christopher Snowhill
6156aa0095 [Credits] Update Patreon credits
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-10 00:30:18 -07:00
Christopher Snowhill
90e24d2459 [Playlist View] Reset column constraints
Reset column constraints to suggested defaults. We can tweak them from
there if necessary.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-10 00:24:48 -07:00
Christopher Snowhill
e96a4efa68 [Metadata Loading] Added null pointer guards
This prevents crashes where inputs were not returning either properties
or metadata blocks and the file open cache was attempting to cache the
resulting nil pointer as if it were valid. Also prevent the metadata
redundant string coalescing from processing nil objects as well, in case
it's used that way somewhere else.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-09 23:18:51 -07:00
Christopher Snowhill
2dabcb2581 [Build System] Forgot to set API key for symbols
The symbol uploads on archive are useless unless they're uploaded with
the API key set correctly in the script.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-09 21:25:03 -07:00
Christopher Snowhill
aca29e472b [Bug Reporting] Introduce Bugsnag crash reporting
Crashes will now be collected with an optional comment, and uploaded on
next launch of the app.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-09 18:58:42 -07:00
Christopher Snowhill
bca1b02dc4 [Git Hooks] Fix hook to ignore submodule projects
Submodule projects are sometimes out of my control, so I shouldn't have
to deal with team identifiers in projects that don't affect my build
process in any meaningful way. The only way to deal with this would be
to fork and modify every project I touch that contains this stuff. No.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-09 18:55:21 -07:00
Christopher Snowhill
6bd0bf1dc5 [Audio Threads] Set realtime priority on old OS
Set baseline real-time priority for audio threads even on old macOS,
since that API is available there. Only set it once, and do not attempt
again if it fails, only once per thread.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-09 18:53:58 -07:00
Christopher Snowhill
7813712df3 [Audio Threads] Correctly set real time priority
I'm not sure about macOS Ventura, but stable releases of macOS, at
least on Intel, require that threads joining Audio Interval
workgroups already be set to run as real-time before joining. Not
doing this results in an uncaught exception and a crash.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-09 18:15:44 -07:00
Christopher Snowhill
91898e9e77 [Audio Threads] Change workgroup system again
Now it allocates audio workgroups per thread, using work slices like the
Apple documentation describes for asynchronous threads.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-09 01:38:30 -07:00
Christopher Snowhill
fef8821cf6 [Visualizer] Add extra condition to visible check
Add an extra condition to the visibility check, which is similar to the
previous version of this check, which now guards against the window it
is hosted in not being visible.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-09 00:43:23 -07:00
Christopher Snowhill
6179b304d0 [Audio Threads] Join output device workgroup
On Big Sur or newer, it is possible to join the audio threads to the
same OS workgroup as the audio output device, improving response.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-09 00:27:55 -07:00
Christopher Snowhill
cdcbabd72f [Visualizer] Accidentally left in debug test code
This was changed to verify the legacy code still works.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-08 21:56:47 -07:00
Christopher Snowhill
1728debe94 [Visualizer] Bring back CoreGraphics visualizer
For legacy systems that do not support Metal. The Metal SceneKit view
does work on even 10.13.6, if a Metal GPU is present in the system.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-08 21:32:52 -07:00
Christopher Snowhill
f2b015c149 Merge branch 'xcode14' 2022-06-07 19:06:48 -07:00
Christopher Snowhill
6022526ad4 [Visualization] Improve hidden window detection
The NSView should detect if it's a visible control in a window

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-07 19:01:47 -07:00
Christopher Snowhill
fc7a8dbcb7 [Vorbis Plugin] Fix compilation on case sensitive
Fix compilation when source code is checked out on a case sensitive file
system.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-07 18:58:45 -07:00
Christopher Snowhill
f11ef2d887 [Playlist Controller] Fix ambiguity with Xcode 14
This NSArray member call is ambiguous, but Xcode <14 allowed it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-07 18:57:19 -07:00
Christopher Snowhill
00ea4562dc Update project files for Xcode 14 recommendations
Update all project files with new upgrade version number, and add the
dead code stripping option. Don't touch MASShortcut because it's not my
project.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-07 18:56:11 -07:00
Christopher Snowhill
dc103ac546 [Visualizer] Disable processing when vis is hidden
When visualizer windows are created, but not actually visible, stop the
update timer, to save processing, especially if the vis is enabled in
one or the other main/mini windows.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-06 08:19:42 -07:00
Christopher Snowhill
c208f60da4 [HRIR Convolver] Rewrite to use PFFFT float
Replace overlap-add vDSP/Accelerate implementation with a faster PFFFT
overlap-save implementation, using fewer FFT steps as well.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-06 08:18:33 -07:00
Christopher Snowhill
18af8a06df [Output] [Downmixer] Optimize a bit
Rewrite some of the output and a lot of the downmixer to use Accelerate
framework instead of dumb for loops.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-06 08:16:27 -07:00
Christopher Snowhill
0ba766023e Playlist/Time: Simplify font initialization
Apparently this simpler API already existed on a minimum of 10.11 for
creating a system font with monospaced digits.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-03 16:46:37 -07:00
Christopher Snowhill
eaa73bc52f [Threading] Queue expensive actions outside audio
Use delayed dispatching on expensive operations which occur every time
the "heard" track end happens, and when audio metadata is changed by a
stream, so that they are inserted into the main thread queue after the
invoking callback returns control execution back to the audio thread.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-30 23:59:42 -07:00
Christopher Snowhill
4a0b337936 [Resampler] Change pffft_double project import
Change import from folder reference to group, like I originally
intended.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-30 22:31:49 -07:00
Christopher Snowhill
05f17ea950 [Menu] Add Stop after Selection to context menu
Since the existing code already supports setting any arbitrary track as
a stopping point, add a menu interface to toggle Stop After for any
track in the playlist. Stop After will be removed from the given track
after it has been played. Stop After will not be remembered on disk.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-30 22:23:02 -07:00
Christopher Snowhill
aabd9431f1 [Visualization] Gate registered observers
Gate registering observers behind a check variable in the object state,
which will be zero initialized by the Objective-C runtime, and will
prevent the class from erroneously unregistering observers without them
being registered in the first place. Apparently, services cannot be
unregistered if they were never registered first, or else an exception
will be thrown upon attempting to unregister them. This fixes a crash on
startup in the now several times running failure to work properly on
legacy Macs without Metal graphics, now that the new visualization
system has been implemented.

It's probably not worth bringing back the previous Core Graphics based
visualizer method anyway, as on those same legacy machines, it was
causing out of control CPU usage by WindowServer. At least on modern
Macs, any amount of 60fps UI updating will cause WindowServer to use
about 45% of a core, regardless of how many apps are drawing that much
at once.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-30 21:38:29 -07:00
Christopher Snowhill
94057cf467 Updated VGMStream to r1745-22-gf696beb0
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-30 18:26:34 -07:00
Christopher Snowhill
bea896cca5 [Resampler] Switch r8brain back to PFFFT double
Apparently, PFFFT double is much faster than vDSP, and I didn't even
notice. Thanks to Aleksey Vaneev for testing this properly.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-30 18:24:37 -07:00
Christopher Snowhill
50342891af [Convolver] Normalize HRTF impulse when resampling
When resampling the impulse according to the playback rate, it becomes
necessary to normalize the resulting impulse by the inverse of the
sample ratio, as resampling adds more or less loudness by virtue of
interpolating samples.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-30 01:39:12 -07:00
Christopher Snowhill
7e0b7f2008 [Resampler] Update r8brain with proper commit
This will be proper at least unless I get this commit merged upstream.
Squashed the changes to a single commit, and removed extraneous
whitespace that crept into the code.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-30 01:37:11 -07:00
Christopher Snowhill
8c2df13f3b [Visualization] Disable visualization if no Metal
If the system has no working Metal devices, disable the visualization.

The legacy visualization was also too slow for said systems to handle
reasonably anyway, so I guess it's safe to say that they shouldn't have
to handle any visualizers at all. At least have working audio playback,
of course, since that is the primary function of the application. Too
bad that the OpenGL renderers don't work on my scene, it would be nice
to have a fallback there. GL 4.1 crashes on an M1, and both GL 4.1 and
3.2 crash with SIGFPE division by zero error on Intel Macs without Metal
devices. Meh.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-30 00:15:49 -07:00
Christopher Snowhill
539a8c79eb [Visualization] Remove default Metal device option
Remove the default Metal device option, as it can return nil on systems
where it won't be expected to work.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-28 19:32:26 -07:00
Christopher Snowhill
ec18d0b260 [Visualization] Fix crash with frequency mode
The frequency mode, apparently the default, doesn't like that the code
was setting the width of the spectrum data to 11 instead of the default
1000. This was causing it to overwrite freed memory when the spectrum
started processing audio.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-28 18:31:09 -07:00
Christopher Snowhill
6b381f3d08 [Visualization] Remove OpenGL fallback
The OpenGL fallback was causing division by zero errors on Intel Macs
running macOS High Sierra.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-28 18:23:15 -07:00
Christopher Snowhill
5e5b2e4071 [Visualization] Add micro bias to cylinder scale
Apparently, old macOS wants to divide something by the scale size, so
setting it to zero causes division by zero errors? Let's set it to a
really small number instead.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-27 04:33:07 -07:00
Christopher Snowhill
0cc7e61434 [Resampler] Remove another bad block of code
Oops, I missed some code when fixing it up.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-27 04:09:51 -07:00
Christopher Snowhill
f89f1dad5a Change comment to be more correct
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-27 04:06:17 -07:00
Christopher Snowhill
527976197a [Resampler] Oops, made an error with multiply
The function I added only works for non-interleaved real/imaginary pairs
and not the interleaved setup that r8brain expects. Fix that by removing
the multiply implementation and using the original one.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-27 04:01:49 -07:00
Christopher Snowhill
381e52178c [Resampler] Change FFT to use Accelerate framework
The used fork of r8brain now uses the Accelerate vDSP FFT functions for
resampling, which should provide a slight speedup, or significant for
large sample ratios.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-27 03:40:14 -07:00
Christopher Snowhill
4d25b41462 GME Plugin: Silence a type truncation warning
Adding a cast here silences a warning from passing a long to a function
accepting an int. It doesn't really matter here anyway, as the long in
question is hard coded to initialize to a fixed sample rate. Even when
sample rate configuration is eventually added, this will still be hard
capped to well within the range of 32-bit integers.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-24 01:11:07 -07:00
Christopher Snowhill
872816f056 VGM Decoder: Change logic of dictionary creation
Metadata logic code should be using this dictionaryWithDictionary method
so that the resulting dictionary is actually immutable, like it claims
to be, rather than simply casting it. Safety coding, all that jazz. Not
really a major issue, just feels right.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-24 01:09:39 -07:00
Christopher Snowhill
8cf37cadf3 Unicode metadata: Change most logic to use guesser
Most file formats the player supports may or may not have UTF-8 safe
strings in their metadata. This should not be assumed to be UTF-8, and
when it is assumed, it results in nil NSString objects, which results in
inline initializers crashing due to uncaught exceptions.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-24 01:07:55 -07:00
Christopher Snowhill
f7dc6beda1 Plugin utilities: Moved encoding guesser to header
Moved the string encoding guesser/converter to the Plugin.h header, so
it may be accessible from any plugin. I may make it a global member of
something eventually, but a static inline for such a simple function
should be fine for now.

This function facilitates converting arbitrary 8 bit encoded strings to
Unicode NSString objects. It should be used anywhere that UTF-8 is
expected, but not necessarily guaranteed, and where other 8-bit
encodings may also be supplied by a user's files.

Not using this setup for string inputs has already led to failed UTF-8
decoding resulting in nil NSStrings being passed to the inline array or
dictionary initializers, which results in crashes due to uncaught
exceptions.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-24 01:05:43 -07:00
Christopher Snowhill
4b2cf22800 [Visualization] Use OpenGL on legacy systems
On legacy OSes, and legacy GPUs, it should use OpenGL and not Metal,
otherwise there could be horrible performance, or even crashes.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-23 17:21:13 -07:00
Christopher Snowhill
c59d4d0215 [Visualization] Tear down window vis when not open
When the visualization window is not open, it should not continue to run
the scene until the app is quit. Apparently, the windowed mode is really
slow on old Intel machines, too. Full screening it is enough to bodge
the entire system session until the machine is remotely rebooted.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-22 18:39:32 -07:00
Christopher Snowhill
84eadd1f33 [Visualization] Use forced 3D mode in window
Windowed style should always use the perspective camera mode.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-22 17:45:51 -07:00
Christopher Snowhill
438634d6df [Visualization]: Change peaks to float on top
Change the peak sphere positions so they float on top of the bottom or
the bars, instead of clipping into them.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-22 17:25:21 -07:00
Christopher Snowhill
f4712ad219 [Visualization]: Add Spectrum window
Add a dedicated spectrum visualization window, and add the necessary
hooks to start its event timer if playback is already running when it is
first opened.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-22 17:24:35 -07:00
Christopher Snowhill
e2d7ebdec5 [Visualization] Enable anti-aliasing
Enable 8x multisampled anti-aliasing, to improve the appearance of the
spectrum on non-Retina/HiDPI displays. It can't really hurt on HiDPI,
either. Hopefully this won't cause it to use a whole load of GPU
resources, more than is reasonable.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-22 16:32:57 -07:00
Christopher Snowhill
79ac1e0dd6 [Visualization] Adjust Spectrum scene parameters
Disable color fringing and motion blurring, which were causing artifacts
with the transparent background.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-22 16:31:34 -07:00
Christopher Snowhill
b99bc67bac
Merge pull request #256 from losnoco/nevack/spectrum-camera-mode-angles
[Visualizer] Adjust 2d projection camera angles.
2022-05-22 16:28:18 -07:00
Dzmitry Neviadomski
a58b11dc90 [Visualizer] Adjust 2d projection camera angles. 2022-05-23 02:12:25 +03:00
Christopher Snowhill
4f1ea02359 README: Add directions for Git hooks path
Since we use a non-default path in the repository to store shared hooks,
it needs to be configured on a freshly cloned repository before it can
be usable.

Yeah, I forgot to follow my own directions before working on the project
for quite some time. The error crept in at the following commit:

2aa3ddd545 - Icon replacement, and team ID

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-22 16:12:12 -07:00
Christopher Snowhill
25906d1b2b Project file: Remove team ID that leaked in
I accidentally forgot to enable my hooks after cloning on a new macOS
installation.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-22 16:10:51 -07:00
Christopher Snowhill
4035ca861f Spectrum Visualizer: Add customization options
Add options to the Appearance preferences page to allow changing the
spectrum's projection between a 2D-like one and 3D perspective, and add
options to change the bar and peak dot colors.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-22 15:26:27 -07:00
Christopher Snowhill
fce0e129a5 Spectrum Visualization: Replaced spectrum view
Introduced a brand new spectrum view based on SceneKit, with a scene
created by @kddlb and then altered by me to add the peak spheres. This
new scene should be lighter on display resources, even though it's fully
3D instead of a vector 2D scene done in Cocoa drawing primitives.

Co-authored-by: Kevin Lopez Brante <kevin@kddlb.cl>
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-22 00:03:52 -07:00
Christopher Snowhill
bf54c45242 Info.plist: Updated with new file types
Updated with new file types added by VGMStream.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-02 15:00:39 -07:00
Christopher Snowhill
ace62005db Updated VGMStream to r1745-4-g9ef1030d
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-02 14:58:25 -07:00
Christopher Snowhill
2aa3ddd545 Icon: Replace icon with a newly rendered design
Icon has now been replaced with a newly rendered design, and code
changed accordingly.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-05-02 14:35:09 -07:00
Christopher Snowhill
5a47021f6d MAD Input: Fix gapless decoding of FFmpeg files
FFmpeg processed files may also contain the LAME tag magic of 'Lavf' or
'Lavc', not just 'LAME'. Missed this when I was maintaining the FFmpeg
code that handles this, or at least adding iTunes support to it.

Fixes #250 again.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-04-25 13:19:12 -07:00
Christopher Snowhill
2995f67c56 Updated VGMStream to r1721-52-g4eb40f00
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-04-21 14:29:41 -07:00
Christopher Snowhill
6a9b37f91e Info.plist: Update bundle properties
Update includes turning on system generated icons for all file types,
as well as adding several new file types from VGMStream that I missed
the last time around. Also includes some new fields that Xcode added in.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-04-21 14:24:05 -07:00
Christopher Snowhill
136200e963 Info.plist generator: Update with default icons
Update the Info.plist generator to emit file type definitions which use
system generated icons in place of the legacy icons in the app bundle.
Also include the new LSHandlerRank field. And also add a definition for
the scripting definition, which I accidentally added to the Info.plist
manually when I fixed scripting.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-04-21 14:22:43 -07:00
Christopher Snowhill
c6c76c696d FFmpeg Input: Change Monkey's Audio description
Apparently, Info.plist, as generated by Xcode, is perfectly fine with
raw apostrophes in the source code, and doesn't require it to be an XML
entity.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-04-21 14:20:35 -07:00
Christopher Snowhill
94f915b892 VGMStream Input: Fix subsong files dumping tracks
Fixed an issue with individual files that reference single subsongs
inadvertently dumping all tracks in the referenced bank to the playlist,
instead of only adding the one bookmark or txtp file. Now it matches the
behavior of foobar2000.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-04-20 01:50:44 -07:00
Christopher Snowhill
d1c6950ec6 MAD Input: Further gapless decoding and seek fixes
This time, a two-fer. First, ensure that file start seeking still skips
over the Xing/LAME header packet properly. Then, ensure that decoding
the last desired packet of the file does not indicate having decoded
more sample data than desired, which may have caused errors when
resuming playback position on restart and then smoothly transitioning to
the next track.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-04-19 23:56:17 -07:00
Christopher Snowhill
54f6702fb2 Updated VGMStream to r1721-48-g9d47eded
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-04-19 23:29:21 -07:00
Christopher Snowhill
299cc5a406 MAD Input: Possible further fix for seeking
This is a possible fix for another gap issue I experienced, and may be
exposed by seeking from the start of the file without decoding first.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-04-19 23:19:52 -07:00
Christopher Snowhill
36d2d7b7e0 MAD Input: Fixed gapless handling on file start
This error was caused by the necessary fix of the previous commit, only
it caused something completely different. Due to the fact that MP3 is
included in the list of formats supported for embedded CUE Sheets, the
open stage performs a seek to the file start after opening the file,
even if there is no sheet embedded. And the resulting seek was supposed
to be a null operation, since the file was already at the start. But, as
a result, this reset the start skip counter to zero, and because the
offset wasn't backwards, but to the same position, it didn't reset the
skip counter to the start of track delay. So, as a result, start of
track delay wasn't being removed, introducing a gap. Now, this change
bypasses the seek function altogether if seeking would do nothing from
the current playback position. Whew.

Fixes #250 and MP3 gaplessness in general, surprised I didn't notice
this sooner myself, but I guess I didn't bother to verify whether my
change would break anything. Whoops.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-04-19 22:57:21 -07:00
Christopher Snowhill
2ed463034f MAD Input: Fix seeking backwards and in general
A backwards comparison led to seeking forward doing a full seek up from
the file start, and seeking backwards being a non-functional operation,
so the file would just continue playing as if there were no seek.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-04-01 19:34:54 -07:00
Christopher Snowhill
69ebce32c0 Revert "VGMStream Input: Remove downmixing, add layout"
This reverts commit 0d4ee4c901.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-21 16:34:49 -07:00
Christopher Snowhill
38969cd3b1 Updated VGMStream to r1702-86-gb1acf343
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-14 04:39:00 -07:00
Christopher Snowhill
3815ba0baf libOpenMPT Legacy: Updated to version 0.5.17
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-14 04:35:36 -07:00
Christopher Snowhill
aa28b2beb1 libOpenMPT: Updated to version 0.6.2
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-14 04:34:25 -07:00
Christopher Snowhill
8abbf267e1 Highly Complete / USF: Fix playback for some USFs
The code now requires a variable to be set if Display Lists are to be
skipped by setting display processor interrupt as the bypass code is
supposed to. Also handle unsupported Ucode by calling the low level RSP
emulator instead.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-09 20:55:15 -08:00
Christopher Snowhill
efadd1d012 Changed add files to observe playlist settings
Reverted 7f3da31b45, and reverted a past
commit of some sort. Now adding URLs and opening files from the Open...
option will obey the preferences for playlist adding, including modifier
keys, if used.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-08 00:04:14 -08:00
Christopher Snowhill
8cdbc28455 Core Audio Output: Add extra safety checks
Add safety check to check if a device is actually alive when enumerating
it, and also add nil pointer checks for the device name before trying to
CFRelease it. Fixes a rare crash on device add/remove cycle, such as
Bluetooth headphones.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-08 00:00:34 -08:00
Christopher Snowhill
9a0c598cf1 MAD Decoder: Correct length of iTunes MP3 files
The total frames count in the iTunSMPB header is the encoded length, so
add the start and end padding to it for the decoder implementation,
which expects this variable to contain the total decodable length
including the start and end padding. Fixes gapless decoding of iTunes
files.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-07 23:59:14 -08:00
Christopher Snowhill
183a03657d VGMStream Decoder: Fix mutable dictionary
This dictionary was replaced with an inline literal declaration, but
this defines an immutable dictionary. Change it to a mutable copy.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-06 03:57:03 -08:00
Christopher Snowhill
ab8154348e Hively Replayer: Fix undefined behavior
Shifting negative numbers to the left is undefined behavior, so replace
with a multiply operation instead.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-06 03:53:28 -08:00
Christopher Snowhill
014f136b7e Visualization: Protect against out of bounds read
The analyzer was reading out of bounds, so guard against that.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-06 03:51:25 -08:00
Christopher Snowhill
26966c46a2 Cog Audio: Sanitize search paths
Remove references to previously used libraries from search paths.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-06 03:50:01 -08:00
Christopher Snowhill
6741151423 Highly Complete / USF: Enable HLE again
Enable HLE processing for USF playback, based on previous commit filling
out the HLE operations list. It should be safe to enable it again now.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-05 20:44:41 -08:00
Christopher Snowhill
d570cf346d Highly Complete / USF: Preliminary overload HLE
Include preliminary overload effect for MP3 and CBFD HLE operations,
based on a pull request from upstream. This should make the HLE pretty
much sound for general use once again.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-05 20:43:41 -08:00
Christopher Snowhill
5622e92899 Resampler: Fix gapless output
The resampler wasn't being given enough room to flush its final output,
so a function was added to determine the current output latency, and
more sample data is requested, allowing the full output flush to occur.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-05 20:40:18 -08:00
Christopher Snowhill
6dccaa4d7f Fixes starting playback on short files
These two changes fix playback issues with either starting in the middle
of the playlist on a really short file terminating immediately instead
of queueing more files (InputNode.m), and issues with starting playback
at all on the end of a playlist on a short file. (OutputCoreAudio.m)

Fixes #246

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-05 15:53:47 -08:00
Christopher Snowhill
7c5cec1eb7 Amend r8bstate definition with extra safety
Just in case anything using the implementation ever needs to request
less sample data than would be returned by the resampler, it should be
able to return a remainder and keep extra remaining samples, if any.
However, the way Cog currently uses it, it would not be likely to run
into this scenario.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-05 15:23:21 -08:00
Christopher Snowhill
ed0f7d81ab Various fixes for R8Brain resampler wrapper
Fixes to the resampler wrapper, such that it will survive some close
encounters with the edge of the buffer, if necessary. Also so it will
obey the buffer size limit for the output buffer.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-04 20:44:36 -08:00
Christopher Snowhill
e1fa8d1e9b Clarified my hopefully not too stupid position
Sorry about that, everyone. I didn't mean to make it look like I
was freezing out my audience by assuming a portion of them support
the every move of their government.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-04 18:52:03 -08:00
Christopher Snowhill
18121a0a5a Forked R8Brain repository
The lineage of this library was not as obvious to me as it should have
been, considering the country of origin. While the developer has not
publicly stated their position on the invasion of Ukraine, they seem to
be in the anti-vaccine camp, which is disappointing to say the least.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-04 18:08:26 -08:00
Christopher Snowhill
fe4af170ef Add R8Brain to the credits and readme
Added the R8Brain notice to the credits html document, and added a link
to the Github repository to the README.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-04 14:19:27 -08:00
Christopher Snowhill
c9ed4bc678 Rename a variable to be more correct
This rename is more in line with what R8Brain does in its example code.
No actual behavioral changes to the code, however.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-04 14:18:23 -08:00
Christopher Snowhill
7f7e17a410 Correct capitalization of WavPack in codec info
Report the correct codec name for WavPack files. An info refresh will be
needed for it to take effect on existing playlist entries.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-04 02:08:55 -08:00
Christopher Snowhill
777ab28d6a Replaced libsoxr with r8brain free source
Replaced the free SoX resampler with the r8brain resampler source, which
is also free.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-03-04 02:07:38 -08:00
Christopher Snowhill
c8d8e759bc Add autoreleasepool to cache thread
The cache thread should have an autoreleasepool around the release loop,
because it will be freeing Objective C objects periodically.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-26 23:30:18 -08:00
Christopher Snowhill
da4630f4c5 Add a metadata loader cache
Promote the Plugin Controller source file to Objective-C++, and add a
simple data cache that holds on to requests for up to 5 seconds after
their last access, for preventing spammed requests from hitting files
over and over. This is apparently really relevant to the CUESheet reader
and its embedded CUESheet handling, as that tends to reread the same
file over and over as it populates the playlist with tracks. The nested
reader can also lead to repeated reading even on files without CUESheets
embedded.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-26 23:24:32 -08:00
Christopher Snowhill
b3247578ed MAD Decoder: Comment out unused variable
A variable wasn't being used, except in debug builds. Comment out its
use and only skip over the field in the LAME header.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-26 20:52:35 -08:00
Christopher Snowhill
1dffaae990 Tweak libsoxr for Apple Silicon again
This should improve performance slightly again, as there were some ARM
code paths that weren't being enabled for ARM64.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-26 20:51:30 -08:00
Christopher Snowhill
a978dfbf5a MAD Decoder: Fix MP3 decoding crash
There was a stupid bug in the previous commit I made, which caused local
or seekable MP3 files to crash the player on decode. This fixes that, by
checking that a packet has actually been decoded before touching the
packet info structures. Dumb, dumb, dumb error on my part.

Fixes #244

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-26 04:26:12 -08:00
Christopher Snowhill
ca3dec4497 MAD Decoder: Support changing format
Support the weird scenario of format changes mid-stream. Probably
highly unlikely, and likely to break things if it does occur, but
whatever, it might actually happen in some weird file.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-26 01:43:54 -08:00
Christopher Snowhill
53209485c0 MAD Decoder: Correctly prepare buffer after free
The current buffer size argument is used to determine if a buffer should
be allocated on the next run. Just in case something reuses the same
decoder instance.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-26 01:38:17 -08:00
Christopher Snowhill
6b53a87784 Clean up a couple of warning notices on this file
There were several warnings due to the capitalization of the header
paths, and due to unused functions that are only required by the text
CUESheet parser, and we're only using the CUESheet generator, which has
been heavily modified to emit NSString output rather than a file on
disk.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-26 01:11:50 -08:00
Christopher Snowhill
0f10543566 Improve spam formatting string in two ways
For one thing, improve it so that if the tracknumber field is present,
but zero, it doesn't show the number sign in the spam. For the second,
only show the track artist field if it differs from the album artist.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-26 01:10:27 -08:00
Christopher Snowhill
2c0f04bbeb Possibly improve MAD sample conversion speed
No idea if this brings a noticeable improvement, but it probably makes
better sense to only do the division step one time instead of doing it
twice interleaved when processing stereo files, which are the most
common scenario anyway.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-26 01:08:55 -08:00
Christopher Snowhill
51e9648865 Improve libsoxr setup
Replace libsoxr dylib with a static library, and also build the two
architectures separately, to allow for platform-specific optimizations
to be employed for both. This also reduces the size of the CogAudio
framework by a few hundred kilobytes, as we eliminate unused code paths
better this way.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-26 01:07:20 -08:00
Christopher Snowhill
19556cc630 Brought back the MAD plugin from death
Now Cog supports freeformat MP3 once again. The plugin has been extended
to include sample accurate seeking, accurate length probing of files
missing headers, and iTunes gapless info reading using libid3tag.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-24 17:51:10 -08:00
Christopher Snowhill
1da6cf2557 Deduplicate artwork using hashes
Artwork deduplication should be done with hashes, not by full data
comparison. This should be a lot faster loading artwork from files now,
especially if the playlist already contains a lot of unique artwork.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-22 23:10:02 -08:00
Christopher Snowhill
9a2ac6ae5a When starting playback, start shuffle at selection
If starting playback from a given playlist entry, or selection, then
start shuffle mode from that track. Otherwise, start shuffle from the
beginning of the shuffle list.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-21 22:01:01 -08:00
Christopher Snowhill
b6330279ce Start playback on first shuffle item in shuffle
When in shuffle mode, start playback on the first item in the shuffle
list, rather than the selection, or the start of the playlist.

Fixes #241

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-21 21:53:41 -08:00
Christopher Snowhill
b63a076e21 Add more automation commands and properties
Added commands to control playback: play, pause, stop, previous, next.
Also added a spam property to PlaylistEntry, to return the formatted
spam string for the playlist entry, which is currently limited to the
playing item.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-21 21:52:09 -08:00
Christopher Snowhill
9614ec6e98 Add option to quit on natural stop
When the option is enabled, and playback comes to a completion, the
player will quit on its own.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-21 20:55:42 -08:00
Christopher Snowhill
f9040dd1d3 Fixed Mini Window appearing topmost on startup
This stupid setLevel default was something suggested when making a
window a drag target, and I was observing a setLevel for a window
control, not for a window itself. I should not have set that in the
first place.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-21 20:31:35 -08:00
Christopher Snowhill
763f4c8cd5 Shrink the time field on macOS 10.13 and older
Since 10.13 doesn't want to observe the auto sizing attribute of the
field properly, gotta use the tiny font size that the field is already
configured to use.

Should fix #243

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-21 16:51:46 -08:00
Christopher Snowhill
9fd85f6670 Updated VGMStream to r1702-76-g00bdb165
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-21 16:44:18 -08:00
Christopher Snowhill
d70e1da126 Updated libFLAC to version 1.3.4
Updated the FLAC library to what is the official release of 1.3.4,
although I already had all the commits from that version prior to this
update.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-21 16:43:36 -08:00
Christopher Snowhill
90ed02302e Fix FFmpeg handling odd WMA files, at least
This small change brings the decoding more in line with what ffplay
does, and allows, for example, John McLaughlin.wma to play without
interruption from the stream warnings throughout the file.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-20 03:14:30 -08:00
Christopher Snowhill
b995030aec Bring back scripting automation
This fixes #126 and brings back basic automation support. The basic
currentEntry object will return an object that can enumerate the track
metadata or the file URL of the currently playing track. More automation
suggestions are welcome, including playlist manipulation, or playback
control.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-20 01:53:25 -08:00
Christopher Snowhill
81f5adfb5c Fix Info.plist having bare apostrophes
Xcode touched the Info.plist and fixed these, and I changed the file
type association definitions to print the correct thing in the future.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-20 01:51:11 -08:00
Christopher Snowhill
1b48459eaa Track number column should also sort by disc
Apparently, the sort descriptors are going by data members of the array,
not by the column identifiers, or their textual contents.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-18 02:23:15 -08:00
Christopher Snowhill
60a4266840 Fix sorting of playlist
Unfortunately, the track number column will always bug out and pop the
indicator back over to the Album Artist column. No way around it. The
control is just buggy like that.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-18 01:57:19 -08:00
Christopher Snowhill
0902703ee1 Playlist: Fix sorting by the track number column
Should now properly sort by album artist, album, then disc/track number.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-17 17:07:47 -08:00
Christopher Snowhill
5c3050c0d3 Playlist loader store: Adopt more correct method
This is a more correct method of identifying the supported classes to
coalesce into unique pointers through the storage array. I completely
forgot about this method, oops.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-17 03:01:34 -08:00
Christopher Snowhill
2a27435f7e Dictionary merge: Correctly drop empty data tags
This allows for TagLib to handle artwork reading where the file built-in
readers fail, such as the FFmpeg reader, which would require parsing the
stream data for artwork packets, a really wacky convention to have.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-17 03:00:35 -08:00
Christopher Snowhill
007ec3696d SQLite Store: Properly read strings into memory
Strings read from the database were not being stashed in the memory
store, which caused things like blank tags instead of correct metadata.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-17 02:58:57 -08:00
Christopher Snowhill
4f5e4eca36 Fix visualization for variable audio block sizes
IN A.D. 2101, WAR WAS BEGINNING. *boom*

Yeah, this was a dumb bug, I didn't realize that AUAudioUnit would just
arbitrarily ignore my configured block size and request a different one.

The AirPods Pro will just request 480 instead of the 512 I ask for, so
let's instead support variable block sizes, and only take up to the last
4096 samples of the chunk fed to the output device.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-16 21:54:55 -08:00
Christopher Snowhill
5611d08df1 Reduce memory usage of adding tracks
Significantly reduce the memory footprint of adding tracks to the
playlist, by coalescing the NSString and NSData objects in the info
dictionaries as they are being loaded in the background, into a common
data set which will then be discarded when the whole job is completed.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-16 21:38:43 -08:00
Christopher Snowhill
d30746bffa Extend deduplication to loading artwork on open
When adding tracks, deduplicate their artwork when loading to memory.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-16 17:06:13 -08:00
Christopher Snowhill
3de43b55a7 Significantly reduce memory usage all around
Added a string dictionary for deduplication of metadata, and actually
initialize both it and the art dictionary on startup, so they actually
work like they should.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-16 16:57:47 -08:00
Christopher Snowhill
c242d53200 Resume on restart: Only seek into seekable files
This allows streams to be resumed from the beginning when restarting.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-16 13:22:53 -08:00
Christopher Snowhill
7f3bf052ca Update supported file name extensions for art
Art read from external files supports more formats than previously
listed here. Amend the list accordingly.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-16 01:56:34 -08:00
Christopher Snowhill
b8057b7c29 Add support for AVIF album artwork
Import libavif and libaom, specifically built only for decoding, not
encoding.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-16 01:52:51 -08:00
Christopher Snowhill
8c945b53de HTTP Reader: Guess encoding type of stream info
Stream metadata could be in any encoding, not necessarily UTF-8. Handle
this in an appropriate way.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-16 01:51:16 -08:00
Christopher Snowhill
1ac1fe29c7 Implement new spectrum mode, toggled by left click
The new spectrum mode is linear frequency. Both modes also now have a
lower range of 10Hz, where possible.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-15 23:24:58 -08:00
Christopher Snowhill
6d052bc1ac Visualization: Increase temporal resolution
By reducing the window size, we have a more responsive visualization.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-15 23:22:47 -08:00
Christopher Snowhill
0d4ee4c901 VGMStream Input: Remove downmixing, add layout
Downmixing should no longer be necessary, unless someone actually tries
to emit up to 64 channels, while we support only 32 channels, but really
only 18 channels. Also read the channel layout field from the decoder,
so that the speaker layout will propagate from the files to the player.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-15 22:55:34 -08:00
Christopher Snowhill
8372ed4eea Fix equalizer applying presets in the background
The equalizer needs to apply its presets to the new settings variables
every time the preset changes, even when it happens with no dialog open.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-15 22:54:14 -08:00
Christopher Snowhill
4906c38827 Align all use of Accelerate vDSP functions
vDSP functions expect their input and output pointers to be aligned to
an even four values. Correct this by aligning all pointers. The
allocated buffers used for one parameter should already be aligned
somewhat, but align the incremented positions used on some of them so
that the vDSP functions don't misbehave. Also align the volume scaler
input by doing scalar math until the pointer is aligned prior to calling
vDSP_vsmul. Also, change 16-bit and 32-bit scale to use vsdiv instead of
vsmul with a really small number already divided into one.

Fixes the test vectors that were sent in extrapolating incorrectly due
to their final blocks having uneven sample counts, resulting in
unaligned pointers.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-15 22:53:09 -08:00
Christopher Snowhill
627aeda8b1 Set default volume to 75%
This doesn't fix an outstanding issue which will be fixed by the next
commit, but it does fulfill a request.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-15 22:49:26 -08:00
Christopher Snowhill
25077277b3 Add bad sample cleaner for debugging
A bad sample scanner and cleaner will point out in the log whenever a
bad sample, such as infinity, or Not a Number, or even huge values over
±2.0, in case some piece of code, or a decoder, or even a bad file, has
taken over the output.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-15 22:48:47 -08:00
Christopher Snowhill
51e8223078 Linear Predictor: Rearrange things somewhat
The original didn't really handle backwards versus forwards differently,
as far as the predictor coefficients should have been, as they probably
should have been reversed for a different direction window.

This didn't fix my problem, though, but did possibly expose something
else to mess with.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-15 22:41:18 -08:00
Christopher Snowhill
3274bc9fe7 Revert "HTTP Reader: Support more stream info"
This reverts commit 33388918b3.
2022-02-15 15:00:11 -08:00
Christopher Snowhill
96f2a382ee DSD gaplessness, part 3, mildly pointless
In the rare event that we're somehow playing decimated DSD at full
sample rate instead of resampling, only the start needs to be skipped,
and the end needs the input to the decimator padded to flush it, but
nothing needs to be truncated from the end of the output in that case.
Still, mostly pointless, since next to nobody will be outputting 384 kHz
from their Macs, in any case, much less unprocessed DSD.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-15 02:29:06 -08:00
Christopher Snowhill
bec01b675a DSD gaplessness, part 2
We should be extrapolating right over top of the DSD decimator latency,
rather than in front of it. Yeah, that'll do.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-15 02:11:53 -08:00
Christopher Snowhill
4b0f6b381f Fix DSD gaplessness handling
DSD files should be properly gapless now.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-15 02:03:06 -08:00
Christopher Snowhill
570e28403e Redo x86_64 build of libFLAC
It needed to be built separately to enable the intrinsic
optimizations. Oops.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-15 01:11:58 -08:00
Christopher Snowhill
33388918b3 HTTP Reader: Support more stream info
For streams offering a three way split in their ICY metadata blocks,
support album/artist/title using that three way split. Otherwise do the
usual of artist/title, or blank artist if there's no hyphen to split on.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-15 00:57:22 -08:00
Christopher Snowhill
1b1769c5c2 Validate libraries once again
Remove the entitlement for disabling library validation, as this should
not be needed any more.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-15 00:47:31 -08:00
Christopher Snowhill
5e8f066a01 Add include path for libogg
The new libogg directory must be included for <ogg/ogg.h> in one place.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-15 00:40:47 -08:00
Christopher Snowhill
2036a92b23 Remove deleted file
This vorbisfile.h is no longer included in the project tree.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-15 00:40:15 -08:00
Christopher Snowhill
df661dc466 Fix dynamic metadata in some cases
For some reason, this sometimes gets set to nil. Fix to refer to the
current track in that case.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-15 00:34:57 -08:00
Christopher Snowhill
f071d3e90c Build several libraries out of tree now
Building libogg, libvorbis, libvorbisfile, libFLAC, libopus, and
libopusfile out of tree, to utilize their projects' CMake build scripts,
and also enable any platform optimizations that may have been missing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-15 00:26:55 -08:00
Christopher Snowhill
52443066e7 Spectrum Visualizer: Fix frequency range, bands
Reduce the virtual resolution to match the actual resolution, and set
the analyzere frequency to Nyquist of the audio input, as it seems to
behave as if the entire range of the input FFT bands are up to the
specified frequency, rather than half of it. Otherwise, we lose half of
the frequency range provided by the input data.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-14 21:10:57 -08:00
Christopher Snowhill
934589ebdd FFmpeg: Enable AIFF support
The system AIFF reader seems unable to read some really old files, so
enable FFmpeg to do so instead.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-14 21:09:24 -08:00
Christopher Snowhill
efea2e33d8 Equalizer: Correctly handle flatten vs. custom
Flatten EQ button should remember that the preset is set to "Flat", and
drawing on the equalizer or changing sliders should remember that the
preset is on "Custom".

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-14 20:19:03 -08:00
Christopher Snowhill
b8a98e301e Metadata loading: Correctly merge over empty tags
Metadata versus properties merging, correctly merge over empty fields if
they are assigned with empty strings or zeroed numbers, instead of only
merging over completely missing fields.

Fixes emailed bug, CUE Sheet metadata reading, primarily.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-14 20:02:18 -08:00
Christopher Snowhill
67fcd2bb27 NSDictionary+Merge: Support overwriting empty
Support overwriting empty fields of NSNumber or NSString form with
values from the merging dictionary. Correctly overwrite the value from
the first dictionary with values from the second if the first contains
empty strings or zeroed numbers.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-14 19:55:20 -08:00
Christopher Snowhill
a8c9f748c7 FLAC Input: Correctly prioritize text CUESheet tag
Prioritize "cuesheet" Vorbis tag over binary CUESheet tag, as the former
can contain metadata, while the latter cannot.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-14 19:54:08 -08:00
Christopher Snowhill
4a0690b3ab Spectrum Visualizer: Change border dimensions
This should make the border consistently sized.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-14 17:15:38 -08:00
Christopher Snowhill
ec56725824 Equalizer: Disable tabbing, and remove HUD style
This should improve contrast significantly.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-14 17:15:09 -08:00
Christopher Snowhill
0c504d9330 Preferences: Fix alignment of some options
This hopefully handles #232 as best I can, for now.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-14 17:01:10 -08:00
Christopher Snowhill
b9dde0deca Preferences: Fix dead/dupe remove buttons
For some reason, they were marked "navigational", because I accidentally
chose the Info inspector button as the button to dupe to create them in
the first place.

Fixes #237

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-14 16:59:25 -08:00
Christopher Snowhill
f09022693a Preferences: Got rid of appcast selection
There is only one appcast to choose from, and it has been this way for
quite some time now, so simply make it final.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-14 16:58:03 -08:00
Christopher Snowhill
a4ff2477be Equalizer: Various changes
Among the many:
- Spaced out the equalizer settings from the preamp slider
- Propery synchronize the bands' state with the stored settings
- Properly store the setting for Custom mode when drawing on the bands

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-14 16:46:32 -08:00
Christopher Snowhill
4a9e7baf7f Equalizer: Rename window
Oops. I'll push this change to my next release I have planned.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-13 23:54:02 -08:00
Christopher Snowhill
41efc22096 Equalizer: Bring it back to the quality it had
The quality of the equalizer dialog is now up to par with what we had
before, minus all the crashes.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-13 23:37:58 -08:00
Christopher Snowhill
344ceb173d Visualization: Increased fft size, imported code
Boy, I just be outright stealing code now. But it looks nicer now.

Fixes #234

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-13 12:18:58 -08:00
Christopher Snowhill
cad09b8912 CUE Reader: Fix enumerating sheets and tag reading
The reader should have been skipping the properties of CUE sheets when
reading the referenced data for the inner files.

Fixes #235

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-13 12:18:58 -08:00
Christopher Snowhill
7ef583340d Equalizer: Replace dialog with custom job
New custom equalizer dialog, painstakingly hand assembled.
2022-02-13 11:05:32 -08:00
Christopher Snowhill
8033256c4d Visualization: Fix customize toolbar
Spectrum item needs fixed size.

Fixes #230

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-13 02:56:39 -08:00
Christopher Snowhill
f2bebdefa7 Visualization: Clear peaks on stop
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-13 01:42:02 -08:00
Christopher Snowhill
992b716193 Visualization: Greatly improve spectrum design
Improvement includes greatly reducing the CPU usage by not using an
NSImage based painting system.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-13 01:32:26 -08:00
Christopher Snowhill
417687600b Implement visualization support and a spectrum
Borrowing some DFT code from deadbeef, this implements a simple spectrum
visualization into the main toolbar of the app.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-12 23:04:03 -08:00
Christopher Snowhill
1309672adc CUE Sheet Reader: Merge metadata the other way
The file metadata should be merged into the CUE Sheet metadata, as we
want the CUE Sheet to take priority, wherever it happens to have fields
set.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-12 07:57:13 -08:00
Christopher Snowhill
a618073203 Highly Complete: Keep USF RSP HLE disabled for now
There is a missing effect in the relevant tracks from Conker's Bad Fur
Day, an overdrive effect.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-12 07:45:10 -08:00
Christopher Snowhill
6d09b72c1d Dynamic info now pushes to the correct track
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-12 07:29:02 -08:00
Christopher Snowhill
455dc0d5c8 Remove unused formatter class from info inspector
The info inspector xib still referenced the blank zero formatter, left
over from before disc support was added.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-12 07:19:50 -08:00
Christopher Snowhill
a05d4537c1 Various tagging fixes
- Fix Vorbis, Opus, and FLAC tag reading
- Fix Vorbis getting a 0 length if passing through the CUE Sheet reader
- Implement support for FLAC binary CUE Sheets

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-12 07:16:59 -08:00
Christopher Snowhill
1df166b060 Updated lazyusf2, and disabled RSP HLE warnings
The warn logging was preventing working USFs from playing due
to warnings occurring during the playback that didn't otherwise
affect the ability to play the files.
2022-02-12 03:29:43 -08:00
Christopher Snowhill
c39b7ee96a Converter: Smarter, if less portable, endian swap
For big endian sample formats, endianness can be swapped using Clang
specific byte swap functions, which are present in all supported
versions of Xcode.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-12 00:38:08 -08:00
Christopher Snowhill
5f68131437 Converter: One minor change to double to float
Use Accelerate for this, too.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-12 00:03:25 -08:00
Christopher Snowhill
6b148fef11 Channel Mixer: Rewrite upmixing, changed HRIR
Simple upmixing algorithms now use Accelerate framework functions
instead of complex loops, and the HRIR filter now supports forcing
stereo output to any channel output configuration that has at least
front stereo speakers.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-11 23:51:41 -08:00
Christopher Snowhill
5bcedab274 Disallow window tabbing on main window
No point in allowing tabs when we don't support multiple playlists yet.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-11 17:11:04 -08:00
Christopher Snowhill
3711999112 Cog Audio: Allocate maximum needed audio memory
The chunk could be any format, up to floating point double samples, and
up to 18 channels.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-11 13:50:26 -08:00
Christopher Snowhill
7f8c19799d Fix a very serious error resampling short files
Files that are so short that they need both pre- and post-extrapolation
at the same time.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-11 07:10:31 -08:00
Christopher Snowhill
0b33fe6dea Don't count output buffering for queue hold
This would count the output duration for every file buffered, rather
than only once.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-11 06:50:58 -08:00
Christopher Snowhill
d5aecaf6a2 Fix outstanding crashes and issues with CUE reader
CUE reader was crashing due to nil metadata pointers, which the new
inplace initializer I was using didn't like. Change it to use a mutable
regular dictionary, and only add items if they're not nil.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-11 06:49:41 -08:00
Christopher Snowhill
d7becdf01a Add a nil pointer check for metadata read
No idea if this is needed or not.
2022-02-11 06:00:36 -08:00
Christopher Snowhill
69c4cb3c16 Minor change to remove unnecessary mutable objects
These are no longer being manipulated, so remove their mutable state.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-11 05:59:44 -08:00
Christopher Snowhill
e695e33537 SID Input: Bring back file hints, better this time
Now file hint stashes the whole file in memory, so that any other
threads reading the file at the same time will just grab the same memory
block and read it, rather than opening the file repeatedly.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-11 04:43:20 -08:00
Christopher Snowhill
425306129f SID Input: Clean up memory leaks
Two were potential memory leaks on file errors, one was a guaranteed
leak when reading metadata.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-11 04:19:27 -08:00
Christopher Snowhill
b40b8521dd SID Input: Open the files for decoding regardless
No more file handle caching, this was probably a source of crashes.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-11 04:18:39 -08:00
Christopher Snowhill
09bf1c7ad9 libsidplayfp: Sync with upstream again
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-11 04:06:16 -08:00
Christopher Snowhill
4f5e5a9e4e SID Input: Synchronize cross file access
The same file may be accessed from other threads, thanks to this cache
thing. Synchronize access so that only one thread is reading the file at
a time.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-11 03:56:50 -08:00
Christopher Snowhill
be6fda4663 SID Input: Don't close hinted source files
The SID decoder uses a hint cache so that when the library requests the
current file open, it will return the exact file already opened, rather
than opening it again. Unfortunately, I was closing the file regardless,
and sometimes, libsidplayfp will reopen the file multiple times, from
other threads, even.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-11 03:55:26 -08:00
Christopher Snowhill
e7df4e529d libsidplayfp: Updated to newer version
This update is from my personal fork, and includes synchronization
around two places in ReSIDfp that use static global tables as caches.
Without the synchronization, there were errors in playback and even
crashes.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-11 03:48:10 -08:00
Christopher Snowhill
38efa7c8c5 libsidplayfp: Reorganize project file order
Sorted the file tree a bit, for more easily locating files while working
on the code.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-11 03:46:51 -08:00
Christopher Snowhill
bf88c57454 Minor artwork caching changes
Art ID should be set on new files when they are stored into the
database, and the album art property should be affected by assigning to
the artId property, since it affects the caching identifier.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-10 22:45:26 -08:00
Christopher Snowhill
740fdfa883 Attempt to wrangle memory usage from artwork
Now cache around NSData objects of individual pieces of album art,
unique by their byte contents. And the artwork image cacher will also
use the art ID keys from the database as the cache keys for NSImages,
so they'll not only be only read once per unique image, but also tracks
can have unique artwork per track, if the files so feature it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-10 22:37:37 -08:00
Christopher Snowhill
2e52066293 Skip to next on trash, else stop playback
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-10 21:48:30 -08:00
Christopher Snowhill
2e1460f72d Only trash regular files
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-10 21:48:08 -08:00
Christopher Snowhill
5411a60ea1 Added option to remove tracks to the trash
Fixes #23

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-10 21:35:13 -08:00
Christopher Snowhill
68c3f3b1d8 Highly Complete: Disable USF HLE
The HLE is incomplete, and sometimes buggy. Disable it for now.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-10 20:57:44 -08:00
Christopher Snowhill
7d0ff8e525 Update Info.plist with new file types
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-10 15:40:12 -08:00
Christopher Snowhill
39dcb88728 FFmpeg input: Support reading metadata
Where TagLib is not being employed, use FFmpeg to read tags where
possible. This allows reading tags from files like IFF. It reads it
through properties, otherwise allowing tag readers to function like
usual.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-10 15:29:13 -08:00
Christopher Snowhill
5ff1f95481 Add decoder open error indicator
When decoder is redirected to the internal silence decoder, show an icon
on the playlist indicating a playback error.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-10 02:15:48 -08:00
Christopher Snowhill
8f1143818b Replace playlist status icons with SF Symbols
On Big Sur and up only, of course.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-10 01:51:40 -08:00
Christopher Snowhill
a4387dc6d1 Playlist now supports dragging tracks out of app
Playlist now supports dragging copies of URL references to other apps,
including Finder, and possibly other audio players. The chosen drag
operation is to copy files.

Fixes #75

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-10 01:32:09 -08:00
Christopher Snowhill
421eb8ed82 Replace playback buttons with SF Symbols on 11.0+
On macOS Big Sur and newer, replace the playback buttons with system
symbols.

Should fix #96

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-10 01:18:34 -08:00
Christopher Snowhill
5330295a97 Fix array bounds issues with album shuffle builder
The shuffle list builder was encountering errors when some album tags or
empty album tags led to empty lists.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-10 01:14:42 -08:00
Christopher Snowhill
f203911bb1 FFmpeg Input: Support various DSD formats and IFF
Implement support for DFF, WSD, and IFF formats, and all DSD formats
carried within, using our own DSD decimation method instead of relying
on FFmpeg to do it.

Fixes #165

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-10 00:32:24 -08:00
Christopher Snowhill
f3356a821a Touched by Xcode
Xcode loves to tweak coordinates by fractional values just opening the
darn thing in the resource editor.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-10 00:27:11 -08:00
Christopher Snowhill
086367f388 Add two new toolbar buttons
Added buttons to remove duplicates and remove dead items, in case anyone
finds themselves needing these options often enough to want to put them
in their toolbar instead of using the menu.

Fixes #225

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-09 23:12:50 -08:00
Christopher Snowhill
60a7052868 Fix volume control tooltip appearance on the left
Increasing the threshold for the width of the tooltip to the right of
its intended location to a more generous value, makes it appear on the
left side sooner rather than later, but should fix positioning issues.

Fixes #226

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-09 22:51:39 -08:00
Christopher Snowhill
085891aff1 FFmpeg Input: Retry on decode error
When feeding packet to decoder, attempt to retry another packet when it
reports invalid data.

Fixes #97

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-09 22:37:39 -08:00
Christopher Snowhill
4cdf919b45 Opus Input: Now reads ReplayGain tags
Instead of rendering the ReplayGain values into the stream on decode, as
it did before. This allows exposing the values to the properties dialog.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-09 21:27:33 -08:00
Christopher Snowhill
df63726128 Track properties take priority over metadata read from tag readers
This allows inputs to override things with self-read tags and such, such
as ReplayGain tags.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-09 21:26:17 -08:00
Christopher Snowhill
64c4aa2e25 Handle deleting the current track gracefully
Now it should flow playback correctly to the next remaining track after
the block of deleted tracks. And if the user deletes the next queued
track, it will still be queued to flow past the deleted block. If the
user undoes their deletes and restores the tracks, playback will resume
after the originally deleted track.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-09 21:04:17 -08:00
Christopher Snowhill
c3cd4c34f4 MIDI Plugin: Rearrange project source files
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-09 18:43:01 -08:00
Christopher Snowhill
a212c85252 MIDI Plugin: Fix stupid typo
Damn, how did I miss this one?

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-09 18:38:12 -08:00
Christopher Snowhill
b03702e164 MIDI Plugin: Fix BASSMIDI driver SysEx handling
These events were split up in handling after this driver fell out of
use. It needed updating with the latest split handling design.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-09 18:36:37 -08:00
Christopher Snowhill
808b14a358 MIDI Plugin: Vital changes for stability
Among the changes, range checking on lots of things, and especially,
the pre-render-loop backlog handler, which rendered samples left over
from the previous call, would possibly over-render by way too much, due
to a stupid backwards subtraction I managed to type into there. This is
totally fixed now.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-09 18:29:34 -08:00
Christopher Snowhill
b1a98139cb Cog Audio: Fix generic upmixer mode
This resulted in horrible things, the generic N to N upmixer was leaving
unmapped channels as uninitialized memory. This fixes horrible things
happening for people with interfaces with more channels than the source
file, frequently when the source file is stereo, or if the file is mono
and a center channel is present.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-09 15:16:19 -08:00
Christopher Snowhill
e2e83ea760 FFmpeg/FLAC/Opus/Vorbis Inputs: Fix metadata
The dynamic metadata functions should only activate for unseekable
streams, not seekable streams, and not local files.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-09 15:04:49 -08:00
Christopher Snowhill
0012d1b17e Implement dynamic metadata reading for streams
Supported by FFmpeg, FLAC, Ogg Vorbis, and Opus.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-09 13:44:50 -08:00
Christopher Snowhill
cdf27e4786 CogDecoderMulti: Reset file even if not seekable
HTTP Reader now supports limited seeking backwards even in streams, so
seek back to file start for repeated file tests, since there are at
least a few inputs that all claim to support things like Ogg containers.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-09 13:44:04 -08:00
Christopher Snowhill
d77a5472f3 Only seek on restart if file is seekable
Do not restart from the last position if file isn't seekable.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-09 13:42:47 -08:00
Christopher Snowhill
69506cd1d7 HTTP Reader: Replaced implementation with libCURL
New implementation largely based on the vfs_curl module from DeaDBeeF.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-09 13:41:01 -08:00
Christopher Snowhill
e13f83609e FFmpeg Input: Implement stream metadata reading
Now reads Icy interval metadata and timed ID3v2 tags.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-08 21:34:28 -08:00
Christopher Snowhill
7cea254f4c Implement framework for dynamic metadata updates
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-08 21:21:53 -08:00
Christopher Snowhill
b927f4c02b Replace more NSDictionary use with literals
Use literals to initialize fixed NSDictionary objects in various places.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-08 19:56:04 -08:00
Christopher Snowhill
838b31a6e8 MIDI: Replaced FluidSynth with BASSMIDI again
FluidSynth is just too unstable, and also just bad in general.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-08 18:29:03 -08:00
Christopher Snowhill
52ddc26bb9 OpenMPT Legacy: Remove modifications from library
There were some leftover modifications to the 0.5.x tree I was using,
which were supposed to be speed optimizations, but they're probably
pointless anyway. The NEON optimizations were especially pointless,
since this plugin version isn't used on any macOS version that runs on
Apple Silicon.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-08 00:15:49 -08:00
Christopher Snowhill
0763b28f38 HRIR Filter: Replace deprecated Intel-only code
_mm_malloc and _mm_free are apparently based on intrinsic functions,
and only exist on Intel or older macOS targets. So removing them in
favor of posix_memalign.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-08 00:13:41 -08:00
Christopher Snowhill
f4f4f80f64 Restart playback on device or output format change
Now the output is restarted on the current file at the current position
if the output format has changed. This should resolve the issue finally.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-07 22:44:56 -08:00
Christopher Snowhill
728c44242c Do not reset output sample rate automatically
This was buggy as hell, and resulted in errors. Now the user should
restart playback if they change output device formats.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-07 22:02:17 -08:00
Christopher Snowhill
4fd24838fa FFmpeg Input: Fix format changes
Format changes should only occur on whole packet intervals.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-07 19:37:06 -08:00
Christopher Snowhill
90ce0e5ae4 Updated VGMStream to r1702-55-g39074f95
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-07 19:31:32 -08:00
Christopher Snowhill
477feaab1d Now properly supports sample format changing
Sample format can now change dynamically at play time, and the player
will resample it as necessary, extrapolating edges between changes to
reduce the potential for gaps.

Currently supported formats for this:

- FLAC
- Ogg Vorbis
- Any format supported by FFmpeg, such as MP3 or AAC

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-07 19:18:45 -08:00
Christopher Snowhill
0b8a659bc2 TagLib: Implement support for APE tags on TTA
TrueAudio will now read APE tags, and if I should start writing tags
some day, will prefer creating APE tags if no tags exist.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-07 15:33:50 -08:00
Christopher Snowhill
91da112e35 Cog Audio: Fix potential hang on stop
The ChunkList wasn't clearing the remover entered flag when the chain
was empty. Now it does, so it will shut down correctly.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-07 15:31:57 -08:00
Christopher Snowhill
418d03ae23 Updated VGMStream to r1702-53-g00441228
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-07 04:30:41 -08:00
Christopher Snowhill
08da31f96c Cog Audio: Fix generic downmix to stereo
Code ordering was wrong, it was writing the output samples repeatedly
for each input speaker, now it will only write them once.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-07 04:17:53 -08:00
Christopher Snowhill
acb1dd75d3 Cog Audio: Fix memory leaks with new buffering
By applying copious amounts of autorelease pools, memory is freed in a
timely manner. Prior to this, buffer objects were freed, but not being
released, and thus accumulating in memory indefinitely, as the original
threads and functions had autorelease pools that scoped the entire
thread, rather than individual function blocks that utilized the new
buffering system. This fixes memory growth caused by playback.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-07 04:06:36 -08:00
Christopher Snowhill
6120fce40a Metadata: Fix length field on track reloading
This fixes the dynamic length field not updating correctly after a track
info reload, which breaks the seekbar when reloading the current track.

Fixes #227

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-07 03:03:39 -08:00
Christopher Snowhill
b2177fccbc Core Audio input: Fix channel config, and a leak
Channel config should not contain duplicate channels, or unsupported
channels. Also fix a memory leak from not freeing the AudioChannelLayout
structure allocated previously.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-07 02:47:32 -08:00
Christopher Snowhill
22d8b8c132 Implement channel config fields for inputs
This implements channel masks for inputs where applicable, namely the
CoreAudio decoder, FFmpeg, FLAC, and WavPack. All others will still use
guessing from the channel number.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-07 02:06:51 -08:00
Christopher Snowhill
95fb65527f Playlist Entry / SQLite: Add channel config field
Add channel config field to PlaylistEntry and the SQLite backing store.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-07 01:11:30 -08:00
Christopher Snowhill
1ef8df675f Cog Audio: Implement support for channel config
This implements the basic output and mixing support for channel config
bits, optionally set by the input plugin.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-07 01:10:05 -08:00
Christopher Snowhill
b0b1446aa7 HRIR Filter: Corrected scale math, fixing volume
The volume should have been twice what it was, because I got this scale
wrong. The correct scale for Accelerate inverse FFT is 1/4 per sample,
not 1/8 like I accidentally misread while rewriting a convolver for the
umpteenth time from scratch.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-06 21:53:42 -08:00
Christopher Snowhill
7bf4c4445d Remove old, now unused code 2022-02-06 21:50:23 -08:00
Christopher Snowhill
85c7073649 Reformat my own source code with clang-format
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-06 21:49:27 -08:00
Christopher Snowhill
361f61618a libFLAC: One more time
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-06 03:21:47 -08:00
Christopher Snowhill
b73f1f280e libFLAC: Fix so Intel compiles
Didn't do those pragmas correctly

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-06 03:14:14 -08:00
Christopher Snowhill
62edb39761 Cog Audio: Major rewrite of audio buffering
Rewrite attempt number two. Now using array lists of audio chunks, with
each chunk having its format and optionally losslessness stashed along
with it. This replaces the old virtual ring buffer method. As a result
of this, the HRIR toggle now works instantaneously.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-06 03:08:34 -08:00
Christopher Snowhill
11ecb1cd8b libFLAC: Improve decode speed on Haswell
Import a feature change that improves decoding speed on Haswell or newer
Intel processors. No effect on Apple Silicon, which doesn't support the
feature under Rosetta 2, and the ARM64 build doesn't need the changes
anyway, as the code already did the right thing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-06 02:59:26 -08:00
Christopher Snowhill
e5f668ce71 libFLAC: Modified unused VC project files
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-06 02:59:25 -08:00
Christopher Snowhill
b85fef5c16 MIDI Input: Fix seeking code
This fixes a possible crash with seeking operations, especially with
Audio Unit plugins. Fix implemented in foo_midi and imported here.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-05 05:01:31 -08:00
Christopher Snowhill
0131f7c925 Revert "Core Audio output: Rewrote major portions"
This reverts commit 637ea4efe1.
2022-02-05 04:14:03 -08:00
Christopher Snowhill
4cdca2f5f8 Converter: Fix DSD gaplessness
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-05 04:03:40 -08:00
Christopher Snowhill
637ea4efe1 Core Audio output: Rewrote major portions
After all this rewriting, down or upmixing the audio is now handled with
the lowest latency possible, meaning that toggling the HRIR option now
takes effect immediately.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-05 03:45:02 -08:00
Christopher Snowhill
e0e7274339 HTTP Reader: Fix opening really tiny files
Tiny files complete fetching within the scope of the open function, so
the URL session task would have completed already. Now the function will
accept the data, and allow reading it.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-04 22:03:22 -08:00
Christopher Snowhill
3069a81d85 HDCD Decoder: Adjust gain stepping algorithm
This is a fixed point implementation identical to Microsoft's original
algorithm. Or at least I assume it's Microsoft's. It was actually
adapted from hdcd_decode.exe, which was adapted from somewhere else.
It's entirely in fixed point math now, so it's fairly deterministic.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-04 21:52:20 -08:00
Christopher Snowhill
6d9f1be7ea Playlist Controller: Stop when deleting current
When deleting the currently playing track, stop playback, because the
player engine doesn't like dealing with the current playing track not
actually having a playlist reference to go with it. Better stop playback
instead, as a safety check.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-04 19:54:43 -08:00
Christopher Snowhill
39cc33cac4 Converter: Remove no longer necessary includes
These were only needed when I wasn't using Accelerate framework.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-04 19:53:17 -08:00
Christopher Snowhill
ac0058ad1a Preferences: Fix MIDI synthesizer setting
This fixes the ability to configure the MIDI synthesizer properly, after
commit 7e5107d431 was applied.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-03 14:26:51 -08:00
Christopher Snowhill
bf6627aa73 MIDI input: Fix general pacing issues with AU
The timing of block based mode was kind of off. Now it should be just
fine. Thanks to testing on Windows in foo_midi.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-03 13:50:25 -08:00
Christopher Snowhill
e820e2bbd6 Update libvgm again
No appreciable changes, as I don't implement tempo control. (yet?)

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-02 18:03:18 -08:00
Christopher Snowhill
b5eb31dabf Updated libvgm
But nothing I updated affects playback currently.
2022-02-02 17:22:57 -08:00
Christopher Snowhill
71d7697788 Updated patrons header file 2022-02-02 17:22:24 -08:00
Christopher Snowhill
0b243158a0 Cue Sheet input: Fix files with no length
This bug prevented zero length or unknown length files, such as FLAC
files with no sample count in the header, or audio streams, from playing
properly, and clipped their output to the 0 samples indicated by the
field. Now it will simply allow wrapped files to decode until they stop
producing output.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-01 23:54:54 -08:00
Christopher Snowhill
d6760c823a HRIR Filter: Change resampler to use soxr oneshot
This should use the oneshot method, which takes care of flushing for us.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-01 22:54:27 -08:00
Christopher Snowhill
002be384ff Cog Audio: Terminate queueing when stopping
The end of input queueing, which can go nuts when there are a lot of
short files, should be terminated when the user asks the player to stop.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-01 22:48:25 -08:00
Christopher Snowhill
074e4115dd sox resampler: Perform post file flush
Flush the resampler when the source file terminates, so that it outputs
delayed samples properly. This fixes gapless decoding of resampled
files.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-01 22:47:11 -08:00
Christopher Snowhill
587be93f21 Cog Audio: Fix runpath search path for libsoxr
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-01 19:44:48 -08:00
Christopher Snowhill
0e6350116b libsoxr: Fix import path
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-01 19:28:28 -08:00
Christopher Snowhill
b40d5eecc5 GME: Play SPC and SFM files at 32 kHz
And let the player itself resample them, as necessary.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-01 19:04:06 -08:00
Christopher Snowhill
d4990de7f3 Adopt the sox resampler instead of RetroArch
Removing RetroArch code from my project.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-01 18:55:39 -08:00
Christopher Snowhill
78e960a9e4 Revert "Ring Buffer: Replace virtual buffers"
This reverts commit 476c88973b.
2022-02-01 18:45:12 -08:00
Christopher Snowhill
641f6390c5 HRIR Filter: Quality of life improvements
The memory allocation is now nicer, and only allocates what is needed.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-01 15:28:24 -08:00
Christopher Snowhill
61a30c959c Bundled resources: Use NSBundle interface
These methods should use NSBundle, rather than CF* C functions

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-01 14:40:02 -08:00
Christopher Snowhill
f3ddd69f63 libOpenMPT: Updated to version 0.6.1
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-30 15:19:56 -08:00
Christopher Snowhill
ebb9c5b4f1 libOpenMPT Legacy: Updated to version 0.5.16
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-30 15:19:36 -08:00
Christopher Snowhill
9e42182928 Update Code of Conduct, remove placeholder
Oops, I should have scanned it for placeholders before uploading.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-30 14:38:49 -08:00
Christopher Snowhill
54ccad7c5d Volume Slider: Fix appearance of tooltip
Tooltip should appear on the left side when the volume bar is close to
the right side of the screen.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-30 14:05:12 -08:00
Christopher Snowhill
fe67d1a6ea Adopt Contributor Covenant as code of conduct
From now on, all contributions, and all issues and pull requests posted,
must adhere to this document. I would like people to remain civil on my
project, if they possibly can. If they cannot, they will be ejected.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-30 13:47:30 -08:00
Christopher Snowhill
808710b881 Volume Control: Fix linear 100% range control
Range is now linear on 100%, like it should be.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-30 00:18:07 -08:00
Christopher Snowhill
476c88973b Ring Buffer: Replace virtual buffers
Replace individual virtual buffers with large _mm_malloc blocks at a
time, then dole out chunks of those buffers as the nodes need them.
Should reduce memory contention a little bit.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-29 21:32:59 -08:00
Christopher Snowhill
9e5a70c9ae Cog Audio: Dealt with a major retain cycle leak
This seals up a major memory leak of the playback state whenever a chain
is released on stop or on manual track change. CogAudioMulti was
retaining the input node due to its listeners, and InputNode was not
releasing the listeners when asked to stop running. This is fixed now.

Fixes #221

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-29 21:31:19 -08:00
Christopher Snowhill
77a079bd53 Mini Window: Fix saving and restoring position
Fixes #212

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-29 18:00:34 -08:00
Christopher Snowhill
1c3419580f Templates: Touched by Xcode
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-29 17:59:59 -08:00
Christopher Snowhill
d2a8ccb098 Toolbar: Replace Randomize Playlist button again
Now with a slightly more appropriate icon for non-retina displays. I
still want to consider what to do with this, since it still looks a bit
blurry on 1x displays.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-29 17:45:41 -08:00
Christopher Snowhill
66f27b4e12 Spotlight Panel: Align all controls properly
Fixes #224

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-29 17:28:53 -08:00
Christopher Snowhill
abffadef4e Equalizer: Prevent circular application of presets
This prevents the apply presets function from resaving the preset number
and retriggering itself repeatedly, which would cause a crash.

Fixes #223

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-29 17:27:10 -08:00
Christopher Snowhill
e695e36599 Equalizer: Store custom presets on change
Store custom presets on value changes, on half second intervals, as the
listener observes the user changing the settings.

Fixes #222

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-29 17:21:43 -08:00
Christopher Snowhill
5184c8e48b Sparkle: Disable automatic updates when debugging
Disable automatic update checking on startup for debug builds. Prevents
a crash from occurring when it attempts to retrieve the version number.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-29 17:01:51 -08:00
Christopher Snowhill
7e5107d431 User Settings: Obey standards
Replace "midi.plugin" with "midiPlugin", as per the value naming
conventions that Apple set out. Migrate the old value if found.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-29 16:38:53 -08:00
Christopher Snowhill
85fd3836c0 Debug logging: Added logging of playback and tags
Added a logging method that indicates starting playback of a given URL,
and added a debug build only logging of every metadata load event.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-29 16:34:43 -08:00
Christopher Snowhill
326e9d5970 GME: Fix music playback with no fade from crashing
Only crashed with division by zero error on Intel, not on Apple Silicon.
Funny that. Sending the fix upstream, too.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-29 16:26:28 -08:00
Christopher Snowhill
c5f9ffe87c
Merge pull request #220 from losnoco/nevack/linear-scale-for-volume-slider
Scale VolumeSlider linearly if volume is limited.
2022-01-29 15:40:34 -08:00
Dzmitry Neviadomski
050a3d3112 Scale VolumeSlider linearly if volume is limited.
Fixes #198
2022-01-29 05:57:19 +03:00
Christopher Snowhill
7be0ade7ce Ogg Vorbis and Opus: Fix 7.1ch file remapping
File channel remapping was incorrectly only working for 1-7 channel
files, not 8 channel files. Fixed that.

PLEASE NOTE: This will be my last commit and build for over a week, I
promised myself I would stop, and this is the last straw. These are the
last two, I promise. No more bug fixes this week, until at least the 7th
of February. Please, I'm begging you.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-27 23:04:19 -08:00
Christopher Snowhill
d239b58ab1 HRIR Filter: Fix 7.0 downmix and WAV files
7.0 downmix was passing parameters to cblas_scopy backwards, and WAV
files report "host" endian, not "native".

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-27 23:02:04 -08:00
Christopher Snowhill
38c7fdafd0 Delete Gitlab CI config
We're not using Gitlab's CI anyway, and they don't offer free Mac
build bots at this time, either. It just keeps spamming me with build
failure notices every time I push commits to that mirror.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-27 22:23:19 -08:00
Christopher Snowhill
241b7b4b34 FFmpeg patches: Updated iTunes gapless patch
The patch is now updated to exactly what I sent to the ffmpeg-devel
mailing list for hopeful inclusion in the latest release of FFmpeg.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-27 19:31:15 -08:00
Christopher Snowhill
f807cd8169 FFmpeg Input: Just-in-case change to file reader
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-27 14:49:33 -08:00
Christopher Snowhill
9caf704630 Equalizer: Better handle interpolating presets
The old quadra method was broken, too. Now it uses a simple linear
difference sliding scale for the extra points, which seems to work much
better for the 20 kHz band. And the 16 kHz band doesn't get predicted to
heck any more, either.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-27 14:30:14 -08:00
Christopher Snowhill
7c012b2714 MainMenu template: Touched by Xcode
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-27 14:29:08 -08:00
Christopher Snowhill
72c18ca960 Toolbar: Try second edition Randomize button
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-27 14:19:58 -08:00
Christopher Snowhill
efc044ae33 Toolbar / Menu adjustments for equalizer, etc.
Added a keyboard shortcut for the equalizer menu item, added a user
contributed button for an equalizer toolbar button, and replaced the
randomize playlist button with something different from the same user.

I had to redo the randomize button, because template PDFs don't support
white cutout shapes, but instead need to be formatted as hollow spaces
in the paths. Naturally, I couldn't figure out how to do this with
Inkscape the right way, so I rendered the original to a 1024x1024
bitmap, then imported that into a new document and traced it. Meh. I
need a better icon anyway, but this looks okay on the toolbar for now.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-27 01:31:50 -08:00
Christopher Snowhill
b0fca5127f SQLite Store: Fix updating track entries
Track entries are updated when files are added and their metadata is
later loaded. The refresh cycle was failing, because dbIndex was unset
in the new tracks, for some reason. Now it will set this when updating
the track item, assuming it read from the database in the first place.

This fixes metadata being loaded properly on adding tracks to the
playlist, as well as reloading track data manually.

Fixes #218, hopefully.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-27 00:11:14 -08:00
Christopher Snowhill
2e41e7c525 FFmpeg Input: Enable networking and HLS support...
... also disable use of AudioToolbox codecs, and use only bundled codecs
and libfdk-aac for AAC input. This is required for HLS at least, as
Apple's system codecs didn't really like the network streams that were
provided by HLS streaming stations.

Also reshuffle the input priorities between Core Audio input and FFmpeg
input, so that they were the way they were before I messed with things a
while back. This puts FFmpeg back at the top, using bundled codecs where
supported.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-27 00:11:14 -08:00
Christopher Snowhill
7f114bce0e FFmpeg libraries: Enable networking and HLS
Also disable AudioToolbox codecs, as they don't really like network
streaming so much. Use bundled codecs instead.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-27 00:11:14 -08:00
Christopher Snowhill
547de6cf08 M3U Playlist container input: Disable for HLS
The built-in M3U container parser should not be used for HLS playlists,
so they should end up in the playlist as-is, so that inputs can parse
them in real time.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-27 00:11:14 -08:00
Christopher Snowhill
2541633c17 Playlist Entry: Display full URL for remotes
For Playlist Entries that are not File URLs, return the full absolute
URL for path queries, so the playlist path column will show the full
URL instead of a useless reduced path string.

Fixes #214.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-27 00:11:14 -08:00
Christopher Snowhill
cc2b27d43f Core Audio output: Potential shutdown fix
The thread wait on shutdown had the potential to lock up waiting for the
thread to shut down. Now it should at least spam the semaphores, so that
the thread should progress to shutdown a lot quicker.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-27 00:09:40 -08:00
Christopher Snowhill
3c35cf1037 MIDI Input: Fall back to system DLS Synth
If there's no configured SoundFont bank, or if the selected bank has
gone missing, and the user has configured the player to use the
FluidSynth driver, fall back to the system DLS Synthesizer, which has
its own Roland bank to fall back on if unconfigured.

Also, whether falling back, or already on an AU synthesizer, don't fail
if there's no bank configured or found. DLS doesn't explicitly require a
bank, and most other synthesizers of interest would not require a bank
either.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-27 00:09:40 -08:00
Christopher Snowhill
fce851bfff Updated VGMStream to r1702-16-g2db8e56e
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-27 00:09:40 -08:00
Christopher Snowhill
b53567edc5 Fix VGMStream so it handles EOF properly
The file prober in FFmpeg expects that when the read function reaches
end of file, it returns AVERROR_EOF, not zero. Otherwise, it will loop
endlessly until the process is terminated.

Fixes #217.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-27 00:09:40 -08:00
Christopher Snowhill
9edf4ddc49 Update credits: New patron
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-26 17:19:50 -08:00
Christopher Snowhill
bbce6880d7 Core Audio output: Add a quick safety fix
Add a safety fix for pausing and shutting down, so that we don't call
into AUAudioUnit's stopHardware function unless the stream has already
been started by the output.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-26 15:42:28 -08:00
Christopher Snowhill
ee7b7dad5f VGMStream: Add a bodge for PSF files
For some incredibly dumb reason, PSF files get into FFmpeg 5.0, then
just sit there and lock up, reading them forever and ever, doing nothing
useful. Add a bodge to detect PSF files by signature and ignore them in
the VGMStream container parser, and all other parts of VGMStream in Cog.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-26 15:40:44 -08:00
Christopher Snowhill
600c447531 Virtual Surround: Further cleanup
Quick changes I missed. Oops.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-26 01:03:12 -08:00
Christopher Snowhill
7b5925d7d2 Virtual Surround: General cleanup
This should fix some coding issues, and also fix some potential memory
leaks in the file verifier, assuming it didn't already release the
files it was pulling the stats from.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-26 01:00:28 -08:00
Christopher Snowhill
e6b056d7ae Updated README.md
Added a link to a downloadable set of HRIR presets, borrowed from the
HeSuVi project, which is on SourceForge, but inside of an executable,
therefore possibly a pain to extract.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-26 00:33:03 -08:00
Christopher Snowhill
97b8ad0949 Update README regarding HRIR convolver
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-25 23:27:10 -08:00
Christopher Snowhill
778ac0699e Virtual Surround: Cleanup properly
The filter wasn't properly freeing its FFT setup state, and also was
unnecessarily null checking the pointers before passing them to the
aligned free function, which already does null checking.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-25 22:06:53 -08:00
Christopher Snowhill
c7c3c82c18 Core Audio output: Change end of file timing
Reduce the timing at which an end of file notification is sent to the
main thread from 16384 bytes to 8192 bytes. This may help with playback
of a lot of really small files, and skipping tracks.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-25 21:55:08 -08:00
Christopher Snowhill
708c7dc721 Headphone Virtualization: Implement customization
Implement the ability to configure and select an HRIR preset to use with
the HRIR filter, or remove the preset. It will validate the file's
usefulness before setting it for the player to use.

Also, fixed back center channel filtering for 7.0 format audio.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-01-25 21:30:33 -08:00
Christopher Snowhill
bb029757fd
Headphone Virtualization: Fix an oops
The previous commit was not sound. Now it is.
2022-01-25 17:45:32 -08:00
Christopher Snowhill
e53144acfa Headphone Virtualization: Implement 7ch impulses
This is needed for HeSuVi no-echo impulses, which are only one channel
per input channel, and mapping uses symmetrical mirroring of the input
set to create the surround effect, since there's no side-to-side delay
in these impulses.
2022-01-25 17:23:34 -08:00
Christopher Snowhill
e7b78085ca New feature: Implemented headphone virtualization
This new virtualizer uses the Accelerate framework to process samples.
I've bundled a HeSuVi impulse for now, and will add an option to select
an impulse in the future. It will validate the selection before sending
it to the actual filter, which outright fails if it receives invalid
input. Impulses will be supported in any arbitrary format that Cog
supports, but let's not go too hog wild, it requires HeSuVi 14 channel
presets.
2022-01-25 16:50:42 -08:00
Christopher Snowhill
4567df54b7 Playback Buttons: Correctly assign tooltips on button changes 2022-01-24 22:11:54 -08:00
Christopher Snowhill
4bc3a2a1f3 Playback Buttons: Made stop button optional, hidden by default 2022-01-24 22:05:00 -08:00
Christopher Snowhill
fa67b79b22 Mini Window: Window now acts as a drop target for files, sending them to the end of the playlist 2022-01-24 21:30:36 -08:00
Christopher Snowhill
640a514d40 Toolbar Controls: Changed some toolbar items and their visibility priorities 2022-01-24 21:29:52 -08:00
Christopher Snowhill
e471945a08 Equalizer: Implemented new presets contributed by Oleg-Chashko 2022-01-24 20:01:22 -08:00
Christopher Snowhill
ec7009f3fc Equalizer: Instances of GraphicEQ AU are now relinquished to the main thread for destruction instead of being destroyed by the Core Audio Output shutdown 2022-01-24 19:49:43 -08:00
Christopher Snowhill
d8b16e44c7 SQLite Store / Drag and Drop: Now correctly store changes made by dragging playlist entries around to the database 2022-01-24 06:07:13 -08:00
Christopher Snowhill
fee7fcdb21 FFmpeg: Handle preroll skip manually 2022-01-24 06:07:09 -08:00
Christopher Snowhill
d771a58e69 FFmpeg: Update to version 5.0, and add another patch for iTunes MP3 gapless info 2022-01-24 04:41:27 -08:00
Christopher Snowhill
9e42df41bd Equalizer: Adjust dialog somewhat again, changing the splitter style, and cleaning up the effects of changing the bands manually, and bringing back the Flatten button 2022-01-23 22:34:41 -08:00
Christopher Snowhill
f35c632f00 Equalizer: Fix the app switching presets in the background versus the open equalizer dialog
This should fix #198
2022-01-23 20:40:48 -08:00
Christopher Snowhill
fe4e17a4a0 Equalizer: Remove equalizer from window, thus saving settings, on stop or shutdown
Fixes #204
2022-01-23 20:25:42 -08:00
Christopher Snowhill
51caf3f4e3 Cog Audio: Don't overfill the output buffer when asked to reset the buffers 2022-01-23 19:53:50 -08:00
Christopher Snowhill
d364d48944 Cog Audio: Change for recursive lock, fixing a deadlock on buffer resets 2022-01-23 19:50:01 -08:00
Christopher Snowhill
494ad84ea7 Cog Audio: Made ring buffer locking mechanism more secure and/or smarter 2022-01-23 19:36:33 -08:00
Christopher Snowhill
1b4b22501b FFmpeg libraries: Accidentally forgot to enable the True Audio (TTA) decoder and demuxer 2022-01-23 16:10:33 -08:00
Christopher Snowhill
29ad6e3060 File Tree: Accidentally removed logging header that's used elsewhere 2022-01-23 15:02:46 -08:00
Christopher Snowhill
003b30cba2 File Tree: Remove useless logging, as the issue is apparently with pCloud's FUSE host 2022-01-23 14:43:22 -08:00
Christopher Snowhill
06adf472e9 File Tree: Bodge removed as it doesn't work, logging added for missing files 2022-01-23 13:22:52 -08:00
Christopher Snowhill
6b8d300384 Opus input: Support switching gain modes based on player settings, since the Opus tag reader doesn't support Opus gain tags yet 2022-01-22 21:03:52 -08:00
Christopher Snowhill
8e5c62f185 Info Inspector: Now displays ReplayGain info as tooltip for status text 2022-01-22 20:44:06 -08:00
Christopher Snowhill
38e013e4ab File Tree: Attempt Unicode Normalization Form bodge on enumerated paths 2022-01-22 20:32:18 -08:00
Christopher Snowhill
72f1168498 TagLib: Support reading Apple SoundCheck tags from ID3v2 and MP4 2022-01-22 20:20:24 -08:00
Christopher Snowhill
b54b10861b Playlist View: Enable column text tightening before truncation 2022-01-22 15:03:30 -08:00
Christopher Snowhill
502e52d699 Core Audio output: Hopefully stop buffer looping on device stop 2022-01-22 14:37:37 -08:00
Christopher Snowhill
6011982a63 Equalizer: Correctly activate the equalizer when starting playback 2022-01-22 12:59:59 -08:00
Christopher Snowhill
6cf7d1d615 SQLite Store: Create and update database schema version properly 2022-01-22 12:43:26 -08:00
Christopher Snowhill
ae10e3e75b TagLib: Read MP4 ReplayGain tags as foobar2000 writes them, not just as EZ CD Audio Converter writes them 2022-01-22 00:22:31 -08:00
Christopher Snowhill
5bf5830b17 Info Inspector: Now displays ReplayGain tag presence 2022-01-21 23:49:07 -08:00
Christopher Snowhill
97b8d07066 TagLib: Now reads foobar2000 ReplayGain fields from MP4 files 2022-01-21 23:48:49 -08:00
Christopher Snowhill
9bfc51cbf4 Info Inspector: Add field to display whether a track has an embedded CUE Sheet 2022-01-21 23:19:32 -08:00
Christopher Snowhill
058614b6a0 Core Audio / FFmpeg inputs: Change to correctly discern most lossy/lossless codecs 2022-01-21 23:09:35 -08:00
Christopher Snowhill
9d1fd08574 HDCD Decoder: Only process lossless tracks 2022-01-21 22:47:11 -08:00
Christopher Snowhill
0c4d5002f6 Metadata: Now supports storing cuesheet tags and encoding quality status properties 2022-01-21 22:38:54 -08:00
Christopher Snowhill
2165d37144 Metadata: Now supports disc number field where possible 2022-01-21 21:49:17 -08:00
Christopher Snowhill
bde3f552d9 Drag and Drop: Fixed jank with dragging, especially undo and redo 2022-01-21 16:11:24 -08:00
Christopher Snowhill
a743f914e9 HDCD Indicator: Made this less janky too 2022-01-21 15:00:44 -08:00
Christopher Snowhill
391fc474f3 Drag and Drop: Made DND undo possibly less janky 2022-01-21 15:00:27 -08:00
Christopher Snowhill
297b7b2909 Playlist View: Fix default sorting and playlist refreshing, which fixes playlist search bugging out 2022-01-21 00:16:29 -08:00
Christopher Snowhill
26e0e0cead HDCD Decoding: Add HDCD indicator 2022-01-20 23:53:45 -08:00
Christopher Snowhill
3a2d360d24 Play Time Field: Rename function used to count digits 2022-01-20 22:33:15 -08:00
Christopher Snowhill
6e68494f09 Play Time Field: Now pads with spaces up to the duration size plus hyphen, as necessary 2022-01-20 22:30:31 -08:00
Christopher Snowhill
71347aab83 Play Time Field: Changed how control achieves monospace numbers, and changed font 2022-01-20 22:03:59 -08:00
Christopher Snowhill
0f90dd3b3e Playlist View: Support undoing and redoing Drag and Drop operations within the playlist 2022-01-20 21:48:23 -08:00
Christopher Snowhill
c07b268288 Playlist View: Adjust threshold for expansion tooltip assignment 2022-01-20 18:18:05 -08:00
Christopher Snowhill
4e918fc868 Playlist View: Refresh playlist entries when queue is emptied 2022-01-20 17:58:24 -08:00
Christopher Snowhill
973664f3b3 Playlist View: Correctly refresh playlist tooltips when queue is manipulated 2022-01-20 17:54:02 -08:00
Christopher Snowhill
7cc4ee22f7 Playlist View: Fix centering and sizing of status icons 2022-01-20 17:37:56 -08:00
Christopher Snowhill
8c63e8fde3 Playlist View: Now using monospaced numbers on all fields 2022-01-20 17:26:30 -08:00
Christopher Snowhill
b317bfcdc2 Playlist View: Remove some bugs in the sizing 2022-01-20 17:02:34 -08:00
Christopher Snowhill
db867c841c Playlist View: Add status tooltip to status icon 2022-01-20 15:54:40 -08:00
Christopher Snowhill
a4c3509e75 Playlist View: Refresh entire rows on status changes to refresh tooltips 2022-01-20 15:51:24 -08:00
Christopher Snowhill
b78e55a50c Playlist View: Fix status message tooltip 2022-01-20 15:39:29 -08:00
Christopher Snowhill
2b4de1033d Playlist View: Replace Cell-based table with View-based table. It needs some work still, though. 2022-01-20 14:59:26 -08:00
Christopher Snowhill
e8f4e5ece7 SQLite store: Only store raw title field in database, rather than auto generated one 2022-01-20 14:54:51 -08:00
Christopher Snowhill
6f0f9d7617 Playlist Entry: Made copy contsructor proper 2022-01-20 14:54:42 -08:00
Christopher Snowhill
34942a0ffa SQLite store: Internal database cache now uses copied objects, and returns copies to the caller 2022-01-19 23:23:52 -08:00
Christopher Snowhill
ba5f5b8694 Playlist Entry: Made object copyable 2022-01-19 23:23:17 -08:00
Christopher Snowhill
698798a6f4 CUE Sheet input: Seek function now returns correct time offset 2022-01-19 22:09:29 -08:00
Christopher Snowhill
244f896318 CUE Sheet input: Fix for regular cue sheets, and for existing URLs for embed supported tracks 2022-01-19 22:06:36 -08:00
Christopher Snowhill
3bb57c7ca5 GSF plugin: Updated libmgba 2022-01-19 20:45:46 -08:00
Christopher Snowhill
178b32cbdf Core Audio output: Remove all delayed track end events when buffer reset 2022-01-19 14:54:04 -08:00
Christopher Snowhill
576f1a702a Core Audio output: Hopefully really fix deadlock issue 2022-01-19 14:50:48 -08:00
Christopher Snowhill
16a58e87a0 Core Audio output: Attempt to fix deadlock near track transitions when buffer resets occur 2022-01-19 14:38:48 -08:00
Christopher Snowhill
5f82fa572e Correct accents in Credits 2022-01-19 02:45:05 -08:00
Christopher Snowhill
6f0a737123 Cog Audio: Implement HDCD decoding 2022-01-19 02:08:57 -08:00
Christopher Snowhill
f2feb3bcd7 Equalizer: Fix applying equalizer presets on automatic track change 2022-01-19 01:23:59 -08:00
Christopher Snowhill
31e5cd9337 Core Audio output: Add debugging code for logging output to disk, only enabled at compile time as necessary 2022-01-19 00:41:42 -08:00
Christopher Snowhill
5c17dc9207 Notifications: Only send position notifications periodically 2022-01-19 00:41:12 -08:00
Christopher Snowhill
de193b70e2 Converter: Improve extrapolation for resampler, and also pad decimated DSD, even if not resampling it 2022-01-19 00:40:40 -08:00
Christopher Snowhill
2c7d083588 Equalizer: JSON parser can now read the equalizer preset items out of order, and supports an 'altGenres' field, which should be an array of strings, alternate genre names to match for a given preset 2022-01-18 20:24:52 -08:00
Christopher Snowhill
c2971dd1f6 Update Patreon credits 2022-01-18 18:38:26 -08:00
Christopher Snowhill
684951bdc0 Change a bunch of NSArray declarations to const collection literals 2022-01-18 18:12:57 -08:00
Christopher Snowhill
ba0fedf151 Add stub function to Silence Decoder 2022-01-18 17:30:07 -08:00
Christopher Snowhill
7495bff780 FFmpeg: Enable all the PCM and ADPCM codecs for WAV file use 2022-01-18 17:25:45 -08:00
Christopher Snowhill
f7db1f550a Update Info.plist with static container types, such as playlists 2022-01-18 16:59:30 -08:00
Christopher Snowhill
f9ace87319 Add static container types to Info.plist generator stub 2022-01-18 16:58:31 -08:00
Christopher Snowhill
9085cf18df Core Audio output: Fix crash on playback reaching the end of the playlist 2022-01-18 16:48:37 -08:00
Christopher Snowhill
5c0a510848 Core Audio output: Add various minor changes 2022-01-18 16:43:58 -08:00
Christopher Snowhill
c4c29be35a Output converter: Limit extrapolation to only be trained on twice as many samples as the extrapolation order 2022-01-18 16:43:10 -08:00
Christopher Snowhill
ec8466e56c Update Info.plist with new associations 2022-01-18 03:22:18 -08:00
Christopher Snowhill
1540b84b09 Clean up association names 2022-01-18 03:20:07 -08:00
Christopher Snowhill
c05dc28a8d Updated VGMStream to r1702-8-gb1325840 2022-01-18 03:13:34 -08:00
Christopher Snowhill
39a5ee8ab7 Utility: Add stubs to regenerate Info.plist with file type associations 2022-01-18 03:07:32 -08:00
Christopher Snowhill
e70efdaa5a Donate options: Re-launched my Patreon page, so added the link back 2022-01-18 00:07:40 -08:00
Christopher Snowhill
96166f9e8d Equalizer: Hide stock control's 'Flatten EQ' button 2022-01-17 23:19:18 -08:00
Christopher Snowhill
7a0c1d230e Volume control: Make preamp optional, defaulting to a limit of 100% volume 2022-01-17 22:41:26 -08:00
Christopher Snowhill
6684a8280f AdPlug: Plugin now loads its AdPlug database on startup 2022-01-17 21:48:35 -08:00
Christopher Snowhill
322d9539d6 AdPlug: Updated library 2022-01-17 21:47:54 -08:00
Christopher Snowhill
4aa6ef0b14 Equalizer: Load presets when first used by genre tracking if dialog hasn't been opened yet 2022-01-17 21:16:39 -08:00
Christopher Snowhill
c56852437d Equalizer: Track band count changes 2022-01-17 21:10:57 -08:00
Christopher Snowhill
83ad969d9b Equalizer: Add option for presets to track the music genre tags 2022-01-17 20:43:08 -08:00
Christopher Snowhill
147de11d89 Equalizer: Interpolate to reach bands outside of presets 2022-01-17 18:45:59 -08:00
Christopher Snowhill
dbc0698cee Equalizer: Implemented stock presets 2022-01-17 06:37:38 -08:00
Christopher Snowhill
87c771c67c Equalizer: Add option to toggle the equalizer on or off 2022-01-17 01:22:15 -08:00
Christopher Snowhill
c8057e1037 Fix bug in new Core Audio output code 2022-01-16 14:08:17 -08:00
Christopher Snowhill
ee44c12baf Fix CORS policy template 2022-01-16 14:07:44 -08:00
Christopher Snowhill
71b2f7a4f2 Implement graphic equalizer 2022-01-16 07:32:47 -08:00
Christopher Snowhill
c640481c25 Add SIMD optimized volume scaling 2022-01-16 00:46:21 -08:00
Christopher Snowhill
669c52e63d Use numeric minus sign for time remaining 2022-01-16 00:18:29 -08:00
Christopher Snowhill
297b6247cc Show volume slider tooltip on the left side of the slider if it would otherwise run off the screen 2022-01-16 00:15:56 -08:00
Christopher Snowhill
6366769614 Add randomize playlist button to mini mode usable toolbar buttons 2022-01-16 00:00:23 -08:00
Christopher Snowhill
72453ba05a Cog Audio: Converter now rounds up sample counts affected by resamlping ratio 2022-01-15 23:41:31 -08:00
Christopher Snowhill
d3548d77e7 Hide current artist from dock context menu when not playing or when there is no artist set 2022-01-15 23:41:02 -08:00
Christopher Snowhill
7da599fe3c Remove stale function declarations 2022-01-15 23:30:43 -08:00
Christopher Snowhill
df1f70c70e Adjust all preferences dialog control positions and panel sizes for consistency 2022-01-15 22:05:41 -08:00
Christopher Snowhill
1efa5ae055 Add aws invalidation back to update script 2022-01-15 20:39:12 -08:00
Christopher Snowhill
33aa7e2f38 Add local testing host to CORS policy file 2022-01-15 20:38:42 -08:00
Christopher Snowhill
602facf31a Move feed and downloads back to S3 2022-01-15 19:04:26 -08:00
Christopher Snowhill
8b7cd39576 Add default cors-policy for storage bucket 2022-01-15 16:22:32 -08:00
Christopher Snowhill
8eb2b4c4a3 Cog Audio: Finally fix track glitching on lots of tiny tracks 2022-01-15 02:52:35 -08:00
Christopher Snowhill
61d096aef3 SQLite store: Fix track update cache 2022-01-15 02:28:47 -08:00
Christopher Snowhill
fbef034903 Cog Audio: Further overhaul output buffering and track queue code 2022-01-15 02:09:26 -08:00
Christopher Snowhill
1a7e7a4b70 SQLite store: Fix playlist syncing 2022-01-15 02:08:58 -08:00
Christopher Snowhill
c5b940680d Cog Audio: Change NEON s16/s32 to f32 code to use linear load/store instead of interleaved 2022-01-15 02:08:04 -08:00
Christopher Snowhill
5ab728b205 Cog Audio: Overhaul output buffering yet again, adding an extra buffer stage between the converter and the output thread 2022-01-14 22:46:41 -08:00
Christopher Snowhill
a1522aeb6e CueSheet parser: Support quirky FLAC generated CueSheets that contain sample counts instead of frames 2022-01-14 22:45:45 -08:00
Christopher Snowhill
ccbfc6ec4b Semaphore: Change timedWait to wait in microseconds 2022-01-14 22:43:46 -08:00
Christopher Snowhill
74cd0f7da9 SQLite playlist store: Greatly improved performance of playlist sync operations 2022-01-14 22:42:57 -08:00
Christopher Snowhill
33f3b4f5a0 CueSheet processor: Support timestamps with one or two fields, as well as the standard three fields 2022-01-14 19:05:48 -08:00
Christopher Snowhill
dac1dfee47 CueSheet input: Implement support for ReplayGain tags 2022-01-14 18:51:44 -08:00
Christopher Snowhill
59aea2966f Cog Audio: Fix >16 <=32 integer bits per sample to float conversion on Apple Silicon 2022-01-14 18:51:12 -08:00
Christopher Snowhill
2d32381bc1 Cue Sheet: Fix decoder priority level 2022-01-14 17:45:10 -08:00
Christopher Snowhill
d24a01a637 Implemented basic embedded CueSheet support 2022-01-14 16:46:35 -08:00
Christopher Snowhill
6315377eaf Cog Audio: Fix extrapolator to use signed type for sample delta 2022-01-14 11:37:52 -08:00
Christopher Snowhill
af6677cf34 Cog Audio: Keep track of last resampler quality used so we don't reinitialize when not necessary, and also keep track of DSD decimated sample rate separately, so the input format remains unmodified 2022-01-14 11:18:50 -08:00
Christopher Snowhill
2e164d3fc8 Cog Audio: Reduce glitching on track change by invoking a delegate method that occurs when the track finishes outputting without waiting for it 2022-01-14 11:16:35 -08:00
Christopher Snowhill
3cc5b46a0e Cog Audio: Improve end of track handling 2022-01-14 10:17:41 -08:00
Christopher Snowhill
cb3782d0b1 Cog Audio: Improve ring buffer 2022-01-14 10:17:08 -08:00
Christopher Snowhill
3ce3edde88 Cog Audio: Fix track end extrapolator used by resampler 2022-01-14 07:39:55 -08:00
Christopher Snowhill
748891f285 Cog Audio / WavPack input: Add DSD decimation to converter, and change WavPack input to emit only raw DSD 2022-01-14 06:26:09 -08:00
Christopher Snowhill
996bdec4be RetroArch resampler: Template channel configurations from 1 through 8 using macros for speed, and also fix kaiser SSE for channel counts other than 2 2022-01-14 03:05:55 -08:00
Christopher Snowhill
ec0b343596 WavPack input: Decode DSD without letting WavPack library decimate it. The supplied filter was rather noisy. 2022-01-14 02:11:46 -08:00
Christopher Snowhill
903b457a28 Cog Audio: Make it possible to play obscene sample rate files without major failures 2022-01-14 02:00:32 -08:00
Christopher Snowhill
5aa3f7dd0a Cog Audio: Properly support seeking within the file that appears to be playing, even if it has already finished decoding 2022-01-14 00:29:02 -08:00
Christopher Snowhill
083dbbf18b Cog Audio: Also commit synchronization delay on new track playback 2022-01-13 23:54:16 -08:00
Christopher Snowhill
c8d2864862 Cog Audio: Enhance playback queue handler, so it always halts buffering when there are at least 30 seconds worth of buffers filled, possibly spanning multiple files. Also improve the chain reset function so that playlist changes and playback order control reset the queue properly when the queue refill function is currently entered in another thread. 2022-01-13 23:05:32 -08:00
Christopher Snowhill
7cc89c9f92 Cog Audio: Enhance track end extrapolator so it will always have a reasonable amount of buffered data for extrapolation 2022-01-13 23:03:53 -08:00
Christopher Snowhill
e6124335d1 Cog Audio: Change output callback to always retry reading for sample data until the requested buffer is filled, or until the playback either ends or is torn down. This prevents gaps when the preceding ring buffer wraps around. 2022-01-13 23:02:01 -08:00
Christopher Snowhill
92d29e7acf Cog Audio: Now preserves already resampled output when switching output formats 2022-01-13 19:43:18 -08:00
Christopher Snowhill
ee509b6e13 Cog Audio: Remove unnecessary preprocessor macro for RetroArch code 2022-01-13 18:01:12 -08:00
Christopher Snowhill
601b412d98 libfdk-aac: Update README.md with optimization flags 2022-01-13 17:21:05 -08:00
Christopher Snowhill
bba2fa6592 libfdk-aac: Fix library id path in rebuilt library 2022-01-13 16:39:25 -08:00
Christopher Snowhill
ca4a2efea1 FFmpeg input: Disable peak limiting for libfdk-aac decoder 2022-01-13 16:14:04 -08:00
Christopher Snowhill
4029160a0c libfdk-aac: Oops, forgot to enable optimization 2022-01-13 16:13:12 -08:00
Christopher Snowhill
bfa178f4e2 FFmpeg input: Add support for libfdk-aac, which will be used to support USAC and AAC on 10.14.x and older 2022-01-13 04:13:58 -08:00
Christopher Snowhill
73348b1616 Cog Audio: Implement play position skip ahead when output format changes, based on how much converter output is being discarded 2022-01-12 23:17:07 -08:00
Christopher Snowhill
52b17bd4d8 Cog Audio: Implement virtual ring buffer function to read buffered bytes count 2022-01-12 23:16:13 -08:00
Christopher Snowhill
d1b519d59d Cog Audio: Only declare end of stream on read when previous node has declared end of stream and the buffer has actually run empty. This prevents the case where the buffer may terminate early due to the read pointer hitting the end of the ring buffer and wrapping. 2022-01-12 23:15:23 -08:00
Christopher Snowhill
ec7ac74fcd Cog Audio: Fix input chain to reset its buffers when seeking properly 2022-01-12 23:13:49 -08:00
Christopher Snowhill
cc134ce293 Cog Audio: Converter node actually pauses when it is being reconfigured, and resets its buffer when the output format is changed 2022-01-12 23:13:00 -08:00
Christopher Snowhill
b0f5a37e85 Cog Audio: Only proceed to the next track when the current track has actually finished 2022-01-12 21:53:58 -08:00
Christopher Snowhill
5fef62dd03 Cog Audio: Implemented device output and input file format changing support 2022-01-12 21:31:22 -08:00
Christopher Snowhill
9feaffc92d Cog Audio: Made RetroArch resampler safer 2022-01-12 18:45:43 -08:00
Christopher Snowhill
f2656bc7b3 Updated VGMStream to r1702-0-ga76ac04d 2022-01-12 16:53:42 -08:00
Christopher Snowhill
e3df82cf70 VGMStream input: Improve file interface, to handle duplicate file requests in the same thread, and to handle archive paths 2022-01-12 16:45:50 -08:00
Christopher Snowhill
8664bacc60 Core Audio output: Correctly terminate output when requested to stop, preventing a case where multiple outputs were draining the playback buffer at once 2022-01-12 16:04:41 -08:00
Christopher Snowhill
2633e713a3 Cog Audio: Remove seek mess from previous commit 2022-01-12 16:03:49 -08:00
Christopher Snowhill
f1d70aaa54 Cog Audio: Add explanatory comment to source code 2022-01-12 03:36:27 -08:00
Christopher Snowhill
84d445cffe Cog Audio: Fix converter so that seeking on startup playback position resume works properly 2022-01-12 03:01:55 -08:00
Christopher Snowhill
16402f9982 RetroArch resampler: Stub out code we don't need, reducing code size 2022-01-12 03:01:55 -08:00
Christopher Snowhill
9dbaed22f0
Update README.md
Added addendum on new resampler
2022-01-12 01:22:49 -08:00
Christopher Snowhill
3b125c0440 Cog Audio: Improve virtual ring buffer class 2022-01-11 22:50:18 -08:00
Christopher Snowhill
a76f3c3476 Cog Audio: Reorder project files 2022-01-11 22:48:50 -08:00
Christopher Snowhill
f8e3b0e1ee Core Audio output: Some more minor changes 2022-01-11 22:06:41 -08:00
Christopher Snowhill
3b62842021 Playback Notifications: Prevent crash when notifying a track with unusable album artwork 2022-01-11 20:39:10 -08:00
Christopher Snowhill
557e0bd399 Core Audio output: Fix so it stops properly 2022-01-11 20:38:17 -08:00
Christopher Snowhill
91c3feac2e Cog Audio converter: Fix handling signed versus unsigned for 8 bit samples 2022-01-11 19:37:47 -08:00
Christopher Snowhill
f44e4e793b Cog Audio converter: Fix end of track flush and extrapolation 2022-01-11 19:37:17 -08:00
Christopher Snowhill
8a91bc1d09 Playlist loader: Allocate larger properties dictionary 2022-01-11 19:35:59 -08:00
Christopher Snowhill
ed882e25cb Cog Audio: Resampler now extrapolates into latency padding for better gapless playback 2022-01-11 18:19:30 -08:00
Christopher Snowhill
7d4841b1c6 Core Audio output: Don't upmix unless output device requests it by default 2022-01-11 18:18:38 -08:00
Christopher Snowhill
ee05fe9e44 Core Audio output: Add sanity checking for supported formats, and support 64 bit float input data, in case anything actually uses that 2022-01-11 17:09:06 -08:00
Christopher Snowhill
4dd46a1b5b Core Audio output: Fix output stopping properly 2022-01-11 07:52:44 -08:00
Christopher Snowhill
72210c67e4 Replaced AudioQueue output with AUAudioUnit 2022-01-11 07:06:40 -08:00
Christopher Snowhill
c4c9a741ef Replaced AudioToolbox converter process with homebrew solution, using the RetroArch sinc resampler 2022-01-11 04:09:19 -08:00
Christopher Snowhill
c8301a9868 CoreAudio input takes priority over FFmpeg on 10.14.x and older 2022-01-09 17:05:10 -08:00
Christopher Snowhill
a1a85c502e FFmpeg input: Check for seeking errors and stop decoding when they happen 2022-01-09 03:37:45 -08:00
Christopher Snowhill
87ebca5e03 Really fix saving track position on quit 2022-01-09 03:17:43 -08:00
Christopher Snowhill
6e9266e194 Fix track position storage on quit 2022-01-09 03:06:36 -08:00
Christopher Snowhill
3e72087a41 Play position is stored every 10 seconds, and status is stored every time playback is started, paused, stopped, or seeked 2022-01-09 02:34:29 -08:00
Christopher Snowhill
7fe67b1630 Implement dock icon progress bar indicator for many processing operations, including adding tracks, removing tracks, and loading or reloading track metadata 2022-01-09 02:10:08 -08:00
Christopher Snowhill
0d90ccb7c1 FFmpeg: Update ID3v1 genre list 2022-01-08 16:19:08 -08:00
Christopher Snowhill
51e48dc424 MPCDec: Update genre list to match what TagLib reads 2022-01-08 16:12:00 -08:00
Christopher Snowhill
6c910bdfbc TagLib: Fix reading ReplayGain tags from ID3v2 tags 2022-01-08 01:29:55 -08:00
Christopher Snowhill
b35d405e20 libvgm input: Correctly declare logging formatting strings 2022-01-07 19:07:46 -08:00
Christopher Snowhill
614517f813 FFmpeg input: Disable AudioToolbox codecs on macOS 10.14.x and older 2022-01-07 19:07:07 -08:00
Christopher Snowhill
95f1919f90 FFmpeg: Rebuild FFmpeg with different codec settings 2022-01-07 19:06:35 -08:00
Christopher Snowhill
86e3a26598 VGMStream: Turn down libvgmstream optimization to -O1 on Intel, to hopefully fix a possible optimization bug 2022-01-07 17:29:12 -08:00
Christopher Snowhill
b40b506cc3 Remove unneeded header import 2022-01-07 02:16:55 -08:00
Christopher Snowhill
00052130a0 Revert ea589b2635, and fix reloading info for entries on Intel, by invoking the reloader in the background instead of directly calling it from the UI thread 2022-01-07 02:12:49 -08:00
Christopher Snowhill
ea589b2635 Playlist loader: No longer do background metadata reading on Intel machines, where VGMStream mysteriously clobbers the stack at random when run in the background 2022-01-07 01:35:59 -08:00
Christopher Snowhill
60ad561a26 OpenMPT: Compile libraries with precompiled headers so they build faster 2022-01-06 23:55:00 -08:00
Christopher Snowhill
7ee76f914a OpenMPT legacy: Correct header import paths so that the correct version of OpenMPT framework headers are used 2022-01-06 23:53:39 -08:00
Christopher Snowhill
1eb2270049 VGMStream: Rewrite file interface based on the VGMStream stdio interface, only using CogSource files 2022-01-06 22:12:34 -08:00
Christopher Snowhill
71fd2eb0f8 SQLite storage: Implement missing function to empty the play queue 2022-01-06 21:03:31 -08:00
Christopher Snowhill
0e8f417e67 libvgm Player: Correctly report version number in codec field 2022-01-05 02:37:39 -08:00
Christopher Snowhill
5b67735f12 libvgm Player: Fix FM clocks for really old VGM files 2022-01-05 02:26:02 -08:00
Christopher Snowhill
e4e6da1a94 Clean up new GME somewhat 2022-01-04 03:42:18 -08:00
Christopher Snowhill
fc38295d02 Replaced Game_Music_Emu with mpyne version, for the most part. Re-added the missing NSF chips, replaced the SPC player with the Higan one, re-added SFM, and disabled GYM and VGM. 2022-01-03 17:50:07 -08:00
Christopher Snowhill
888ee2fb38 Implemented new libvgm-based VGM, S98, DRO, and GYM player 2022-01-03 01:55:48 -08:00
Christopher Snowhill
8ad7e086a8 Update copyright year 2022-01-02 23:34:29 -08:00
Christopher Snowhill
6e1e3daf76 Consolidate libbinio framework usage 2021-12-31 01:40:11 -08:00
Christopher Snowhill
df9743c821 Consolidated Vorbis framework usage 2021-12-31 01:35:08 -08:00
Christopher Snowhill
4cb4a000f0 Consolidate Ogg framework usage 2021-12-31 01:30:16 -08:00
Christopher Snowhill
e166402bb5 Consolidate MASShortcut framework usage 2021-12-31 01:23:58 -08:00
Christopher Snowhill
98ead66851 Consolidate File_Extractor framework usage 2021-12-31 01:16:44 -08:00
Christopher Snowhill
2e76c56ba7 Switch FFmpeg libraries to dynamic builds, consolidate to a single copy in the main application framework folder 2021-12-31 01:07:05 -08:00
Christopher Snowhill
78fa5accc0 Updated VGMStream to r1690-35-gc38c09fb 2021-12-30 23:45:02 -08:00
Christopher Snowhill
16b1bfea03 Updated libsidplay to version 2.3.1 2021-12-30 23:24:07 -08:00
Christopher Snowhill
112a20132b OpenMPT: Add format info as codec string 2021-12-30 00:07:32 -08:00
Christopher Snowhill
e4cbdb07f8 FFmpeg Decoder: Remove spurious debug logging 2021-12-29 22:56:53 -08:00
Christopher Snowhill
fa20465271 FFmpeg Decoder: Fix seeking in files with preroll that happens to make the decoder return EAGAIN error, so they don't inadvertently skip actual audio data unnecessarily. Fixes seeking to the start of USAC files with preroll packets. 2021-12-29 22:55:31 -08:00
Christopher Snowhill
cd8b728ca6 Removed plugin 2021-12-29 15:24:23 -08:00
Christopher Snowhill
41a32f0b9d Update Gitlab CI config file again 2021-12-28 21:22:40 -08:00
Christopher Snowhill
8d7c24e0ad Update Gitlab CI config 2021-12-28 21:16:39 -08:00
Christopher Snowhill
dfe92ffedc Audio Player: Fix so ReplayGain isn't reset on seek 2021-12-28 21:05:25 -08:00
Christopher Snowhill
841481599e Audio Player: Minor change 2021-12-28 21:04:46 -08:00
Christopher Snowhill
c1c21ec84f Hopefully fix glitching on seeking 2021-12-28 16:04:16 -08:00
Christopher Snowhill
486352ea72 Core Audio output: Enforce some minimum quality settings 2021-12-28 15:41:31 -08:00
Christopher Snowhill
ba3746fcff Remove blank line 2021-12-28 15:40:53 -08:00
Christopher Snowhill
476dd913b2 Audio player: Attempt to fix queue issues. There are still remaining issues if a single short track queues repeatedly and the user changes tracks manually. 2021-12-28 15:40:26 -08:00
Christopher Snowhill
38c530043d Output converter: Add more upmixing modes 2021-12-28 15:39:23 -08:00
Christopher Snowhill
27dbd609c9 OpenMPT: Change decode call slightly 2021-12-28 15:38:57 -08:00
Christopher Snowhill
73a356ad1d Ogg Vorbis/Opus: Use correct channel output order for surround files 2021-12-28 00:54:28 -08:00
Christopher Snowhill
b13235ec5f Fix 6.1 stereo downmix mapping 2021-12-28 00:10:44 -08:00
Christopher Snowhill
258a56a276 Audio Output: Implement more upmixing modes, and correct some upmixing behavior 2021-12-28 00:09:57 -08:00
Christopher Snowhill
ad3058c4f3 Audio Queue: Better handle a lot of short files playing in a row, so files don't get skipped, and so the player doesn't get overburdened starting new files 2021-12-27 23:21:48 -08:00
Christopher Snowhill
120daf291a OpenMPT legacy: No longer need to reduce its priority level, since it's OS version gated to not load on OSes that support the newer plugin 2021-12-27 17:47:57 -08:00
Christopher Snowhill
e2bca8f93b OpenMPT: Correctly OS version gate the OpenMPT plugins, and add an interface for any other plugin to use, should it ever become necessary 2021-12-27 17:46:09 -08:00
Christopher Snowhill
25a43a9083 Audio Output: Fix converter to always emit trailing samples on end of track 2021-12-27 17:04:16 -08:00
Christopher Snowhill
8e895c88c0 Core Audio output: Properly apply or remove default device change listener when switching preferences between the 'System Default Device' setting and manually setting the device to the current default 2021-12-26 21:33:28 -08:00
Christopher Snowhill
8435416cd7 Core Audio output: Default device setting now tracks system device changes, and output assigns a speaker mapping depending on the channel count 2021-12-26 21:27:26 -08:00
Christopher Snowhill
378aaf23ae Clean up several CFStringRef leaks 2021-12-26 18:08:53 -08:00
Christopher Snowhill
f241d88e16 OpenMPT legacy: Commit missing files, and fix .gitignore to allow them 2021-12-26 17:18:39 -08:00
Christopher Snowhill
d2e480ace5 Core Audio output: Properly support switching output devices 2021-12-26 17:16:16 -08:00
Christopher Snowhill
642945e80a OpenMPT: Add include path for svn_version.h header file 2021-12-26 04:47:12 -08:00
Christopher Snowhill
917b7457b6 Made resume playback on startup so that seeking operation is entirely atomic with starting playback, so the new seeking behavior doesn't have the potential to crash the player 2021-12-26 04:35:54 -08:00
Christopher Snowhill
1cc34ea7d4 Audio Output: Made converter cleanup atomic, to wait on any threads that are still running 2021-12-26 04:34:33 -08:00
Christopher Snowhill
106eb587b4 Updated libopenmpt to version 0.6.0, with major new changes. This new version requires macOS 10.15 to work, due to libc++ features required. A compatibility plugin has been duplicated from the existing plugin, which will now load libopenmpt 0.5.14, or whatever newer version may come out that still supports as old as macOS 10.12. 2021-12-26 03:29:43 -08:00
Christopher Snowhill
8d7cd6cc93 Multi Input plugin: Correctly forward register and remove observer callbacks to the actual decoder in use 2021-12-26 02:01:53 -08:00
Christopher Snowhill
dfeca7aa97 Seeking now takes the true nuclear approach to output, and should no longer have glitches 2021-12-26 02:01:02 -08:00
Christopher Snowhill
d22ee14a36 Audio Output: Take a more nuclear approach to output resetting when seeking 2021-12-25 23:41:45 -08:00
Christopher Snowhill
1278b64afd Audio Output: Fixed converter so it won't loop endlessly when it either reaches the end of a stream or is otherwise supposed to terminate 2021-12-25 22:47:17 -08:00
Christopher Snowhill
5246731189 Core Audio: Overhauled audio output to use AudioQueue instead of AudioUnit, fixed downmixing to mono, and implemented upmixing mono or other formats to more channels if the device requests them 2021-12-25 22:32:43 -08:00
Christopher Snowhill
c6b112f512 CoreAudio output: Fix buffer underruns on output that could result in buffer looping in CoreAudio, by feeding silence from the callback instead of returning incomplete or possibly empty buffers 2021-12-25 19:43:10 -08:00
Christopher Snowhill
098650099e Fix SQL playlist loader so it doesn't crash on an empty playlist 2021-12-25 16:42:28 -08:00
Christopher Snowhill
9c9d71cd9c Overhaul CoreAudio output code: Downmix properly from 8 channels, redo converter process, and no longer crash when forced to output to a low quality device. Switchover to stereo from mono isn't perfect, however. 2021-12-25 15:02:13 -08:00
Christopher Snowhill
d4614a2f03 Syntrax/Jaytrax: Replace cubic interpolation function with a fixed point integer based version, for a 20% performance boost 2021-12-24 23:33:34 -08:00
Christopher Snowhill
a8a982d3a4 SQLite Store: Fix storing strings with multi byte Unicode sequences 2021-12-24 15:48:30 -08:00
Christopher Snowhill
2445cc94a9 - Retrieve profile paths properly instead of hard coding
- Display playlist total duration in units up to weeks and down to just seconds, and only pluralize units as necessary
- Major change: Implemented a SQLite disk backed playlist, track data, and queue storage system, which will be synchronized from the player in real time, and will hopefully survive system or app crashes. Existing plist playlist will be imported on first run, and removed on shutdown.
2021-12-24 01:01:21 -08:00
Christopher Snowhill
fd75e1b260 HTTP source: Fix API abuse by calling completion handler as requested 2021-12-22 16:27:41 -08:00
Christopher Snowhill
2bb9698e34 FLAC: Remove unused files from libFLAC framework 2021-12-22 16:24:16 -08:00
Christopher Snowhill
e207cdc022 Opus/FFmpeg: Add more streaming types to handle, now supports working Ogg Vorbis, Opus, and FLAC streaming 2021-12-22 16:23:54 -08:00
Christopher Snowhill
4ff38268ae Plugins: Support multiple handlers per MIME type for streams 2021-12-22 16:22:49 -08:00
Christopher Snowhill
9566a36815 Error handler: Better handle errors and increase silence generator to 10 seconds at a time 2021-12-22 16:22:05 -08:00
Christopher Snowhill
7da3324e32 OpenMPT: Enable SSE2 and ARM NEON optimizations for a slight improvement in performance 2021-12-22 00:18:57 -08:00
Christopher Snowhill
c2585f5567 FFMPEG input: Add more formats, reduce buffering so streams start faster, and fix seeking calculation so streams seek properly 2021-12-22 00:17:59 -08:00
Christopher Snowhill
c47bd96d65 FFMPEG / vgmstream: Update dependencies for newer Matroska support 2021-12-22 00:15:19 -08:00
Christopher Snowhill
45ee8b01df HTTP reader: Keep track of task suspend/resume so we don't stall trying to resume an already running stream 2021-12-22 00:14:19 -08:00
Christopher Snowhill
b2ae62a4db URL open panel: Fix invocation of completion handler so it doesn't crash 2021-12-22 00:13:27 -08:00
Christopher Snowhill
bb1f9dcb33 CoreAudio / FFmpeg: Swap decoder priorities so FFmpeg takes priority over Core Audio 2021-12-21 22:26:50 -08:00
Christopher Snowhill
10d43d9154 FFmpeg: Enable extra demuxers, and switch AAC to AAC AudioToolbox 2021-12-21 22:24:05 -08:00
Christopher Snowhill
caf4855b4e Syntrax/Jaytrax: Replace existing reverse engineered implementation with a different one that handles more songs correctly 2021-12-15 16:47:36 -08:00
Christopher Snowhill
44b813d2bf Audio queue: Better handle queues of lots of short files 2021-12-11 00:22:54 -08:00
Christopher Snowhill
00f1e0957c FLAC: Move libFLAC decoder to higher priority than any potential system decoder, support arbitrary sample bit depths 2021-12-11 00:22:19 -08:00
Christopher Snowhill
ed8a5763ab Output: Add System Default Output option, rather than adjusting the listing to display the current system default only the first time 2021-12-05 22:49:56 -08:00
Christopher Snowhill
554dde4e91 Updated VGMStream to r1690-0-g82d86c64 2021-12-05 21:26:16 -08:00
Christopher Snowhill
8df33d1cc9 Updated libopenmpt to version 0.5.14 2021-12-05 21:05:35 -08:00
Christopher Snowhill
5772662984 Cuesheet: Read and merge metadata from referenced audio files, no matter their format 2021-11-21 00:16:16 -08:00
Christopher Snowhill
63e10bcb77 Fix Git hook to actually trip when only a single match is found 2021-11-21 00:13:17 -08:00
Christopher Snowhill
91bd653b55 Fading: Hopefully fix fading being broken after fading in once, possibly a rounding error that depends on the volume level set before fading in 2021-11-17 21:12:25 -08:00
Christopher Snowhill
d8dcb75ec6 Updated VGMStream to r1667-99-g1355279f 2021-11-17 21:11:40 -08:00
Christopher Snowhill
58384cb831 Updated VGMStream to r1667-90-gc57f4383 2021-11-14 21:43:04 -08:00
Christopher Snowhill
4344f358c2 Updated libopenmpt to version 0.5.13 2021-11-14 21:34:08 -08:00
Christopher Snowhill
b53d396a10 Highly Complete: NCSF: Fix portamento register to enable portamento 2021-11-14 21:33:40 -08:00
Christopher Snowhill
b39d585794
Fix dangling team ID
Dammit, I thought I had commit hooks preventing me from letting these changes through?
2021-11-03 20:42:57 -07:00
Christopher Snowhill
bce21b44d4 MIDI: Overhaul player completely, now Audio Unit support works properly, and the Sound Canvas VA hack is no longer needed. Now System Exclusive messages may be filtered for all plugins. 2021-11-02 19:52:12 -07:00
Christopher Snowhill
8b2e4524b2 Sync with latest shpakovski/MASShortcut. 2021-11-01 18:26:18 -07:00
Christopher Snowhill
b3c5bf8e96 GSF: Updated mGBA 2021-11-01 18:23:17 -07:00
Christopher Snowhill
a93510dd8b Updated VGMStream to r1667-70-g3f281cdf 2021-11-01 18:23:17 -07:00
Christopher Snowhill
d522730fd3
Merge pull request #175 from losnoco/nevack/sync-masshortcut
Sync with latest shpakovski/MASShortcut.
2021-10-14 14:59:27 -07:00
Dzmitry Neviadomski
4e93bc2af8 Sync with latest shpakovski/MASShortcut. 2021-10-14 18:18:05 +03:00
Christopher Snowhill
1fd160dc0f VGMStream: Disable HCA key brute forcing 2021-10-05 20:44:00 -07:00
Christopher Snowhill
ac998301c6 Updated VGMStream to r1640-104-gc92e4f85 2021-10-05 20:31:37 -07:00
Christopher Snowhill
3aa2e3149f Updated libopenmpt to version 0.5.12 2021-10-05 19:46:06 -07:00
Christopher Snowhill
ee6faec757 VGMStream: oops, coding error 2021-10-02 18:49:00 -07:00
Christopher Snowhill
6c8c807781 VGMStream: Clear sample buffer, just in case 2021-10-02 18:47:04 -07:00
Christopher Snowhill
71dd68036b Remove obsolete donation methods 2021-10-02 18:42:19 -07:00
Christopher Snowhill
cbf20dab08 VGMStream: Correctly implement mixing support and output channel reporting for downmixes 2021-10-02 18:38:23 -07:00
Christopher Snowhill
9e6199b108 UI: Fix table column duplication and other mess, due to saved application state 2021-10-02 00:40:10 -07:00
Christopher Snowhill
934bdc9b35 UI: Fix table identifiers 2021-10-02 00:39:23 -07:00
Christopher Snowhill
0ec1ae4c47 Core Audio input: Added Codec info reporting 2021-10-01 20:22:26 -07:00
Christopher Snowhill
cb70b066d7 Updated VGMStream to r1640-85-gfe316bb2 2021-10-01 20:21:50 -07:00
Christopher Snowhill
fdae7eec21 File info: Implemented support for Album Artist and Codec fields 2021-10-01 19:18:42 -07:00
Christopher Snowhill
e5aec4b618 USF: Update LazyUSF2 library from ages ago, fixing several sets which were just broken. Fixed things include reading the rip region from the save state's ROM header field, and vblank interrupt timing. 2021-10-01 16:59:04 -07:00
Christopher Snowhill
66f8697435 Remove DSA signing stuff, since nothing should be using it by now 2021-09-27 14:33:06 -07:00
Christopher Snowhill
ceb2e3f7dd Fix warning due to incorrect delegate function prototype 2021-09-25 13:17:00 -07:00
Christopher Snowhill
02de18dde4
Merge pull request #162 from NattyNarwhal/send-npic-stop
Send metadata so that NPIC can receive stop events at end of playback
2021-09-25 01:05:27 -07:00
Christopher Snowhill
217b3d4cf9 Attempt to clean up 10.13+ stuff with fallbacks to the old ways 2021-09-23 00:49:51 -07:00
Christopher Snowhill
505061031e Update Sparkle to version 1.27.0 2021-09-18 01:14:44 -07:00
Christopher Snowhill
cfeadad97f Reduce minimum OS to macOS 10.12 2021-09-18 01:08:49 -07:00
Christopher Snowhill
9fcfb6ddb7 vgmstream: Enable Speex support 2021-09-17 19:56:01 -07:00
Christopher Snowhill
a3aea19525 Updated VGMStream to r1640-49-g0dd8bdd7 2021-09-17 19:31:36 -07:00
Christopher Snowhill
da96d2c21e Core Audio Output: Add a check that should prevent it from attempting to output data through the callback during or after destruction 2021-09-17 19:09:34 -07:00
Christopher Snowhill
91473a11e9 GSF: Updated mGBA 2021-09-14 20:07:38 -07:00
Christopher Snowhill
42a6738e8f Updated VGMStream to r1640-11-gdfa3779a 2021-09-06 09:28:26 -07:00
Christopher Snowhill
b1f947c3b2
Merge pull request #171 from losnoco/readme-fix
Fix readme
2021-08-27 14:14:02 -07:00
Christopher Snowhill
0a6602c9c4 Fix readme 2021-08-27 13:57:50 -07:00
Christopher Snowhill
6395684001 CoreAudio input: Fixed new case where lossy inputs report file bit depth as unsupported field, causing some or possibly all lossy files to fail to decode 2021-08-25 01:57:59 -07:00
Christopher Snowhill
5b73336cb0 CoreAudio input: Optimized file size reporting to cache the file size on open, so file input isn't seeking as much 2021-08-25 01:57:05 -07:00
Christopher Snowhill
a1a0bd2db4 FFmpeg: rebuilt FFmpeg libraries 2021-08-25 01:53:51 -07:00
Christopher Snowhill
4548e54815 FFmpeg build scripts: also install yasm and cross build dependencies 2021-08-25 01:29:53 -07:00
Christopher Snowhill
5c27dcf976 FFmpeg build scripts: Add environment for Homebrew building 2021-08-25 01:27:06 -07:00
Christopher Snowhill
bc5302ed48 FFmpeg build scripts: clean up build products when each stage finishes, so nothing gets mixed from arm64 into x86_64 2021-08-25 01:26:14 -07:00
Christopher Snowhill
49b0bc52b7 FFmpeg build scripts: Support cross compiling x86_64 version from arm64 2021-08-25 01:25:32 -07:00
Christopher Snowhill
48c43167b6 Add update hook from user keychain 2021-08-22 19:25:24 -07:00
Christopher Snowhill
dea022a323 Updated VGMStream to r1626-15-g49dfc218 2021-08-22 18:32:14 -07:00
Dzmitry Neviadomski
f3f5d67b2f
Merge pull request #167 from losnoco/nevack/actions-universal-binary
Build Universal binary with GitHub Actions.
2021-08-22 22:14:51 +03:00
Dzmitry Neviadomski
e892b46b6f Build Universal binary with GitHub Actions. 2021-08-22 21:07:49 +03:00
Dzmitry Neviadomski
b9ba71cd6f
Merge pull request #166 from losnoco/nevack/actions-bigsur
Start building on macOS BigSur.
2021-08-22 20:37:22 +03:00
Dzmitry Neviadomski
1b4304fe3b Start building on macOS BigSur. 2021-08-22 20:28:37 +03:00
Christopher Snowhill
3f6cb1bc1c VGMStream: Fix .txtp with option fragments in the filename 2021-08-11 17:33:02 -07:00
Christopher Snowhill
4298a232fc Updated VGMStream to r1050-3899-g372cd750 2021-08-10 17:56:02 -07:00
Christopher Snowhill
0891a20bba MIDI: Detect presence and compatibility of Sound Canvas VA before attempting to import it later. It currently does not work with arm64, only x86_64 native or Rosetta 2. 2021-08-10 17:35:15 -07:00
Christopher Snowhill
59a5a7687e MIDI: Fix Sound Canvas VA duplication function to support the 32 signed instances current versions ship 2021-08-10 17:35:14 -07:00
Calvin Buckley
d18c9c9bb0 Why was this commented out? 2021-08-08 17:57:42 -03:00
Calvin Buckley
cdde55004a Send metadata so that NPIC can receive stop events at end of playback
Otherwise, the NPIC will just show the last track stuck at the last second.
There may be a better place to put this.
2021-08-08 17:55:51 -03:00
Christopher Snowhill
8875a36aba
Merge pull request #163 from losnoco/nevack/github_actions_no_signing
Do not use signing capabilities in GitHub Actions build.
2021-08-08 13:29:58 -07:00
Christopher Snowhill
ad63964ba1 Change GitHub Workflow to disable signing 2021-08-08 13:29:09 -07:00
Dzmitry Neviadomski
252bf5fa5b Do not use signing capabilities in GitHub Actions build.
We only need to check if changes are buildable.
2021-08-08 22:25:20 +03:00
Christopher Snowhill
fc70e0e8b4 Notifications: Fix so it supports external artwork, and also fix a crash where invalid embedded artwork would cause it to crash 2021-08-07 15:09:36 -07:00
Christopher Snowhill
981827309c Updated libmgba with minor changes 2021-08-05 00:30:11 -07:00
Christopher Snowhill
8622829af7 Updated VGMStream to r1050-3861-g0ad117e8 2021-08-05 00:26:13 -07:00
Christopher Snowhill
0a7be8ab41 Updated VGMStream to r1050-3828-g54f06ba6 2021-07-22 13:37:25 -07:00
Christopher Snowhill
91039aea9c
Merge pull request #160 from NattyNarwhal/reload-info-in-menu-bar
Put Reload Info in menu bar and capitalize consistently in context menu
2021-07-22 13:32:31 -07:00
Christopher Snowhill
63d1346c46 Updated VGMStream to r1050-3804-g3b6e1845 2021-07-11 13:28:00 -07:00
Christopher Snowhill
b08ae49598 Updated libmgba to version 0.9.2 2021-07-11 13:25:13 -07:00
Calvin Buckley
41de2b0c47 Put Reload Info in menu bar and capitalize consistently in context menu
Bizarrely, the binding is identical between them, yet the binding on
"enabled <- playlist selection" doesn't work. Bizarre, would like to
know why.
2021-07-10 12:36:18 -03:00
Christopher Snowhill
1c7b4bfde9 Updated VGMStream to r1050-3802-g5c9d52d9 2021-07-09 01:14:16 -07:00
Christopher Snowhill
0bac16c976 Updated VGMStream to r1050-3791-g4bd91df3 2021-07-07 14:44:53 -07:00
Christopher Snowhill
e0a138a1ac Updated libopenmpt to version 0.5.10 2021-07-07 14:35:06 -07:00
Christopher Snowhill
922e657f0b Context menu: Add option to reload metadata from existing playlist entries 2021-07-03 15:32:13 -07:00
Christopher Snowhill
510c762921 TagLib plugin: Implement FLAC embedded art reading 2021-07-03 15:31:26 -07:00
Christopher Snowhill
6efe954433 Updated VGMStream to r1050-3786-g26e35a02 2021-07-01 19:52:28 -07:00
Christopher Snowhill
14c51ce43a Updated VGMStream to r1050-3782-gdeeb0b4e 2021-06-25 17:12:22 -07:00
Christopher Snowhill
6f710187f9 Fix workflow for real this time, I hope 2021-06-23 02:41:55 -07:00
Christopher Snowhill
d528cbf85a Try updating the workflow again 2021-06-23 02:18:20 -07:00
Christopher Snowhill
4ee46cee77 Update Github workflow for new main branch name 2021-06-23 00:33:25 -07:00
Christopher Snowhill
0bfd14b0f2
Merge pull request #158 from NattyNarwhal/now-playing-more-metadata
Provide more information to MPNowPlayingInfoCenter, including album art
2021-06-21 20:04:46 -07:00
Calvin Buckley
0e6747c21a Provide more information to MPNowPlayingInfoCenter, including album art
NPIC can ask for a lot of metadata, but for now, provide it only what (at least I know) PlaylistEntry can provide. The biggest missing one was album art, so this change should be appreciated by those who do use it.

I don't know what it can do with the other metadata though, seeing at least on macOS, it can only do album/artist/track title/artwork.
2021-06-21 19:45:46 -03:00
Christopher Snowhill
636120c9d5 Updated VGMStream to r1050-3774-gbecac809 2021-06-20 19:36:12 -07:00
Christopher Snowhill
75a4f1e722 VGMStream: Fix one shot files actually decoding to completion instead of getting stuck forever 2021-06-15 01:34:01 -07:00
Christopher Snowhill
cae132ad79 Updated FFmpeg to version 4.4 2021-06-15 00:14:41 -07:00
Christopher Snowhill
0c648b3b1d Updated VGMStream to r1050-3748-g20e1ade3 2021-06-14 19:57:33 -07:00
Christopher Snowhill
11aa63265d Move release upload to B2 2021-06-14 19:57:25 -07:00
Christopher Snowhill
beab7dcf8d Move mGBA submodule back to Github 2021-05-30 15:32:28 -07:00
Christopher Snowhill
668475c43a VGMStream: Correctly report ReplayGain tags from external M3U tags 2021-05-30 14:47:21 -07:00
Christopher Snowhill
ef6530070e Updated VGMStream to r1050-3731-g136a7f7c 2021-05-30 14:33:51 -07:00
Christopher Snowhill
8aa47584f1 FFmpeg: Fix seeking so it's sample exact, using packet timestamps. Fixes noticeable issues when using CUE sheets with APE, for instance. 2021-05-30 14:22:20 -07:00
Christopher Snowhill
297ba6398a VGMStream: Fix loading of newly imported libcelt dependencies 2021-05-18 13:58:03 -07:00
Christopher Snowhill
3e5e24f8a2 VGMStream: Enable libcelt support 2021-05-18 00:38:39 -07:00
Christopher Snowhill
466c1beb00 Added safety checks to VGMStream file interface, which should hopefully prevent a known crash deep in the library due to possibly trying to retrieve the file name from an invalid file handle 2021-05-17 22:43:27 -07:00
Christopher Snowhill
2ab3400aab Updated VGMStream to r1050-3722-g286d5c69 2021-05-17 01:24:11 -07:00
Christopher Snowhill
24dfaf7d5c Updated libopenmpt to version 0.5.9 2021-05-16 16:54:35 -07:00
Christopher Snowhill
7181656ae9 Updated VGMStream to r1050-3714-g82dd9a7d 2021-05-16 14:24:57 -07:00
Christopher Snowhill
95a63327fa MIDI: Trimmed down FluidSynth libraries significantly, and should be compatible with 10.13 once again 2021-05-09 17:46:36 -07:00
Christopher Snowhill
b2a6a67170 MIDI: FluidSynth is now configured to load samples dynamically instead of caching entire banks at once 2021-05-08 19:41:35 -07:00
Christopher Snowhill
dffe888124
Merge pull request #152 from losnoco/nevack/revert-regression
Revert display regressions.
2021-05-08 17:18:01 -07:00
Dzmitry Neviadomski
b69cb98240 Revert display regressions.
1. Revert "Merge pull request #148 from JanX2/two-gigaseconds-mini"

This reverts commit 7365174b11, reversing
changes made to c5ac86725d.

2. Revert "Two gigaseconds (#147)"

This reverts commit c5ac86725d.
2021-05-09 01:16:20 +03:00
Christopher Snowhill
17fd41fbbc Updated FluidSynth again, restoring SF3 support 2021-05-08 00:47:03 -07:00
Christopher Snowhill
5d29b741a0 Updated FluidSynth 2021-05-07 21:08:48 -07:00
Christopher Snowhill
383d27fdff Updated VGMStream to r1050-3706-gdcdc1950 2021-05-07 18:21:19 -07:00
Christopher Snowhill
5df4035568 Brought back background metadata and file info loading, still needs a progress indicator somewhere 2021-05-07 17:19:10 -07:00
Christopher Snowhill
79d12e9fc7 CoreAudio: Don't try closing resources that aren't opened 2021-05-07 15:33:20 -07:00
Dzmitry Neviadomski
7365174b11
Merge pull request #148 from JanX2/two-gigaseconds-mini
Update mini player mode’s "Current Time" toolbar item with recent fixes.
2021-05-07 22:40:26 +03:00
Jan Weiß
c320f7fe27 Update mini player mode’s "Current Time" toolbar item with recent fixes. 2021-05-07 12:07:49 +02:00
Jan
c5ac86725d
Two gigaseconds (#147)
* Fix look of position time field to match the rest of the UI.

* Fix typo.

* Improve position time display.

* Add days, hours support to position time display.

* Fix "Current Time" toolbar item geometry/layout.

* Don’t enforce leading double-digits in position time display.

* MainMenu.xib touched by Xcode.

* Implement and use MonospacedDigitTextFieldCell.
This way the digits of numbers in playlist columns consisting of mostly digits will be aligned vertically.

* Disable font scaling code without effect.

* Set "Current Time" toolbar item to use MonospacedDigitTextFieldCell.

* Improve SecondsFormatter.

* Merge in SecondsFormatter improvements from Play.

* Move formatter setup into XIB.

* Add CogTests.
These can later be used for integration tests.

* Add SecondsFormatterTests.
Tests are stubbed out.

* Pouring foundation for SecondsFormatterTests.

* Implement -testPositive.

* Replace unsigned with int in SecondsFormatter.

* Implement negative support, tests.

* Rewrite SecondsFormatter in preparation for better readability..

* Rewrite SecondsFormatter for better readability.

* Add negative zero support.

* Improve SecondsFormatter readability.

* Refactor into -stringForTimeInterval: in SecondsFormatter.

* Cleanup.

* Mark TimeField as space-indented.

* Replace custom time formatting code in TimeField with SecondsFormatter.

* Cleanup.

* Improve SecondsFormatter format strings.

* Add internal type for time calculations.

Co-authored-by: Jan Weiß <jan@geheimwerk.de>
2021-05-06 19:50:26 -07:00
Christopher Snowhill
503b4a471c MIDI: Update FluidSynth README 2021-05-06 19:24:34 -07:00
Christopher Snowhill
ea6bed51f1 MIDI: Fix FluidSynth crash on GM reset 2021-05-06 19:23:03 -07:00
Christopher Snowhill
37aa36f9f4 MIDI: Fix FluidSynth device-id setting, which requires unique settings objects 2021-05-06 19:02:25 -07:00
Christopher Snowhill
81aca83940 MIDI: Update FluidSynth to HEAD-9b671b2, with personal changes to implement reset messages to switch drum control and bank select mode 2021-05-06 19:01:50 -07:00
Christopher Snowhill
f9d3a5f9eb MIDI: Fix FluidSynth SysEx code 2021-05-06 14:59:27 -07:00
Christopher Snowhill
1a95c234b2 Update FluidSynth code, changing default gain, and letting it handle SysEx messages on its own 2021-05-06 13:35:24 -07:00
Dzmitry Neviadomski
9c58f67c48 Fix Info button sizing when album art not present. 2021-05-05 02:03:55 +03:00
Dzmitry Neviadomski
66efdfcf1e Roll libsidplayfp 2021-05-04 22:30:10 +03:00
Christopher Snowhill
e8e2fc3164 MIDI: Add SF3 extension to FluidSynth loader 2021-05-03 19:18:55 -07:00
Christopher Snowhill
4cf76dd7e3 MIDI: Replaced BASSMIDI with FluidSynth 2021-05-03 19:18:55 -07:00
Dzmitry Neviadomski
a60d6daed8 Update GitHub Action. 2021-05-02 23:41:56 +03:00
Dzmitry Neviadomski
1e6d0e16f0 Remove remaining signing ids. 2021-05-02 23:18:11 +03:00
Dzmitry Neviadomski
f23cd09875
Merge pull request #145 from losnoco/nevack/githook
Update Git hook
2021-05-02 20:57:14 +03:00
Dzmitry Neviadomski
8857171a78
Update Git hook 2021-05-02 20:50:05 +03:00
Christopher Snowhill
1e97d02384 Cleaned up project files, also removed accidental and remaining team identifiers 2021-05-01 15:43:56 -07:00
Christopher Snowhill
13bd399b31 Clean up most warnings and update some dependencies 2021-04-29 18:16:24 -07:00
Christopher Snowhill
db74506747 Updated AdPlug 2021-04-29 18:12:28 -07:00
Christopher Snowhill
d23860d2d8 Updated VGMStream to r1050-3682-g5b76dc05 2021-04-29 16:16:01 -07:00
Christopher Snowhill
4d7a4ec29d MIDI: No longer call BASS_Free on shutdown, may have been possible to cause a hang on shutdown 2021-04-27 00:19:26 -07:00
Christopher Snowhill
6b1d4e7350 MIDI: Update BASS, BASSMIDI, BASSFLAC, and BASSOpus 2021-04-27 00:18:41 -07:00
Calvin Buckley
ea853109ed Fix info inspector to always display the first item of the current selection, or otherwise the currently playing track, or nothing at all, in that order 2021-04-24 19:25:29 -07:00
Christopher Snowhill
7acfdf774d VGMStream: Fix length reporting and track termination when not looping forever 2021-04-22 23:53:59 -07:00
Christopher Snowhill
d4bfbf9fdc GBA: Revert to stock libmgba 0.9.1. The rips in question are broken and need to be fixed. 2021-04-22 23:53:19 -07:00
Christopher Snowhill
d44558b419 GSF: Update libmgba to version 0.9.1 plus a fix for Metroid: Zero Mission and possibly others 2021-04-22 14:35:43 -07:00
Christopher Snowhill
5c6b145f9a Update playback position 5 times per second instead of once, increasing smoothness of seekbar on shorter tracks, and hopefully solving jitter on some tracks 2021-04-19 23:51:31 -07:00
Christopher Snowhill
edb8b7422d Updated VGMStream to r1050-3677-g76566c8d 2021-04-19 12:13:03 -07:00
Christopher Snowhill
4ea289ba27 MIDI: Reject files with no event data 2021-04-11 17:23:55 -07:00
Christopher Snowhill
2925a37a81 Update libopenmpt to version 0.5.8 2021-04-11 17:23:22 -07:00
Christopher Snowhill
7a0e007d08 Updated VGMStream to r1050-3668-g37cc1229 2021-04-10 16:30:36 -07:00
Christopher Snowhill
e603addc07 TagLib: Add generic APE tag support, for TAK files for now 2021-04-10 16:20:55 -07:00
Christopher Snowhill
9dd8dbe2f3 MIDI: Fix Standard MIDI track truncation issues 2021-04-10 00:22:27 -07:00
Christopher Snowhill
10856e6928 MIDI: Hopefully fix last outstanding Standard MIDI issue, this time with track lengths 2021-04-09 15:05:30 -07:00
Christopher Snowhill
d06eec4ff0 Set allowed extensions for the save picker when saving a playlist 2021-04-09 11:16:12 -07:00
Christopher Snowhill
cadb54b454 Fix shutdown action so it removes the playlist filter before saving the playlist 2021-04-09 11:09:18 -07:00
Christopher Snowhill
d51ca224f5 MIDI: Fix Standard MIDI issues correctly this time 2021-04-08 23:47:49 -07:00
Christopher Snowhill
ee5054e12a MIDI: Changed Standard MIDI processor to deal with even more bad MIDI files 2021-04-08 23:29:39 -07:00
Christopher Snowhill
812dde7fb5 MIDI: Made Standard MIDI processor considerably more lenient when dealing with broken files 2021-04-08 17:48:56 -07:00
Christopher Snowhill
2c20205f8f Fix VGMStream info parser to remove anchors and URL percent encodings from filenames 2021-04-06 16:51:08 -07:00
Christopher Snowhill
ce8a1c230d Fix Playlist Loader so it only attempts to process track info for tracks that need it, and not the entire playlist every time 2021-04-06 16:50:17 -07:00
Christopher Snowhill
282252bfe7 Update libsidplayfp with only minor API changes for upstream 2021-04-06 16:49:16 -07:00
Christopher Snowhill
b32f9d4ac3 libsidplayfp: Fix stereo playback, and implement support for multi-file songs, and fix stereo blending so it applies to the entire output 2021-04-05 14:07:20 -07:00
Dzmitry Neviadomski
f6f81c3083
Add Build passing badge to README.md 2021-04-05 21:51:48 +03:00
Christopher Snowhill
5b1bd5a5ff Package CI build artifact with ditto 2021-04-05 11:35:19 -07:00
Christopher Snowhill
2a7c89f294 Merge branch 'master' of github.com:losnoco/cog 2021-04-05 11:28:35 -07:00
Dzmitry Neviadomski
db698cfd54 Another attemt to fix CI build. 2021-04-05 21:15:39 +03:00
Christopher Snowhill
be441fdf0d Merge branch 'master' of github.com:losnoco/cog 2021-04-05 11:11:01 -07:00
Dzmitry Neviadomski
6e8a64f25c Another attemt to fix CI build. 2021-04-05 21:07:41 +03:00
Dzmitry Neviadomski
1f14e5f76d Another attemt to fix CI build. 2021-04-05 20:47:47 +03:00
Dzmitry Neviadomski
1c19046216 Add pre-commit hook for checking leaked Development Team. 2021-04-05 20:31:25 +03:00
Dzmitry Neviadomski
f1a8934ad9 Update Opus & Ogg targets. 2021-04-05 19:53:30 +03:00
Dzmitry Neviadomski
3bb1f1b437 Remove specification of Workspace in xcodebuild step. 2021-04-05 19:08:19 +03:00
Dzmitry Neviadomski
3097a84e56 Fix sidplayfp version define. 2021-04-05 19:06:46 +03:00
Christopher Snowhill
373ee8d57b Updated VGMStream to r1050-3658-gb5d5d6d6 2021-04-03 14:02:28 -07:00
Christopher Snowhill
09e82030e9 Updated libsidplayfp ref to upstream pull 2021-04-03 13:55:29 -07:00
Christopher Snowhill
f0065d1914 Updated libsidplayfp to version 2.2.0, plus some extras 2021-04-03 02:53:09 -07:00
Christopher Snowhill
2925c2e733 MIDI: Fix Standard MIDI processor to handle edge cases like non-track chunks in the files 2021-03-29 00:33:14 -07:00
Christopher Snowhill
0ecc2d4084
Add developer ID certs to action 2021-03-28 18:38:28 -07:00
Dzmitry Neviadomski
497b7a301d Setup DEVELOPMENT_TEAM for GitHub Action. 2021-03-29 04:21:28 +03:00
Dzmitry Neviadomski
69dec865ff Add GitHub Action to test if project is buildable. 2021-03-29 03:42:20 +03:00
Christopher Snowhill
bdd02c76d3 PSF/PSF2: Set harsh compatibility mode, so emulator behaves more like actual hardware, which fixes a few PSF and PSF2 rips 2021-03-28 12:49:34 -07:00
Christopher Snowhill
d681eb293a Restore libsidplayfp remote URL 2021-03-27 12:15:11 -07:00
Christopher Snowhill
f1e14e1e6e Updated VGMStream to r1050-3650-gce033e53 2021-03-27 12:14:09 -07:00
Christopher Snowhill
32ea54e8f0 Update sidplayfp to latest commit 2021-03-27 12:13:34 -07:00
Christopher Snowhill
81a4d92d72 Updated VGMStream to r1050-3644-gc9e2016f
First new build on an Apple Silicon build machine
2021-03-26 06:03:02 -07:00
Christopher Snowhill
d21aa09771 First commit made while running on Apple Silicon
sidplayfp: Implement ARM NEON accelerated sinc resampler on Apple Silicon, and enable existing MMX accelerated sinc resampler on Intel
2021-03-26 05:56:29 -07:00
Christopher Snowhill
7139f5aa08 Update libopenmpt to version 0.5.7 2021-03-20 14:47:28 -07:00
Christopher Snowhill
9a427cf03c Update libopenmpt to version 0.5.6 2021-03-14 14:55:49 -07:00
Christopher Snowhill
ba7aaec69c M3U and PLS playlist handlers now correctly handle macOS Classic line endings 2021-03-09 23:49:13 -08:00
Christopher Snowhill
ab6429b62b Updated VGMStream to r1050-3618-gfbf7bcaa 2021-03-04 15:32:52 -08:00
Dzmitry Neviadomski
3a387c3a3f Update Copyright year to 2021 with regex. 2021-03-03 23:05:57 +03:00
Dzmitry Neviadomski
e5e9dffe0f Update Mini Player minimum width to lower value. 2021-03-03 22:47:31 +03:00
Christopher Snowhill
094025900d
Merge pull request #124 from losnoco/nevack/floating-mini-window
Add option for Mini Player to appear on top.
2021-03-02 17:07:50 -08:00
Dzmitry Neviadomski
3a3694d78b Add option for Mini Player to appear on top. 2021-03-03 00:04:59 +03:00
Christopher Snowhill
f86f7dc532 Fixup for main branch 2021-02-28 18:48:31 -08:00
Dzmitry Neviadomski
c2425344ac Roll MASShortcut. 2021-02-28 18:48:26 -08:00
Christopher Snowhill
483b8d6647 Don't load metadata for stream URLs 2021-02-28 18:48:21 -08:00
Dzmitry Neviadomski
ac44ae12be Mini window UI fixes.
Fix Toolbar customization panel overlapping window.
Fix minimum size to not exceed screen width.
2021-02-28 18:48:15 -08:00
Christopher Snowhill
0ece64c50b Fix sidplayfp install name base so it runs from the correct location 2021-02-28 18:48:10 -08:00
Christopher Snowhill
6e73220211 Revert "Add siplayfp.framework to Cog target."
This reverts commit eaca38df89.
2021-02-28 18:48:05 -08:00
Dzmitry Neviadomski
219cd937e1 Add siplayfp.framework to Cog target. 2021-02-28 18:47:59 -08:00
Dzmitry Neviadomski
8105b9e2b2 Modernize PlaybackEventController. 2021-02-26 23:01:48 +03:00
Dzmitry Neviadomski
d44d188a4f Add clang-format style for VSCode. 2021-02-26 23:01:25 +03:00
Dzmitry Neviadomski
e4199694a8 Update FFMPEG plugin project settings. 2021-02-26 15:31:35 +03:00
Dzmitry Neviadomski
d1469ebfe4 Sort plugins by name. 2021-02-26 15:17:01 +03:00
Dzmitry Neviadomski
b22a57efa5 Roll Sparkle 1.25.0 2021-02-26 14:57:09 +03:00
Dzmitry Neviadomski
ddacb3a6da Update Release build script. 2021-02-26 14:55:01 +03:00
Christopher Snowhill
e8c6a00d9e Release needs a workaround too 2021-02-25 19:39:02 -08:00
Christopher Snowhill
189a01b97d
Merge pull request #114 from losnoco/nevack/remove-sidplay-residfp-code
Use libsidplayfp GitHub upstream as submodule
2021-02-25 19:30:25 -08:00
Dzmitry Neviadomski
b685f5d5c4 Preprocess Info.plist for sidplayfp Xcode subproject. 2021-02-25 18:37:47 +03:00
Dzmitry Neviadomski
f6a0cdf3c2 Fix warnings in sidplayfp Xcode subprojects. 2021-02-25 18:37:47 +03:00
Dzmitry Neviadomski
0aff2c9567 Add sidplayfp Xcode subproject as dep. 2021-02-25 18:37:39 +03:00
Dzmitry Neviadomski
72702ed1e1 Add libsidplayfp submodule and supporting files. 2021-02-25 18:36:04 +03:00
Dzmitry Neviadomski
71a697c5a4 Remove libsidplayfp external dep. 2021-02-25 18:36:04 +03:00
Christopher Snowhill
59477130bb Get rid of background tag loading, as it never worked properly anyway 2021-02-25 02:42:44 -08:00
Christopher Snowhill
04074f5d74 Fix Core Audio input to report and decode format native bits per sample, and report file bitrate 2021-02-22 20:48:23 -08:00
Christopher Snowhill
9f337dc41c
Merge pull request #111 from losnoco/nevack/build-universal-ffmpeg
Update build scripts for universal ffmpeg.
2021-02-22 19:39:09 -08:00
Christopher Snowhill
54a0930dba
Merge pull request #112 from losnoco/nevack/remove-unused-3rd-party
Remove outdated and unused 3rd Party code.
2021-02-22 13:40:05 -08:00
Dzmitry Neviadomski
3d489aeeb9 Remove outdated and unused 3rd Party code. 2021-02-22 21:47:20 +03:00
Dzmitry Neviadomski
2c241af654 Update build scripts for universal ffmpeg. 2021-02-22 18:41:13 +03:00
Dzmitry Neviadomski
204d63923e Fix build after removing resources. 2021-02-22 11:54:04 +03:00
Dmitry Nevedomsky
6aa9898678
Merge pull request #110 from nevack/nevack/remove-outdated-pngs
Remove unused png resources.
2021-02-22 11:02:18 +03:00
Dzmitry Neviadomski
4b7e6db1f4 Remove unused png resources. 2021-02-22 08:25:02 +03:00
Dzmitry Neviadomski
6fdd11f9a1 Update readme with Screenshots and build hint. 2021-02-21 10:42:02 +03:00
Dzmitry Neviadomski
9761412e87 Update default position for MainWindow. 2021-02-21 01:39:19 +03:00
Dzmitry Neviadomski
604edc8099 Update playback control tooltips. 2021-02-21 01:38:52 +03:00
Dzmitry Neviadomski
85e27e7496 Rework playback shortcuts again. 2021-02-19 08:23:13 +03:00
Dzmitry Neviadomski
97cc1e9845 Remove Apple Remote leftovers. 2021-02-19 07:32:33 +03:00
Dmitry Nevedomsky
da13131952
Merge pull request #106 from losnoco/nevack/toolbar-redesign
Toolbar redesign
2021-02-19 03:17:02 +03:00
Dzmitry Neviadomski
18896dcc3e Rework Titlebar.
Show Album art in info button.
2021-02-19 02:58:57 +03:00
Christopher Snowhill
d856e23a74 Move commit log links back to Github 2021-02-18 15:12:40 -08:00
Dzmitry Neviadomski
b08263159e Show Now Playing bar only when needed.
Fixes #101
Fixes #105
2021-02-19 01:07:05 +03:00
Dzmitry Neviadomski
1ddce2395b Rotate Randomize icon.
Fixes #103
2021-02-14 03:19:07 +03:00
Dzmitry Neviadomski
a07d07c9f9 Fix Mini window restoring.
Fixes #99
2021-02-14 03:10:03 +03:00
Dzmitry Neviadomski
e3ecc30507 Remove duplicated files from compilation target TagLib. 2021-02-13 22:57:03 +03:00
Christopher Snowhill
6ccaed14e9 Update copyright year and convert document to UTF-8 2021-02-10 00:42:26 -08:00
Christopher Snowhill
b16d2114eb
Change Core Audio file handler priority
Now it should take priority for all supported formats, including MP3, so that reported broken file should play properly now. Not fixing FFmpeg outside of FFmpeg, someone can report the file to FFmpeg if they want to.
2021-02-09 18:43:39 -08:00
Christopher Snowhill
ca160e1efe
Remove maxValue default
from mini window position slider. Fixes (#100 )
2021-02-09 18:39:58 -08:00
Christopher Snowhill
0bbdf50c18
Update copyright year (#98) 2021-02-09 18:32:20 -08:00
Dzmitry Neviadomski
a64f5e08e6 Use GitHub issues for reporting feedback. 2021-02-09 03:12:31 +03:00
6fe7c059db
Update bug_report.md 2021-02-07 20:07:50 -03:00
Dzmitry Neviadomski
a6aaeafdca Re-apply patch for replay gain support 2021-02-07 06:50:28 +03:00
Dzmitry Neviadomski
119a7214ef Fix incorrect negative value in Current Time on stop. 2021-02-07 05:37:57 +03:00
Dzmitry Neviadomski
15cbc97040 Adapt to new version of TagLib and read Vorbis Album art. 2021-02-07 04:48:49 +03:00
Dzmitry Neviadomski
cb1e7e9d49 Roll TagLib 1.12.0 2021-02-07 04:48:04 +03:00
Dzmitry Neviadomski
1d84b7b682 Fix loading of cover art from same directory. 2021-02-07 03:54:31 +03:00
Christopher Snowhill
0b88e5f041
Remove development team setting leak 2021-02-06 14:34:08 -08:00
Dzmitry Neviadomski
899152db49 Add ability to change toolbar style.
Fixes #86
2021-02-07 01:15:12 +03:00
Dzmitry Neviadomski
e313cdac14 Reflect playback status in log correctly 2021-02-07 00:39:19 +03:00
Dzmitry Neviadomski
864c56a408 Store AppController<NSApplicationDelegate> in MediaKeysApplication 2021-02-07 00:33:47 +03:00
Dzmitry Neviadomski
5e3ed2af4b Remove ThirdParty SPMediaKeyTap 2021-02-07 00:27:14 +03:00
Dzmitry Neviadomski
d0ee3622ed Use MPRemoteCommandCenter without avaliability checks. 2021-02-07 00:24:45 +03:00
Dzmitry Neviadomski
9840d87127 Convert CogStatus enum to NS_ENUM 2021-02-07 00:22:19 +03:00
2b916704a0 Update issue templates 2021-02-06 06:25:59 -03:00
Christopher Snowhill
583b8f3cb4 Hopefully fix Drag and Drop for everyone 2021-02-06 00:02:55 -08:00
Christopher Snowhill
dce400435e Fix #89 by encoding paths correctly I hope 2021-01-30 19:37:10 -08:00
Christopher Snowhill
5d9cc6faea
Merge pull request #88 from nevack/nevack/inhibit-third-party-warnings
Inhibit ThirdParty libraries warnings and refactor+modernize several classes
2021-01-30 17:46:38 -08:00
Dzmitry Neviadomski
c1da9a66e1 Modernize several classes.
Use modern ObjC syntax.
Use new Pasteboard APIs.
Explicitly declare protocols.
2021-01-31 02:14:08 +03:00
Dzmitry Neviadomski
730276a7e7 Modernize DNDArrayController. 2021-01-28 01:09:09 +03:00
Dzmitry Neviadomski
832fa6dbd0 Even more deprecations fixes. 2021-01-27 05:45:02 +03:00
Dzmitry Neviadomski
a0afe85130 Fix deprecations with replacemnt and reindent touched files. 2021-01-27 05:30:19 +03:00
Dzmitry Neviadomski
70a22e9611 Fix some more warnings. 2021-01-27 05:12:07 +03:00
Dzmitry Neviadomski
64b9764b2e Inhibit ThirdParty libraries build errors.
This helps as to actually see warnings of our code.
2021-01-27 04:31:43 +03:00
Christopher Snowhill
0b09d1567b Updated VGMStream to r1050-3581-g8fd25a33 2021-01-25 14:57:19 -08:00
Christopher Snowhill
1be15d73e3
Merge pull request #84 from nevack/nevack/ui-fixes
Fix Status bar message v-alignment and use monospaced font for Time.
2021-01-25 14:41:24 -08:00
Dzmitry Neviadomski
bebe6cd3e8 Fix Status bar message v-alignment and use monospaced font for Time. 2021-01-26 00:40:10 +03:00
Christopher Snowhill
5677780a82
Merge pull request #82 from nevack/nevack/shortcuts-refactor
Migrate to MASShortcut.
2021-01-24 20:29:47 -08:00
Dzmitry Neviadomski
19dbf4c9f5 Migrate to MASShortcut.
Removed NDHotKey code.
Added ability to restore default shortcuts.
Migrated old user-set shortcuts.
2021-01-25 06:47:09 +03:00
Christopher Snowhill
891576365b
Merge pull request #83 from nevack/nevack/broken-feed-urls-set
Use NSSet for broken feed URL lookup.
2021-01-24 19:30:31 -08:00
Dzmitry Neviadomski
ab88e1b65c Use NSSet for broken feed URL lookup. 2021-01-25 06:23:48 +03:00
Christopher Snowhill
4a7b1099c8
Merge pull request #81 from nevack/nevack/preferences-warnings
Resolve all warnings in Preferences (aka General) target
2021-01-24 17:47:14 -08:00
Dzmitry Neviadomski
0c820a1d1c Copy Preferences.preferencePane in a more straightforward way. 2021-01-25 01:25:56 +03:00
Dzmitry Neviadomski
52b2610324 Rename General target to Preferences to reflect it's real purpose. 2021-01-25 01:20:27 +03:00
Dzmitry Neviadomski
d71030d29b Remove outdated growlView reference in Preferences.xib. 2021-01-25 00:57:01 +03:00
Dzmitry Neviadomski
8fa30d109d Remove dead code after NSPopover migration. 2021-01-10 03:33:21 +03:00
Dzmitry Neviadomski
0df2dc2160 Resolve all warnings for Preferences target. 2021-01-10 03:27:39 +03:00
Christopher Snowhill
826b108429
Merge pull request #77 from nevack/nevack/update-info-inspector
Align Info Inspector with app's MainWindow.
2021-01-09 10:09:58 -08:00
Dzmitry Neviadomski
f7e2d0029d Align Info Inspector with app's MainWindow. 2021-01-09 13:46:24 +03:00
Christopher Snowhill
a8fe9d6a2d
Merge pull request #76 from nevack/nevack/cleanup-mainwindow
Cleanup dead code in MainWindow and AppController.
2021-01-09 01:59:09 -08:00
Dzmitry Neviadomski
84b473f847 Cleanup NSDrawer leftovers from AppController. 2021-01-09 12:47:11 +03:00
Dzmitry Neviadomski
a112440849 Cleanup dead code in MainWindow. 2021-01-09 12:46:18 +03:00
Christopher Snowhill
17dcf4cc9c
Merge pull request #74 from kode54/nevack/miniwindow-revamp
Revamp Mini Window shortcuts.
2021-01-08 01:53:39 -08:00
Dzmitry Neviadomski
78d8c0050c Revamp Mini Window shortcuts.
Fix deprecation warnings.
Set max and min size for content view in code.
2021-01-08 12:15:01 +03:00
Christopher Snowhill
5a1c398291
Merge pull request #72 from nevack/nevack/preferences-revamp
Use SF Symbols in Preferences on Big Sur.
2021-01-07 23:24:44 -08:00
Christopher Snowhill
515216cd43
Merge pull request #73 from nevack/nevack/fix-volume-popover
Fix Volume Slider popover reattaching to window.
2021-01-07 23:24:34 -08:00
Dzmitry Neviadomski
581b9e42b3 Use SF Symbols in Preferences on Big Sur.
And refactoring of Preference Window.
2021-01-08 09:40:21 +03:00
Dzmitry Neviadomski
ddf98f7a3b Fix Volume Slider popover reattaching to window. 2021-01-08 09:35:41 +03:00
Christopher Snowhill
0fdabd55dd
Merge pull request #69 from nevack/nevack/volume-slider-popover
Show Volume slider in NSPopover instead of CGWindow.
2021-01-07 15:36:03 -08:00
Dzmitry Neviadomski
9b9e2d2c42 Show Volume slider in NSPopover instead of CGWindow.
Also perform Haptic feedback when volume slider is at 100%.
2021-01-08 00:35:52 +03:00
Christopher Snowhill
1aa9b5a01c
Merge pull request #61 from nevack/nevack/notifications
Show album art with UserNotification api.
2021-01-06 23:22:15 -08:00
Dzmitry Neviadomski
e16d4e8aa7 Save artwork to jpg instead of png to reduce size. 2021-01-07 08:45:44 +03:00
Christopher Snowhill
c0a349d694
Merge pull request #68 from nevack/nevack/update-mini-window
Update Mini Window toolbar item priority
2021-01-06 21:06:54 -08:00
Christopher Snowhill
1b7948ef9d
Merge pull request #67 from nevack/nevack/update-volume-slider
Update volume slider to use NSPopover.
2021-01-06 21:06:38 -08:00
Dzmitry Neviadomski
bd4e64c029 Do not show iTunes Style option with UserNotification. 2021-01-07 07:44:07 +03:00
Dzmitry Neviadomski
05f66d40f3 Show Album Art with UserNotification. 2021-01-07 07:44:07 +03:00
Dzmitry Neviadomski
52c31c5117 Hide Zoom button for Mini Window.
Also fix 4 deprecation warnings.
2021-01-07 07:41:58 +03:00
Dzmitry Neviadomski
edafc3fe1f Update Main Window toolbar item priority. 2021-01-07 07:41:09 +03:00
Dzmitry Neviadomski
76bdebd058 Update volume slider to use NSPopover. 2021-01-07 06:48:40 +03:00
Christopher Snowhill
1f3d045b62
Merge pull request #66 from nevack/nevack/fix-crash
Fix crash when Quitting without active track set.
2021-01-06 15:23:04 -08:00
Christopher Snowhill
858b22d60b Move new PositionSliderToolbarItem.swift to correct folder 2021-01-06 14:56:04 -08:00
Dzmitry Neviadomski
c192fb5c41 Fix crash when Quitting without active track set. 2021-01-07 01:40:49 +03:00
Christopher Snowhill
42690a8077
Merge pull request #65 from nevack/nevack/update-ogg-vorbis-sdk
Updated Ogg and Vorbis targets Base SDK.
2021-01-06 14:40:48 -08:00
Christopher Snowhill
32d4c73c66
Merge pull request #64 from nevack/nevack/update-toolbar
Update Toolbar items visibility.
2021-01-06 14:39:40 -08:00
Christopher Snowhill
a5f0ee7d68
Remove developer team 2021-01-06 14:39:03 -08:00
Christopher Snowhill
1fce0de175
Merge pull request #63 from JanX2/master
Info.plist improvements
2021-01-06 14:35:32 -08:00
Dzmitry Neviadomski
f503963184 Updated Ogg and Vorbis targets Base SDK.
Targets:
- libogg (static)
- libvorbis (static)
- libvorbisenc (static)
- libvorbisfile (static)
2021-01-07 01:18:40 +03:00
Dzmitry Neviadomski
6a4243128e Update Toolbar items visibility.
Use backported NSSearchToolbarItem to support collapsed state.
Give more priority to Playback controls.
Fix sizing of Playback Slider.
2021-01-07 00:49:14 +03:00
Jan Weiß
10a76e3b39 Info.plist touched by Xcode. 2021-01-06 14:05:34 +01:00
Jan Weiß
a065cd75be Actually fix LSMinimumSystemVersion in Info.plist. 2021-01-06 14:05:06 +01:00
Christopher Snowhill
0a99093af0 Fix status bar bodge so stopping manually doesn't prevent playback for 3 seconds 2021-01-06 02:18:09 -08:00
Christopher Snowhill
41d11bdfa8 Fix one deprecation warning 2021-01-06 02:17:30 -08:00
Christopher Snowhill
2a52dd831a Updated VGMStream to r1050-3548-g64ffe5ea 2021-01-06 01:04:54 -08:00
Christopher Snowhill
d070dffdbe Updated lazyusf2 with fixes from Josh W for cases where some USF rips would cause the internal counter variable to take a full 32 bit loop before producing more audio, having all the appearances of temporarily locking up 2021-01-06 00:52:09 -08:00
Christopher Snowhill
97fee7e486 Add a bodge so playback status bar doesn't pop in and out repeatedly on manual track changes 2021-01-06 00:39:12 -08:00
Christopher Snowhill
002fa3b63e Fix last remaining references to old build target 2021-01-06 00:38:23 -08:00
Christopher Snowhill
23ccae9ce5
Merge pull request #62 from JanX2/master
Second attempt to fix build with other than maintainer’s TeamIDs.
2021-01-06 00:36:11 -08:00
Jan Weiß
a197e82d5e Remove addendum and patch. 2021-01-05 17:25:12 +01:00
Jan Weiß
9fc1605330 Improve Shared.xcconfig. 2021-01-05 17:25:12 +01:00
Jan Weiß
63ed28919b Second attempt to fix build with other than maintainer’s TeamIDs. Worked for me with Xcode 12.3. 2021-01-05 17:25:12 +01:00
Christopher Snowhill
238e6cddf6 Update README and add patch 2020-12-22 02:39:18 -08:00
Christopher Snowhill
dbc51d76f9 Revert PR #60 - Nope, that breaks hardened runtime and signing it myself 2020-12-22 02:11:50 -08:00
Christopher Snowhill
bf33cdb113 Adjusted main window constraints a bit 2020-12-22 00:54:29 -08:00
Christopher Snowhill
f1c45a81ef Updated VGMStream to r1050-3533-g95709ce3 2020-12-22 00:54:29 -08:00
Christopher Snowhill
3a677f5f2e
Merge pull request #60 from JanX2/master
Fix build with other than maintainer’s TeamIDs
2020-12-13 17:47:15 -08:00
Jan Weiß
c305a5f949 Fix build with other than maintainer’s TeamIDs.
This commit removes development team and code signing key/value pairs that slipped through when Xcode applied code signing changes.
2020-12-13 12:01:48 +01:00
Christopher Snowhill
58b6ea5881 Added HMQ extension for HMP format 2020-12-08 19:16:03 -08:00
Christopher Snowhill
4ef5283fa8 Updated VGMStream to r1050-3468-gc3ed1fad 2020-12-04 16:29:46 -08:00
Christopher Snowhill
24231ecdbb Update libopenmpt to version 0.5.4 2020-12-04 16:22:42 -08:00
Christopher Snowhill
b375f06faa Eliminate first parent policy from version count generation, as my little stunt with releasing from the development branch has broken build numbers a bit 2020-11-26 18:39:26 -08:00
Christopher Snowhill
0b47070bd0 Remove erroneous macOS 10.7 deployment target from framework 2020-11-26 18:36:29 -08:00
Christopher Snowhill
4755483961 Touched by Xcode 2020-11-26 18:36:08 -08:00
Christopher Snowhill
d9df3cbb0f
Merge pull request #58 from kode54/ohsir
Merge tracking branch of Big Sur update
2020-11-26 18:28:46 -08:00
Christopher Snowhill
b77f3c97a0
Merge branch 'master' into ohsir 2020-11-26 18:28:29 -08:00
Christopher Snowhill
6635de8601
Create FUNDING.yml 2020-11-26 18:18:15 -08:00
Christopher Snowhill
474dca3967 Update donation menu items 2020-11-24 16:03:49 -08:00
Christopher Snowhill
91b1271ae2 Bump deployment target to 10.13 2020-11-24 15:26:26 -08:00
Christopher Snowhill
7f0d12d515 Update icon_blank template 2020-11-23 23:52:48 -08:00
Christopher Snowhill
6b699ec8cf Updated libbass and company 2020-11-23 23:50:50 -08:00
Christopher Snowhill
6646e01d8a Switched FFmpeg back to static libraries, now that I know I can make Universal static libraries 2020-11-23 23:50:50 -08:00
Christopher Snowhill
837c979962
Merge pull request #56 from dleehr/fix-apple-silicon-flac-crash
Fix apple silicon flac crash
2020-11-23 14:20:24 -08:00
Dan Leehr
850fe390ca Fixes FLAC playback crash on Apple Silicon
- Avoid creating an NSDictionary with NULL context object (https://github.com/kode54/Cog/blob/master/Audio/Chain/InputNode.m#L81 passes NULL as context, so this must be handled in NSDictionary creation
- When calling addObserver, downgrade options from NSNumber * to NSKeyValueObservingOptions (aka NSUInteger)

Not sure why this would be specific to Apple Silicon...
2020-11-23 17:01:25 -05:00
Dan Leehr
1d4a777018 Restore libFLAC plugin on macOS 10.13 and newer 2020-11-23 17:01:25 -05:00
Dan Leehr
cd84ec683e Fix path to icon_blank.icns 2020-11-23 17:01:25 -05:00
Christopher Snowhill
dedeb399a8 - Big Sur phase two
- Restructure main window a bit more
- Remove attempt at SF Symbols icons for now
- Add Now Playing popout to Stacks style main window, tooltip instructs to click to select the current track in playlist
- Disable libFLAC plugin on macOS 10.13 and newer, letting Core Audio handle it instead. Apparently, libFLAC is not really ready for Apple Silicon yet.
2020-11-22 18:16:34 -08:00
Christopher Snowhill
dca9655c62 Fixed toolbar buttons on 10.15 and older, and fixed the Preferences dialog on Big Sur and potentially newer. 2020-11-19 16:24:33 -08:00
Christopher Snowhill
44e7e85a5f Update feed script with new Git URL 2020-11-19 02:57:49 -08:00
Christopher Snowhill
55ebd62eba Updated VGMStream to r1050-3424-gd7bd5a2a 2020-11-19 02:07:36 -08:00
Christopher Snowhill
85907a48d9 Add .ogg extension to Opus plugin 2020-11-19 01:37:50 -08:00
Christopher Snowhill
ee0782efbf Updated libopenmpt to version 0.5.3 2020-11-19 01:35:54 -08:00
Christopher Snowhill
4eb7a3eebf Update VGMStream plugin with new API changes a bit, and now force auto downmixing to 6ch 2020-09-21 22:33:18 -07:00
Christopher Snowhill
bb38853ee9 Updated VGMStream to r1050-3272-g842171b8 2020-09-21 22:22:53 -07:00
Jan Weiß
6a534ad900 Swap keyboard shortcuts for "Playlist > Repeat > Toggle" (now ⌘R) and "Playlist > Show in Finder" (now ⇧⌘R). 2020-09-21 22:00:46 -07:00
Christopher Snowhill
dab78ed74f Updated libopenmpt to version 0.5.2 2020-09-21 21:54:24 -07:00
Christopher Snowhill
640e8b7304 Various architectural changes to make Intel plus Apple Silicon build successfully 2020-09-11 17:08:37 -07:00
Christopher Snowhill
002e16260c Change delpoyment target to 10.9 2020-09-06 21:52:07 -07:00
Christopher Snowhill
0e5013abdd Updated main app icon and badges 2020-09-06 21:47:38 -07:00
Christopher Snowhill
f1712aebe1 Moved to new server 2020-09-05 19:37:59 -07:00
Christopher Snowhill
667af62631 Added arm64 flavors of BASS and company 2020-09-05 19:15:45 -07:00
Christopher Snowhill
9400d93a29
Merge pull request #52 from JanX2/reveal-shortcut-mod
Reveal shortcut mod
2020-08-14 16:13:01 -07:00
Jan Weiß
ee78d9f52b Swap keyboard shortcuts for "Playlist > Repeat > Toggle" (now ⌘R) and "Playlist > Show in Finder" (now ⇧⌘R). 2020-06-30 13:13:25 +02:00
Jan Weiß
0e9f1444f1 °MainMenu.xib" updated by Xcode 11.4 beta. 2020-06-30 13:13:25 +02:00
Christopher Snowhill
0001bd581b Phase one of Big Sur 2020-06-30 01:04:55 -07:00
Christopher Snowhill
3b628c3989 Touched by Xcode 2020-06-07 19:57:15 -07:00
Christopher Snowhill
ebfb7e1207 Updated VGMStream to r1050-3043-g295ffac0 2020-06-07 19:57:02 -07:00
Christopher Snowhill
3cdebc8425 Remove unused framework 2020-06-07 19:08:01 -07:00
Christopher Snowhill
5f04d9250d
Merge pull request #48 from sigmaris/map_jit_backwards_compat
Avoid using MAP_JIT mmap flag on macOS < 10.14
2020-06-07 18:58:55 -07:00
Hugh Cole-Baker
be44237199 Avoid using MAP_JIT mmap flag on macOS < 10.14
If compiled with the macOS 10.14 SDK, MAP_JIT will be defined and passed
as a flag to mmap to allocate memory for the dynarec, but this flag will
cause mmap to fail if running on macOS 10.13 and below; on macOS check
the OS version at runtime, set and cache the appropriate flags for mmap.
2020-06-06 16:05:15 +01:00
Christopher Snowhill
c009a17ccd Updated VGMStream to r1050-2955-g9aaba3b3 2020-05-16 19:01:23 -07:00
Christopher Snowhill
cbe7dcfd4f Add patrons to credits info 2020-05-02 00:58:26 -07:00
Christopher Snowhill
aa434c09bb Project file touched by Xcode 2020-05-02 00:53:26 -07:00
Christopher Snowhill
3b41af0dc2 Update donation menu 2020-05-02 00:53:08 -07:00
Christopher Snowhill
fbbbda70d6 Update copyright year 2020-05-02 00:52:11 -07:00
Christopher Snowhill
04686e999f Updated FLAC to 1.3.3 2020-05-02 00:14:26 -07:00
Christopher Snowhill
da72f8bbdb Updated VGMStream to r1050-2946-g1e583645 2020-05-01 23:57:11 -07:00
Christopher Snowhill
05386bce3a Updated VGMStream to r1050-2932-g546accdf 2020-04-23 23:55:49 -07:00
Christopher Snowhill
bf95a58c02 Updated VGMStream to r1050-2930-g9a1b37d2 2020-04-23 00:09:41 -07:00
Christopher Snowhill
f5c7c4d49a Update midi_processing to latest version, fixing some severe MIDI file handling issues, including Standard MIDI file SysEx and SysEx continuation handling 2020-04-14 02:10:52 -07:00
Christopher Snowhill
798cc4ce43 Updated VGMStream to r1050-2900-g8638b219 2020-04-11 00:41:39 -07:00
Christopher Snowhill
53bfe785bb Disable remote file support for CoreAudio decoder 2020-04-11 00:31:22 -07:00
Christopher Snowhill
4aca4a9c77 - Increase HTTP buffer size to 256KB
- Support a different older flavor of ShoutCAST server
2020-04-11 00:30:27 -07:00
Christopher Snowhill
6c7b7f7213 Maximum volume increased to 800% 2020-04-06 23:30:07 -07:00
Christopher Snowhill
20ef302410 Project files touched by Xcode 2020-04-06 23:29:49 -07:00
Christopher Snowhill
95a326ecd7 Cosmetic reordering of project files 2020-04-06 23:29:34 -07:00
Christopher Snowhill
38b5dd6e3f Updated VGMStream to r1050-2895-g772fe03e 2020-04-06 23:29:07 -07:00
Christopher Snowhill
5fbf722f29 Fix NSF player to support N163 waveform lengths like the real thing 2020-03-24 01:11:02 -07:00
Christopher Snowhill
b7487e2ad2 Clean up audio output code just a bit 2020-03-23 01:46:41 -07:00
Christopher Snowhill
b7596caa44 Fixed WavPack tag reading, by actually enabling it 2020-03-22 00:16:13 -07:00
Christopher Snowhill
9ca13ad471 Updated WavPack decoder to 5.2.0 2020-03-22 00:15:45 -07:00
Christopher Snowhill
3e6d599452 Implement new notification display system, when running on Mojave or newer 2020-03-21 01:51:35 -07:00
Christopher Snowhill
7f3da31b45 Consider URLs as 'internal' source so they don't auto play 2020-03-10 02:17:19 -07:00
Christopher Snowhill
a43ae5fc81 - Redo HTTP buffering mechanism
- Handle HTTP errors better
- Fix handling ShoutCAST servers responding ICY headers
2020-03-10 01:56:59 -07:00
Christopher Snowhill
b37a6f0f0d Attempt to add rewinding to CoreAudio for streamed source files, but it doesn't work, it still fails to play anything from a stream 2020-03-09 00:23:58 -07:00
Christopher Snowhill
18acc7fdd2 Handle HTTP redirection, including preventing circular redirects 2020-03-08 20:13:46 -07:00
Christopher Snowhill
25a030a46c Implement custom reader support in CoreAudio decoder, now supports archives and possibly streams 2020-03-08 20:05:03 -07:00
Christopher Snowhill
117ab53343 Fix multi-plugin cascade to handle non-seeking readers, where disposing of some data while finding an input is okay 2020-03-08 20:04:10 -07:00
Christopher Snowhill
58b435dd88 Disable transport security enforcement to allow NSURLSession to access plain HTTP streams 2020-03-08 20:03:30 -07:00
Christopher Snowhill
6d0166e69b Fix multi-plugin cascade when using non-seeking readers 2020-03-07 16:09:26 -08:00
Christopher Snowhill
443aa05f88 Replace HTTPSource with a new reader based on NSURLSession, which actually does support HTTPS. This portion of the player now requires macOS 10.9. 2020-03-07 16:08:47 -08:00
Christopher Snowhill
17bb70e729 Fix macOS version detection to use a proper API 2020-03-05 20:34:15 -08:00
Christopher Snowhill
fc2e6df38f Full screen mode Now Playing Bar now has more appropriate colors in Dark Mode 2020-03-05 20:31:57 -08:00
Christopher Snowhill
e44aad7101 Project file touched by Xcode 2020-03-05 20:31:23 -08:00
Christopher Snowhill
375ff42d0a Updated libmgba 2020-03-05 19:57:44 -08:00
Christopher Snowhill
9dd4f68049 Updated VGMStream to r1050-2834-gc40d364e 2020-03-01 18:36:55 -08:00
Christopher Snowhill
f64a67941a Update update_feed.rb script for new version number style 2020-03-01 17:59:23 -08:00
Christopher Snowhill
4bc7aaf16a Update Sparkle to version 1.23.0 2020-03-01 15:10:15 -08:00
Christopher Snowhill
5b914831d2 Change version numbering algorithm 2020-03-01 15:09:30 -08:00
Christopher Snowhill
fedc271b8c Move a few submodules, update libsidplayfp 2020-02-29 17:49:38 -08:00
Christopher Snowhill
6a17d6426e Switch to Sparkle binaries. Currently trying 1.22.0. 2020-02-29 17:47:07 -08:00
Christopher Snowhill
23c25a6dff Removed Sparkle as a submodule 2020-02-29 17:40:18 -08:00
Christopher Snowhill
b7eb48e322 Fix bundle identifier for libAdPlug 2020-02-28 23:45:35 -08:00
Christopher Snowhill
2c988f5be7 Fix execute permission flags on several files 2020-02-28 23:42:48 -08:00
Christopher Snowhill
0fb02ae7ed Update Info.plist for EdDSA signing 2020-02-28 23:22:53 -08:00
Christopher Snowhill
ed5e43d9d4 Downgraded Sparkle to 1.23.0 2020-02-28 20:28:18 -08:00
Christopher Snowhill
003ba7990e Update commit log location 2020-02-28 01:07:48 -08:00
Christopher Snowhill
3e754aadd0 Updated VGMStream to r1050-2819-gcec5b596 2020-02-28 01:05:33 -08:00
Christopher Snowhill
d05ada5d0a Disable MPRemoteCommandCenter unless on Mojave or newer 2020-02-28 00:40:29 -08:00
Christopher Snowhill
004c53962a Updated VGMStream to r1050-2812-g24e9d177 2020-02-23 00:17:33 -08:00
Christopher Snowhill
fbe9283835 Fix libatrac9 loading from correct location in release builds 2020-02-22 23:44:12 -08:00
Christopher Snowhill
0f543a1b52 Guard background file info retrieval to prevent it in case only a single entry was added 2020-02-17 19:50:32 -08:00
Christopher Snowhill
7308aa5f7b Fall back on non-container file parsing, since VGMStream is too greedy with its extension list 2020-02-17 19:50:32 -08:00
Christopher Snowhill
1bc4ad85d2 Fix PSF1 playback for Dragon Ball: Final Bout, Title Screen 2020-02-17 19:50:32 -08:00
Christopher Snowhill
6374a5669b
Merge pull request #40 from JanX2/fix-device-selection
Fix device selection
2020-02-17 19:46:25 -08:00
Christopher Snowhill
2bdd7f5b90
Merge pull request #39 from JanX2/oss-dev-team-fix
Remove DevelopmentTeam that slipped through.
2020-02-17 16:45:26 -08:00
Jan Weiß
da775ce8a6 Clean up output device code. 2020-02-17 18:20:48 +01:00
Jan Weiß
f01915ed80 Project touched by Xcode. 2020-02-17 17:06:48 +01:00
Jan Weiß
4f9c58ec4a Remove DevelopmentTeam that slipped through. 2020-02-17 13:47:16 +01:00
Christopher Snowhill
8bc6396918 Fix local signing issues 2020-02-13 17:45:11 -08:00
Christopher Snowhill
c2278b49be Remove unused variable from SID decoder 2020-02-13 14:42:57 -08:00
Christopher Snowhill
765cb5e890 Usual Xcode update mess 2020-02-13 01:41:21 -08:00
Christopher Snowhill
0e4694ba67 Updated libsidplayfp to version 2.0.1 2020-02-13 01:29:08 -08:00
Christopher Snowhill
505325e309
Merge pull request #38 from JanX2/output-handling
Output handling
2020-02-12 14:19:56 -08:00
Jan Weiß
b22c5964e4 Improve output handling, 2.
Fix issues with above.
2020-02-01 14:44:07 +01:00
Jan Weiß
57ebc65ba0 Add missing newlines. 2020-02-01 14:00:41 +01:00
Jan Weiß
97ed738846 Improve output handling. 2020-02-01 14:00:41 +01:00
Christopher Snowhill
485b81fe04 Updated VGMStream to r1050-2726-g94dac3ec 2019-12-19 17:30:50 -08:00
Christopher Snowhill
37b75bf6e7 Fix resource leak with VGMStream container parser, and serialize metadata caching from there as well 2019-12-19 17:12:09 -08:00
Christopher Snowhill
072c4346cf Fix album shuffle again 2019-12-15 18:12:11 -08:00
Christopher Snowhill
61c6cf3285 Hopefully fixed metadata parsing for newly added tracks showing up in notifications 2019-12-05 19:04:46 -08:00
Christopher Snowhill
90ac083705 Updated VGMStream to r1050-2696-g0a04a738 2019-12-05 18:43:12 -08:00
Christopher Snowhill
8e9f8237e3 Fix potential error with SID decoder 2019-12-05 18:13:52 -08:00
Christopher Snowhill
86681e9726 Implemented support for VGMStream external !tags.m3u metadata playlists 2019-11-23 20:36:57 -08:00
Christopher Snowhill
319eb84744 Updated VGMStream to r1050-2579-gcce259d4-72-g2ac2c0ce 2019-11-23 20:34:20 -08:00
Christopher Snowhill
b6ed264b32 Updated VGMStream to r1050-2637-gd871302c 2019-11-17 16:19:54 -08:00
Christopher Snowhill
5422338d58 Now supports reading playlists from remote paths 2019-11-17 14:44:47 -08:00
Christopher Snowhill
fa6c02d3e8 Handle relative redirects without crashing, and fix URLs that require trailing slash on path 2019-11-16 15:25:01 -08:00
Christopher Snowhill
4e2b6ea9d8 Automated changes by resource editor 2019-11-16 15:24:15 -08:00
Christopher Snowhill
eba116d92e Replace Feedback submission dialog with link to special contact form 2019-11-16 14:49:30 -08:00
Christopher Snowhill
6847f1bcbf Add MediaPlayer stop command and correctly handle return values for all MediaPlayer remote events 2019-11-14 19:24:13 -08:00
Christopher Snowhill
2476f8827d Hopefully fix compatibility with systems older than 10.12.1 2019-11-14 19:16:43 -08:00
Christopher Snowhill
09777d4554 Implemented support for MediaPlayer framework, which fixes media key support on newer systems, and also media info reporting 2019-11-13 19:13:59 -08:00
Christopher Snowhill
9d8551852b Updated VGMStream to r1050-2625-g02efa7d7 2019-11-11 14:02:50 -08:00
Christopher Snowhill
0a9c7693d4 Updated VGMStream to r1050-2622-g72b9f540 2019-11-11 00:25:59 -08:00
Christopher Snowhill
258a88464a Fix VGM metadata and properties reading 2019-11-08 15:05:21 -08:00
Christopher Snowhill
cb8fb9ce87 Fix VGM parsing so it doesn't hit the other two registered VGM container handlers 2019-11-08 15:04:43 -08:00
Christopher Snowhill
5c85c2a1b9 Fix handling invalid archive paths 2019-11-08 15:03:45 -08:00
Christopher Snowhill
4c955ef806 Simplify metadata loader 2019-11-08 15:03:26 -08:00
484dd23bf5 Update .gitlab-ci.yml 2019-11-06 05:03:31 +00:00
6406d0cfe3 Update .gitlab-ci.yml 2019-11-06 04:55:32 +00:00
93daab4317 Update .gitlab-ci.yml 2019-11-06 04:53:55 +00:00
0112e15dbe Update .gitlab-ci.yml 2019-11-06 04:52:14 +00:00
d93e23cae1 Update .gitlab-ci.yml 2019-11-06 04:45:27 +00:00
0db9f9bb1e Update .gitlab-ci.yml 2019-11-06 04:43:27 +00:00
8b6154f64b Add CI 2019-11-06 04:39:37 +00:00
Christopher Snowhill
754b5f1268 Updated mGBA 2019-10-30 21:50:45 -07:00
Christopher Snowhill
bb974414df Updated VGMStream to r1050-2581-g0e9686ff 2019-10-30 17:33:42 -07:00
Christopher Snowhill
91e6511427 Updated libopenmpt to version 0.4.10 2019-10-30 17:33:03 -07:00
Christopher Snowhill
24c130ae0b Updated VGMStream to r1050-2579-gcce259d4 2019-10-27 19:33:43 -07:00
Christopher Snowhill
38d1dee848 Fixed handling of Unix/macOS generated ZIP archives 2019-10-24 17:34:02 -07:00
Christopher Snowhill
dbaf952429 Updated libopenmpt to version 0.4.9 2019-10-24 17:33:28 -07:00
Christopher Snowhill
2ad9584fb2 Rejigger shuffle list generator for albums mode, to insert the current album at the start of the list, starting from the current track 2019-10-24 17:18:51 -07:00
Christopher Snowhill
55564f2991
Merge pull request #31 from JanX2/file-encodings
File encodings
2019-10-22 14:53:43 -07:00
Jan Weiß
105b0f26bb Improve file encoding detection. 2019-10-22 18:19:15 +02:00
Jan Weiß
f94226bcf2 Fix file encoding. 2019-10-22 18:19:15 +02:00
Christopher Snowhill
242c0b9476 Updated VGMStream to r1050-2574-g246222dd 2019-10-20 17:24:44 -07:00
Christopher Snowhill
163a75f566
Merge pull request #30 from JanX2/oss-dev-team
OSS dev team improvements
2019-10-19 14:18:27 -07:00
Jan Weiß
f5edb6ae71 Added unversioned TeamID infrastruture.
This is described in detail in the file "Shared.xcconfig".
2019-10-19 18:11:56 +02:00
Christopher Snowhill
389a701553 Implemented new VGMStream properties and metadata caching, which keeps file smashing under control, which stops Hardened Runtime from crashing on us 2019-10-18 20:21:27 -07:00
Christopher Snowhill
9be094328c Updated VGMStream to r1050-2553-gee3e1700 2019-10-18 15:44:13 -07:00
Christopher Snowhill
0f93b0c7bc Updated VGMStream to r1050-2552-g2b1de051 2019-10-15 19:56:09 -07:00
Christopher Snowhill
a1ec4dba40 Updated FFmpeg 2019-10-15 19:15:52 -07:00
Christopher Snowhill
52a63dc5bc Update update feed script 2019-10-15 15:03:03 -07:00
Christopher Snowhill
a23085082a Switch back to lazyusf2, and enable JIT entitlement for it 2019-10-15 14:32:18 -07:00
Christopher Snowhill
65c75a26e5 Enable skip-install for several frameworks, so they don't get 'installed' when archiving the project 2019-10-13 00:49:26 -07:00
Christopher Snowhill
c8f91c5092 Implemented album shuffle mode, which somehow wasn't implemented at all 2019-10-12 18:27:02 -07:00
Christopher Snowhill
c53c048d59 Add missing files for OpenMPT that were excluded by .gitignore 2019-10-10 15:53:22 -07:00
Christopher Snowhill
9a47c0ebe9 - Remove obsolete Growl framework
- Update BASS and friends to latest versions
- Remove unused unmo3 library
- Add entitlements to Hardened Runtime for unsigned plugins (for
  AU MIDI playback), and for executable memory use (for the USF
  recompiler)

- TODO: Replace Growl branding with generic notification icon
2019-10-10 15:47:46 -07:00
Christopher Snowhill
14c6ce431a Updated VGMStream to r1050-2526-g8b6b5b9e 2019-10-05 00:44:22 -07:00
Christopher Snowhill
fd7ab684c2 Updates for modern Xcode 2019-10-05 00:12:36 -07:00
Christopher Snowhill
1dceedaa55 Updated VGMStream to r1050-2361-ga2d54810 2019-07-12 17:02:28 -07:00
Christopher Snowhill
45accf38ae Updated VGMStream to r1050-2359-ge1184142 2019-07-07 15:49:12 -07:00
Christopher Snowhill
ff35f6c3cf Updated VGMStream to r1050-2349-g5fe83c0c 2019-07-07 00:41:14 -07:00
Christopher Snowhill
b5b4eaf99d Fix AdPlug fileprovider to handle URL fragments properly. 2019-07-07 00:38:19 -07:00
Christopher Snowhill
c1a45135b3 Remove unnecessary cleanup code that impeded cases where multiple decoders could handle a single file type. 2019-07-07 00:37:56 -07:00
Christopher Snowhill
d9d145007e Whoops. Minor fix so it compiles. 2019-07-07 00:31:59 -07:00
Christopher Snowhill
7c762da573 Minor compile fix for VGMStream 2019-07-02 16:55:16 -07:00
Christopher Snowhill
050eef7225 Updated to latest Xcode 2019-07-02 16:37:17 -07:00
Christopher Snowhill
7657eb4971 Updated VGMStream to r1050-2345-g1d28e0f5 2019-07-02 15:54:31 -07:00
Christopher Snowhill
73b7f3651f Merge branch 'master' of github.com:kode54/Cog 2019-06-30 15:47:03 -07:00
Christopher Snowhill
06426e4b60 Updated VGMStream to r1050-2327-ge003e2c2 2019-06-30 15:45:32 -07:00
Christopher Snowhill
8502bf999d Fix feed updater script to upload the HTML change logs, and remove signature v2 override 2019-06-30 15:45:32 -07:00
Christopher Snowhill
e0488aa31d Remove Media Keys warning dialog, let user discover why their global hotkeys aren't working on their own if they aren't the type to complain about features that have been in since the beginning. 2019-06-30 15:45:32 -07:00
Christopher Snowhill
87078bf10d Updated VGMStream to r1050-2323-g2e1739e6 2019-06-30 15:45:32 -07:00
Christopher Snowhill
65d553a45c Updated libopenmpt to version 0.4.5 2019-06-30 15:45:32 -07:00
Chris Moeller
947ec7f691 Updated libopenmpt to version 0.4.3 2019-06-30 15:45:31 -07:00
Chris Moeller
d484ed47e0 Updated VGMStream to r1050-2066-g3dc52c5f 2019-06-30 15:45:31 -07:00
Chris Moeller
e395358a58 Minor automatic project change 2019-06-30 15:45:31 -07:00
Chris Moeller
8d724110a6 Updated libopenmpt to version 0.4.2 2019-06-30 15:45:31 -07:00
Chris Moeller
363b05afb1 Updated visible copyright year. 2019-06-30 15:45:31 -07:00
Chris Moeller
95141cab76 Updated VMStream to r1050-2028-gac28ccc5 2019-06-30 15:45:31 -07:00
Christopher Snowhill
23ab4b3f86 Updated VGMStream to r1050-2327-ge003e2c2 2019-06-21 20:44:35 -07:00
Christopher Snowhill
cbbd5769d8 Fix feed updater script to upload the HTML change logs, and remove signature v2 override 2019-06-20 23:34:52 -07:00
Christopher Snowhill
62c4e71227 Remove Media Keys warning dialog, let user discover why their global hotkeys aren't working on their own if they aren't the type to complain about features that have been in since the beginning. 2019-06-20 21:04:19 -07:00
Christopher Snowhill
412a094b94 Updated VGMStream to r1050-2323-g2e1739e6 2019-06-20 20:57:32 -07:00
Christopher Snowhill
a6b0e0e8ae Updated libopenmpt to version 0.4.5 2019-06-20 20:17:10 -07:00
Chris Moeller
c5001ddf96 Updated libopenmpt to version 0.4.3 2019-02-12 00:07:17 -08:00
Chris Moeller
e76c1966c6 Updated VGMStream to r1050-2066-g3dc52c5f 2019-02-12 00:05:35 -08:00
Chris Moeller
451e508939 Minor automatic project change 2019-01-23 18:26:37 -08:00
Chris Moeller
d1e4abf78c Updated libopenmpt to version 0.4.2 2019-01-23 18:26:37 -08:00
Chris Moeller
9431a11028 Updated visible copyright year. 2019-01-23 18:26:37 -08:00
Chris Moeller
05de1e5033 Updated VMStream to r1050-2028-gac28ccc5 2019-01-23 18:26:24 -08:00
Chris Moeller
4d18505da5 Updated VGMStream to r1050-1973-g34f962eb 2019-01-06 01:34:00 -08:00
Chris Moeller
18c22cd6b2 Updated VGMStream to r1050-1973-g34f962eb 2019-01-06 01:34:00 -08:00
Chris Moeller
4f828c91b0 Updated mGBA 2019-01-04 19:17:51 -08:00
Chris Moeller
d5b560de06 Updated mGBA 2019-01-04 19:17:51 -08:00
Chris Moeller
fecb53a55a Updated VGMStream to r1050-1964-g9346ae50 2019-01-04 19:15:04 -08:00
Chris Moeller
3a93a0083c Updated VGMStream to r1050-1964-g9346ae50 2019-01-04 19:15:04 -08:00
Chris Moeller
66302216dc Fix File source to not remove text after hash marks, as NSURL does that for us when we use the path property. 2019-01-04 18:30:45 -08:00
Chris Moeller
16d0d9f5cc Fix File source to not remove text after hash marks, as NSURL does that for us when we use the path property. 2019-01-04 18:30:45 -08:00
Chris Moeller
0d656a59ae Updated Sparkle 2019-01-04 18:29:41 -08:00
Chris Moeller
2ec3e0940a Updated Sparkle 2019-01-04 18:29:41 -08:00
Christopher Snowhill
88bc5f3006 Fix feed updater script to point commit links to new location. 2018-09-28 01:22:05 +00:00
Christopher Snowhill
39db4a0726 Fix feed updater script to point commit links to new location. 2018-09-28 01:22:05 +00:00
Christopher Snowhill
fdab126cc6 Implement spacebar for play/pause and enter for restart current track for the mini window, and implement left/right arrows for seeking forward and backward for both the mini window and the main window playlist view. 2018-09-26 20:32:23 -07:00
Christopher Snowhill
39bc8df77c Implement spacebar for play/pause and enter for restart current track for the mini window, and implement left/right arrows for seeking forward and backward for both the mini window and the main window playlist view. 2018-09-26 20:32:23 -07:00
Christopher Snowhill
4efb2f48fb Updated VGMStream to r1050-1726-g5b99d40c. 2018-09-26 19:46:37 -07:00
Christopher Snowhill
2a5221da25 Updated VGMStream to r1050-1726-g5b99d40c. 2018-09-26 19:46:37 -07:00
Christopher Snowhill
0ffe3b0aad Add patch against unmodified VGMStream. 2018-09-26 16:35:22 -07:00
Christopher Snowhill
46e5b89a8b Add patch against unmodified VGMStream. 2018-09-26 16:35:22 -07:00
Christopher Snowhill
dec3e27406 Updated libopenmpt to version 0.3.12. 2018-09-26 16:00:05 -07:00
Christopher Snowhill
63be0c6270 Updated libopenmpt to version 0.3.12. 2018-09-26 16:00:05 -07:00
Christopher Snowhill
7499edd8ca Add HTTPS scheme to HTTP source plugin. 2018-09-23 16:45:03 -07:00
Christopher Snowhill
eda1c9674a Add HTTPS scheme to HTTP source plugin. 2018-09-23 16:45:03 -07:00
Christopher Snowhill
be2316163e Add a safety check for attempting to add unsupported URLs. 2018-09-23 16:44:44 -07:00
Christopher Snowhill
6eeb8a60da Add a safety check for attempting to add unsupported URLs. 2018-09-23 16:44:44 -07:00
Christopher Snowhill
f01cfdb4fd Fix playlist entry to return 0 length instead of NaN when metadata hasn't loaded yet. 2018-09-22 03:11:13 -07:00
Christopher Snowhill
505b8c3140 Fix playlist entry to return 0 length instead of NaN when metadata hasn't loaded yet. 2018-09-22 03:11:13 -07:00
Christopher Snowhill
9866c24b9f Fix refreshing table values when adding tracks to the playlist. 2018-09-22 03:10:44 -07:00
Christopher Snowhill
d9529d04a8 Fix refreshing table values when adding tracks to the playlist. 2018-09-22 03:10:44 -07:00
Christopher Snowhill
ae555ee622 Maintenance edits. 2018-09-22 03:10:08 -07:00
Christopher Snowhill
6a978b8847 Maintenance edits. 2018-09-22 03:10:08 -07:00
Christopher Snowhill
3ae2d94b77 Fix tooltip background color on Mojave Dark Mode. 2018-09-22 02:14:44 -07:00
Christopher Snowhill
0b5bd66c0d Fix tooltip background color on Mojave Dark Mode. 2018-09-22 02:14:44 -07:00
Christopher Snowhill
5d81588d7b Updated Sparkle. 2018-09-22 02:09:53 -07:00
Christopher Snowhill
833f4d32b0 Updated Sparkle. 2018-09-22 02:09:53 -07:00
Christopher Snowhill
1b1fee1cef .gitmodules edited online with Bitbucket 2018-08-16 22:35:53 +00:00
Christopher Snowhill
176d7aa0ba .gitmodules edited online with Bitbucket 2018-08-16 22:35:53 +00:00
Christopher Snowhill
b30a8f213f Fix external M3U decimal index handling. 2018-07-22 02:07:19 -07:00
Christopher Snowhill
e59a9e1ed9 Fix external M3U decimal index handling. 2018-07-22 02:07:19 -07:00
Christopher Snowhill
d3b6e474da Sorted source file list. 2018-07-22 02:06:54 -07:00
Christopher Snowhill
03eac4619f Sorted source file list. 2018-07-22 02:06:54 -07:00
Christopher Snowhill
6f55e6710a Tidy up playlist info loader a bit. 2018-07-22 02:00:30 -07:00
Christopher Snowhill
0513639842 Tidy up playlist info loader a bit. 2018-07-22 02:00:30 -07:00
Christopher Snowhill
0dc91a96ec Fix string resources encoding. Fix runtime path for Sparkle framework. 2018-07-22 02:00:10 -07:00
Christopher Snowhill
fd61d465f7 Fix string resources encoding. Fix runtime path for Sparkle framework. 2018-07-22 02:00:10 -07:00
Christopher Snowhill
67df1e8e8a Fix encoding of strings resources. 2018-07-22 01:58:57 -07:00
Christopher Snowhill
6980e7b4e9 Fix encoding of strings resources. 2018-07-22 01:58:57 -07:00
Christopher Snowhill
46c2ea8f11 Updated BASS libraries. 2018-07-21 23:45:49 -07:00
Christopher Snowhill
8cbd0fc49c Updated BASS libraries. 2018-07-21 23:45:49 -07:00
Christopher Snowhill
fa1efd1391 Updated VGMStream to r1050-1417-g60615e6d. 2018-07-19 20:19:14 -07:00
Christopher Snowhill
c1efdb0a6e Updated VGMStream to r1050-1417-g60615e6d. 2018-07-19 20:19:14 -07:00
Christopher Snowhill
fa52c36881 VGMStream plugin correctly fades channel counts other than stereo. 2018-07-17 23:34:25 -07:00
Christopher Snowhill
b3eb934a38 VGMStream plugin correctly fades channel counts other than stereo. 2018-07-17 23:34:25 -07:00
Christopher Snowhill
211773c714 Fix decoder so it ends properly on non-looped files when Repeat One is enabled. 2018-07-17 18:09:59 -07:00
Christopher Snowhill
5c25e3b071 Fix decoder so it ends properly on non-looped files when Repeat One is enabled. 2018-07-17 18:09:59 -07:00
Christopher Snowhill
6661605ea0 Updated VGMStream to r1050-1399-gee07eaee. 2018-07-17 18:09:27 -07:00
Christopher Snowhill
6f59d10162 Updated VGMStream to r1050-1399-gee07eaee. 2018-07-17 18:09:27 -07:00
Christopher Snowhill
f58db82054 Updated VGMStream to r1050-1395-g454488b5. 2018-07-15 18:40:01 -07:00
Christopher Snowhill
0742206f53 Updated VGMStream to r1050-1395-g454488b5. 2018-07-15 18:40:01 -07:00
Christopher Snowhill
a6efe31256 Updated VGMStream to r1050-1391-g4ed16da3. 2018-07-14 18:36:08 -07:00
Christopher Snowhill
e62c04204a Updated VGMStream to r1050-1391-g4ed16da3. 2018-07-14 18:36:08 -07:00
Christopher Snowhill
ccf4b1506b Replace Sparkle with plain upstream version. 2018-07-12 02:14:36 -07:00
Christopher Snowhill
e387ab7615 Replace Sparkle with plain upstream version. 2018-07-12 02:14:36 -07:00
Christopher Snowhill
dc5186ceac Normalized some source formatting. 2018-07-12 02:05:53 -07:00
Christopher Snowhill
ab6f6ad568 Normalized some source formatting. 2018-07-12 02:05:53 -07:00
Christopher Snowhill
88079f6041 Replaced lazyusf2 with more compatible lazyusf1, and updated its timing code significantly. 2018-07-12 00:13:30 -07:00
Christopher Snowhill
951b2e6c7c Replaced lazyusf2 with more compatible lazyusf1, and updated its timing code significantly. 2018-07-12 00:13:30 -07:00
Christopher Snowhill
8859e9a83c Import original LazyUSF into code base, for debugging and comparison. 2018-07-11 19:01:38 -07:00
Christopher Snowhill
b1e67366d0 Import original LazyUSF into code base, for debugging and comparison. 2018-07-11 19:01:38 -07:00
Christopher Snowhill
84dd41c466 Fix Preferences resources. 2018-06-29 14:02:45 -07:00
Christopher Snowhill
31d47715d1 Fix Preferences resources. 2018-06-29 14:02:45 -07:00
Christopher Snowhill
9fb1381a9a Don't intercept mute or volume control keys. 2018-06-28 16:55:59 -07:00
Christopher Snowhill
993b5af6eb Don't intercept mute or volume control keys. 2018-06-28 16:55:59 -07:00
Christopher Snowhill
bfc63d58b7 Update post build script. 2018-06-28 05:10:27 -07:00
Christopher Snowhill
aa3a4d71cc Update post build script. 2018-06-28 05:10:27 -07:00
Christopher Snowhill
f1fa644738 Disable quiet mode in build script. 2018-06-28 05:10:04 -07:00
Christopher Snowhill
1dfc270d20 Disable quiet mode in build script. 2018-06-28 05:10:04 -07:00
Christopher Snowhill
f8fe7198c1 Misc. changes from simply opening the project file. 2018-06-28 05:04:32 -07:00
Christopher Snowhill
c5918c9aa2 Misc. changes from simply opening the project file. 2018-06-28 05:04:32 -07:00
Christopher Snowhill
9606567b03 Fix media key hook for Mojave. 2018-06-28 05:04:15 -07:00
Christopher Snowhill
a71b2b2f65 Fix media key hook for Mojave. 2018-06-28 05:04:15 -07:00
Christopher Snowhill
6a0ef6cc03 Update copyright date. 2018-06-28 05:03:35 -07:00
Christopher Snowhill
4234a614b6 Update copyright date. 2018-06-28 05:03:35 -07:00
Christopher Snowhill
be0b6adb78 Updates for new build system. 2018-06-28 04:03:37 -07:00
Christopher Snowhill
67495009ff Updates for new build system. 2018-06-28 04:03:37 -07:00
Christopher Snowhill
37a8e4ea3a Hopefully implemented a proper workaround for new Mojave permissions required for the Media Key event hook. We shouldn't crash any more. 2018-06-27 20:50:26 -07:00
Christopher Snowhill
6e6648624d Hopefully implemented a proper workaround for new Mojave permissions required for the Media Key event hook. We shouldn't crash any more. 2018-06-27 20:50:26 -07:00
Christopher Snowhill
8dce830f84 Update README.md. Add note about submodules. 2018-06-20 17:20:36 -07:00
Christopher Snowhill
a7eee36cde Update README.md. Add note about submodules. 2018-06-20 17:20:36 -07:00
Christopher Snowhill
7cfcd87cf5 Only include OpenMPT subsongs if they're 10 seconds or longer. 2018-06-18 19:06:16 -07:00
Christopher Snowhill
923440b16b Only include OpenMPT subsongs if they're 10 seconds or longer. 2018-06-18 19:06:16 -07:00
Christopher Snowhill
75f0e677a8 Updated VGMStream to r1050-1355-g005c5556. 2018-06-18 18:19:23 -07:00
Christopher Snowhill
854e29c29c Updated VGMStream to r1050-1355-g005c5556. 2018-06-18 18:19:23 -07:00
Christopher Snowhill
489c329a21 Update libopenmpt to version 0.3.10. 2018-06-18 18:08:02 -07:00
Christopher Snowhill
56e760f3b3 Update libopenmpt to version 0.3.10. 2018-06-18 18:08:02 -07:00
Christopher Snowhill
2b6248dc75 More descriptions that are suddenly mandatory\! 2018-06-09 19:42:28 -07:00
Christopher Snowhill
c7a7f56511 More descriptions that are suddenly mandatory\! 2018-06-09 19:42:28 -07:00
Christopher Snowhill
315b0bdd5c Add nonsense usage descriptions to Info.plist for a bunch of things that the user is unlikely to ever do with the application. 2018-06-09 19:32:47 -07:00
Christopher Snowhill
3b4709bf28 Add nonsense usage descriptions to Info.plist for a bunch of things that the user is unlikely to ever do with the application. 2018-06-09 19:32:47 -07:00
Christopher Snowhill
141b4fcbf4 Disable media key tap on System Preferences, so we don't interfere with security permission controls. 2018-06-09 19:22:52 -07:00
Christopher Snowhill
a9eb674252 Disable media key tap on System Preferences, so we don't interfere with security permission controls. 2018-06-09 19:22:52 -07:00
Christopher Snowhill
18176782e7 Update SPMediaKeyTap to a more recent version. 2018-06-09 19:22:04 -07:00
Christopher Snowhill
f0c7c0b777 Update SPMediaKeyTap to a more recent version. 2018-06-09 19:22:04 -07:00
Christopher Snowhill
a429025dc2 Updated mGBA GSF player core. 2018-06-04 18:08:36 -07:00
Christopher Snowhill
268a293a7a Updated mGBA GSF player core. 2018-06-04 18:08:36 -07:00
Christopher Snowhill
53fa8e2a1e Apply Xcode's suggested changes to project files. 2018-06-04 00:13:55 -07:00
Christopher Snowhill
bcf839efd1 Apply Xcode's suggested changes to project files. 2018-06-04 00:13:55 -07:00
Christopher Snowhill
61017eea8a Updated VGMStream to r1050-1335-g25479155. 2018-06-03 18:51:00 -07:00
Christopher Snowhill
a767189657 Updated VGMStream to r1050-1335-g25479155. 2018-06-03 18:51:00 -07:00
Christopher Snowhill
4ebde0d584 No longer send '(null)' notifications for files missing artist and/or album tags. 2018-06-03 18:39:07 -07:00
Christopher Snowhill
3901305105 No longer send '(null)' notifications for files missing artist and/or album tags. 2018-06-03 18:39:07 -07:00
Christopher Snowhill
fdf3ae9b29 Correctly invalidate playlist view's data when background metadata loader completes. 2018-05-23 00:34:22 -07:00
Christopher Snowhill
d14d69e3c4 Correctly invalidate playlist view's data when background metadata loader completes. 2018-05-23 00:34:22 -07:00
Christopher Snowhill
2a974d6704 Fix total time display on startup, when all metadata is correctly loaded. 2018-05-23 00:32:47 -07:00
Christopher Snowhill
3b8e498e7f Fix total time display on startup, when all metadata is correctly loaded. 2018-05-23 00:32:47 -07:00
Christopher Snowhill
9b8f3a6ad2 Fix linkage errors due to inline missing 'static'. 2018-05-22 01:04:58 -07:00
Christopher Snowhill
fa648bdc44 Fix linkage errors due to inline missing 'static'. 2018-05-22 01:04:58 -07:00
Christopher Snowhill
be53a3dcd8 Updated Highly Quixotic to include new, more accurate sound emulation. 2018-05-22 00:53:00 -07:00
Christopher Snowhill
aebbef593f Updated Highly Quixotic to include new, more accurate sound emulation. 2018-05-22 00:53:00 -07:00
Chris Moeller
c38ff73e68 Hopefully fix the constant need to recompile some of the frameworks. 2018-05-11 19:22:45 -07:00
Chris Moeller
9609e96143 Hopefully fix the constant need to recompile some of the frameworks. 2018-05-11 19:22:45 -07:00
Chris Moeller
db60c25a3c Hopefully fix multi-port MIDI files that only denote the alternate port tracks. 2018-05-11 19:22:25 -07:00
Chris Moeller
c94c5dd0f2 Hopefully fix multi-port MIDI files that only denote the alternate port tracks. 2018-05-11 19:22:25 -07:00
Chris Moeller
ab2a02cc60 Update mGBA, including a fix for PSG volume. 2018-05-11 19:21:42 -07:00
Chris Moeller
baf8e574cf Update mGBA, including a fix for PSG volume. 2018-05-11 19:21:42 -07:00
Chris Moeller
af3b51cbcb Cleaned up some warnings. 2018-05-11 19:17:14 -07:00
Chris Moeller
8dc0bfb47a Cleaned up some warnings. 2018-05-11 19:17:14 -07:00
Chris Moeller
607f3dff0f Fix sidplay default filter configuration for 8580, which is now a different value format. 2018-05-01 19:31:55 -07:00
Chris Moeller
2df8f2acde Fix sidplay default filter configuration for 8580, which is now a different value format. 2018-05-01 19:31:55 -07:00
Chris Moeller
c6d1174742 Update libsidplayfp. 2018-05-01 19:31:27 -07:00
Chris Moeller
06a43a5aac Update libsidplayfp. 2018-05-01 19:31:27 -07:00
Chris Moeller
d8e0ab71f6 Remove CDN reset as we no longer use CloudFront. 2018-05-01 00:33:37 -07:00
Chris Moeller
4ec46ae565 Remove CDN reset as we no longer use CloudFront. 2018-05-01 00:33:37 -07:00
Chris Moeller
66c22b8b74 Updated VGMStream to r1050-1289-g35cd14fa. 2018-05-01 00:05:29 -07:00
Chris Moeller
f97ffd0574 Updated VGMStream to r1050-1289-g35cd14fa. 2018-05-01 00:05:29 -07:00
Chris Moeller
ae22f79bad Updated libopenmpt to version 0.3.9. 2018-04-30 20:48:06 -07:00
Chris Moeller
dce35b2924 Updated libopenmpt to version 0.3.9. 2018-04-30 20:48:06 -07:00
Christopher Snowhill
186d432108 Updated libopenmpt to version 0.3.8. 2018-04-30 20:36:19 -07:00
Christopher Snowhill
baace3fea9 Updated libopenmpt to version 0.3.8. 2018-04-30 20:36:19 -07:00
Christopher Snowhill
3b9c42af42 Update Sparkle to not code sign the Autoupdate binary until it is copied over. 2018-02-18 20:53:21 -08:00
Christopher Snowhill
df847cdd05 Update Sparkle to not code sign the Autoupdate binary until it is copied over. 2018-02-18 20:53:21 -08:00
Christopher Snowhill
f400e068cf Updated FFmpeg. 2018-02-18 20:44:10 -08:00
Christopher Snowhill
49429c816f Updated FFmpeg. 2018-02-18 20:44:10 -08:00
Christopher Snowhill
e1c33b5477 Updated VGMStream to r1050-1043-g16b4cf22. 2018-02-18 20:38:16 -08:00
Christopher Snowhill
f5d1ca364f Updated VGMStream to r1050-1043-g16b4cf22. 2018-02-18 20:38:16 -08:00
Christopher Snowhill
6cd51431bd Updated libopenmpt to version 0.3.6. 2018-02-18 20:25:43 -08:00
Christopher Snowhill
f9d9a492ad Updated libopenmpt to version 0.3.6. 2018-02-18 20:25:43 -08:00
Christopher Snowhill
8591c29eb8 Fix playlist info loading threading magic. 2018-02-18 20:19:18 -08:00
Christopher Snowhill
200701a2a3 Fix playlist info loading threading magic. 2018-02-18 20:19:18 -08:00
Christopher Snowhill
56ed9c3429 Updated VGMStream to r1050-1001-gebdfed99. 2018-01-27 20:32:27 -08:00
Christopher Snowhill
c114c30a3f Updated VGMStream to r1050-1001-gebdfed99. 2018-01-27 20:32:27 -08:00
Christopher Snowhill
ce1d938b3a Fix AdPlug decoder. 2018-01-27 16:09:02 -08:00
Christopher Snowhill
ea3ef1cadd Fix AdPlug decoder. 2018-01-27 16:09:02 -08:00
Christopher Snowhill
2d685baa4a Don't code sign OpenMPT.bundle on build. 2018-01-27 15:11:08 -08:00
Christopher Snowhill
75bc139600 Don't code sign OpenMPT.bundle on build. 2018-01-27 15:11:08 -08:00
Christopher Snowhill
2a9836569e Implemented AdPlug decoder. 2018-01-27 15:08:06 -08:00
Christopher Snowhill
50616714ad Implemented AdPlug decoder. 2018-01-27 15:08:06 -08:00
Christopher Snowhill
ddc3da7576 Updated VGMStream to r1050-925-g2b92a562, now with Atrac9 support. 2018-01-08 18:54:28 -08:00
Christopher Snowhill
c6c325a303 Updated VGMStream to r1050-925-g2b92a562, now with Atrac9 support. 2018-01-08 18:54:28 -08:00
Christopher Snowhill
5ca94b626d Fix libopenmpt Framework rpath so it loads. 2018-01-04 18:09:02 -08:00
Christopher Snowhill
6c1c3f3615 Fix libopenmpt Framework rpath so it loads. 2018-01-04 18:09:02 -08:00
Christopher Snowhill
66e9a1fa14 Replaced DUMB and company with libopenmpt. 2018-01-04 18:00:39 -08:00
Christopher Snowhill
aaaa5d574f Replaced DUMB and company with libopenmpt. 2018-01-04 18:00:39 -08:00
Christopher Snowhill
4ea71d96f0 Remove last traces of Travis CI support. 2017-12-27 19:20:19 -08:00
Christopher Snowhill
e90a6ef09f Remove last traces of Travis CI support. 2017-12-27 19:20:19 -08:00
Christopher Snowhill
d17e504cbb Remove badge from README.md. 2017-12-27 18:58:15 -08:00
Christopher Snowhill
8762ef5b9a Remove badge from README.md. 2017-12-27 18:58:15 -08:00
Christopher Snowhill
3647ff6e02 Update Secret Sauce functionality. 2017-12-27 18:57:41 -08:00
Christopher Snowhill
11845e18d6 Update Secret Sauce functionality. 2017-12-27 18:57:41 -08:00
13df28fef4 Implement proper fullscreen enter and exit animations. 2017-12-27 18:51:44 -08:00
faf5eb586a Implement proper fullscreen enter and exit animations. 2017-12-27 18:51:44 -08:00
Christopher Snowhill
11adbbedcb Oops. 2017-12-27 17:38:00 -08:00
Christopher Snowhill
0ddddb7965 Oops. 2017-12-27 17:38:00 -08:00
Christopher Snowhill
871fa82620 Hopefully fix Travis CI building once and for all. 2017-12-27 17:33:52 -08:00
Christopher Snowhill
2abba64b32 Hopefully fix Travis CI building once and for all. 2017-12-27 17:33:52 -08:00
Christopher Snowhill
25cc0002a0 Hopefully fix Travis CI building this time. 2017-12-27 17:14:32 -08:00
Christopher Snowhill
550d09b1cb Hopefully fix Travis CI building this time. 2017-12-27 17:14:32 -08:00
Christopher Snowhill
413ef368d9
Update .travis.xml
Try one more time.
2017-12-27 15:53:22 -08:00
Christopher Snowhill
3fe7a56c35 Update .travis.xml
Try one more time.
2017-12-27 15:53:22 -08:00
Christopher Snowhill
7c30545bd4
Update .travis.xml
Try again.
2017-12-27 15:45:11 -08:00
Christopher Snowhill
4eb56b3ae6 Update .travis.xml
Try again.
2017-12-27 15:45:11 -08:00
Christopher Snowhill
6d4572579f
Update .travis.xml
Try this again.
2017-12-27 15:40:59 -08:00
Christopher Snowhill
a530af181a Update .travis.xml
Try this again.
2017-12-27 15:40:59 -08:00
Christopher Snowhill
b5330c2839 Fix BASSMODS IT input, and add MO3 signature check. 2017-12-27 15:16:27 -08:00
Christopher Snowhill
cade10be22 Fix BASSMODS IT input, and add MO3 signature check. 2017-12-27 15:16:27 -08:00
Christopher Snowhill
7abc73fd07
Update .travis.xml
Hopefully fix building again.
2017-12-27 13:49:51 -08:00
Christopher Snowhill
3a2be5c261 Update .travis.xml
Hopefully fix building again.
2017-12-27 13:49:51 -08:00
Christopher Snowhill
54bd1db745 Ignore RepeatOne only when manually skipping tracks, not when playing normally. 2017-12-23 23:55:33 -08:00
Christopher Snowhill
524e161789 Track skip no longer gets stuck on the current track when in Repeat One mode. 2017-12-23 23:33:11 -08:00
Christopher Snowhill
cf8fd45f02 Updated VGMStream to r1050-873-ga4cf9afd. 2017-12-17 20:35:01 -08:00
Christopher Snowhill
df85ce80cd Fix oops in update script. 2017-12-17 00:27:33 -08:00
Christopher Snowhill
04e1dc02b4 Update feed script. 2017-12-17 00:24:01 -08:00
Christopher Snowhill
ed625bd63c Oops in VGMStream. 2017-12-16 20:25:18 -08:00
Christopher Snowhill
16e0a006f2 Updated VGMStream to r1050-866-g5cc215b4. 2017-12-16 20:17:41 -08:00
Christopher Snowhill
10f2ee1461 Added new extensions. 2017-12-16 19:58:49 -08:00
Christopher Snowhill
aa7cd57b19 Updated FFmpeg. 2017-12-16 19:57:49 -08:00
Christopher Snowhill
00549db86a Updated Sparkle. 2017-12-16 19:35:59 -08:00
Chris Moeller
1b1721736e Fix PlaylistLoader to sort the contents of directories by the file path. 2017-12-16 19:05:17 -08:00
Chris Moeller
9e8fd61d8c Update xcschemes. 2017-12-05 19:10:41 -08:00
Chris Moeller
ced683e228 Updated mGBA. 2017-12-05 19:07:55 -08:00
Chris Moeller
4c6eb39f63 Updated Sparkle. 2017-12-05 18:48:18 -08:00
Christopher Snowhill
07510cfabd Update lazyusf2 with latest fixes. 2017-10-30 15:47:51 -07:00
Christopher Snowhill
1abc4d8de4 Update DUMB to fix some possible lockups. 2017-10-30 15:47:27 -07:00
Christopher Snowhill
20d1ce09e5 Updated DUMB to version 2.0.2. 2017-10-08 18:48:02 -07:00
Christopher Snowhill
34357351c8 Updated VGMStream to r1050-707-gfcc79e8f. 2017-10-08 16:25:44 -07:00
Christopher Snowhill
614d57d37f Fix Standard MIDI processor for running SysEx sequences. 2017-10-05 12:50:25 -07:00
Christopher Snowhill
12ca20484c Update FFmpeg build script. 2017-10-02 12:41:16 -07:00
Christopher Snowhill
aa3b4300c8 Fix feed updater script to upload deltas this time. 2017-10-01 18:56:04 -07:00
Christopher Snowhill
2f0ccf8bf2 Update FFmpeg, hopefully resolving the minimum platform spec to support 10.7 again. 2017-10-01 17:46:01 -07:00
Christopher Snowhill
ed5f36f12f Hopefully fix feed update script to upload deltas. 2017-09-26 16:26:13 -07:00
Christopher Snowhill
d48ac9848b Internal fix. 2017-09-26 16:19:59 -07:00
Christopher Snowhill
913287665d Update project files to current recommendations. 2017-09-26 16:12:33 -07:00
Christopher Snowhill
47a6afe62c Update DUMB to version 2.0.0. 2017-09-26 16:11:54 -07:00
Christopher Snowhill
78b69b010d Update feed update method. 2017-09-25 19:08:17 -07:00
Christopher Snowhill
4fd36e1831 Oops, forgot to add my DSA public key to the app. Delta updates should work again after this update. 2017-09-25 18:52:17 -07:00
Christopher Snowhill
28b3dd7c7e Updated VGMStream to r1050-684-gedf8f7a9. 2017-09-24 16:47:21 -07:00
Christopher Snowhill
ba78e14909 Updated FFmpeg. 2017-09-24 16:35:45 -07:00
Christopher Snowhill
d3ef15de82 Updated DUMB to move some macros for internal use only. 2017-09-18 18:05:38 -07:00
Christopher Snowhill
0d904b16ae Fix a macro error caused by obsoletion in the macOS 10.13 SDK, which somehow causes a missing symbol error instead of outright failing. I could have swore I already fixed this, too. 2017-09-18 15:17:07 -07:00
Christopher Snowhill
63eae50486 Fix VGMStream tracknumber metadata, which was causing playlist to be lost on shutdown. 2017-09-17 20:04:05 -07:00
Christopher Snowhill
bf501d9e12 Add error receiver for debugging. 2017-09-17 20:03:30 -07:00
Christopher Snowhill
06f4fb70d4 Silence a warning. 2017-09-17 19:21:48 -07:00
Christopher Snowhill
d0f0f516a3 Really add title reading this time. 2017-09-17 19:21:38 -07:00
Christopher Snowhill
29e548d583 Added title reading for multi-song VGMStream files. 2017-09-17 18:41:04 -07:00
Christopher Snowhill
1ef9455f9d Updated symbol decoration for mono resampler. 2017-09-17 18:40:35 -07:00
Christopher Snowhill
e2748f878b Updated Sparkle framework. 2017-09-17 18:40:13 -07:00
Christopher Snowhill
039347f36f Made all scheme configurations shared, imported. 2017-09-17 18:40:02 -07:00
Christopher Snowhill
2e205f1cfa Updated FFmpeg. 2017-09-17 18:11:47 -07:00
Christopher Snowhill
e3b65daa6e Updated DUMB. 2017-09-16 21:37:49 -07:00
Christopher Snowhill
2f9eb42e24 Updated FT2Play to version 0.79. 2017-09-16 21:26:42 -07:00
Christopher Snowhill
085bbf7650 Updated mGBA core. 2017-09-16 21:25:45 -07:00
Christopher Snowhill
9c80799aea Updated VGMStream to r1050-670-g165cda22. 2017-09-16 21:24:57 -07:00
Christopher Snowhill
1a084b43c0 Add back missing file. 2017-07-30 21:02:43 -07:00
Christopher Snowhill
347439eba1 Remove obsolete files. 2017-07-30 20:59:45 -07:00
Christopher Snowhill
702a52f3ce Updated ft2play to version 0.78. 2017-07-30 20:54:41 -07:00
Christopher Snowhill
1e10430da8 Fix for macOS 10.13 SDK. 2017-07-30 20:54:28 -07:00
Christopher Snowhill
46cf33ca31 Updated VGMStream to r1050-603-g9d0c3ed8. 2017-07-30 20:37:03 -07:00
Christopher Snowhill
a558f9b8b5 Updated VGMStream to r1050-590-gbb8966a6. 2017-07-23 16:49:07 -07:00
Christopher Snowhill
628697f4b0 Forgot to initialize a few things, fixes echo in SPC files. 2017-07-19 11:59:54 -07:00
Christopher Snowhill
436f1caff7 Updated DMXOPL to version 1.9.1. 2017-07-17 18:34:34 -07:00
Christopher Snowhill
eb2ff0d600 Add code conditionally for older macOS SDKs. 2017-07-09 15:01:52 -07:00
Christopher Snowhill
9df683829a Fix VGMStream to not crash on open failure, and generate its file name extension list dynamically. 2017-07-09 15:01:25 -07:00
Christopher Snowhill
428f7e14d2 More 6502 opcodes. 2017-07-08 22:23:22 -07:00
Christopher Snowhill
84b92516e4 Add two missing files to project. 2017-07-03 16:14:53 -07:00
Christopher Snowhill
1d30e1a235 Updated VGMStream to r1050-554-g883d0a4f. 2017-07-03 16:13:01 -07:00
Christopher Snowhill
7a70c1c80e Merge branch 'master' of gitlab.kode54.net:kode54/Cog 2017-07-03 16:03:36 -07:00
Chris Moeller
113c52a616 Updated Doom oplmusic synth to latest version. 2017-06-23 16:50:41 -07:00
Chris Moeller
b18222052b Updated DMXOPL to version 1.8.2. 2017-06-23 16:50:10 -07:00
Christopher Snowhill
2575a2fb43 Updated DMXOPL to version 1.8.2. 2017-06-19 15:15:23 -07:00
Christopher Snowhill
c831470851 Updated VGMStream to r1050-536-gf670ae05. 2017-06-17 18:58:15 -07:00
Christopher Snowhill
95e853a544 Updated DMXOPL to version 1.7. 2017-06-12 20:24:57 -07:00
Christopher Snowhill
dac58b9f48 Updated PLAYPTMOD to version 1.35. 2017-06-11 17:57:00 -07:00
Christopher Snowhill
f2ee79946f Removed code which is no longer necessary. 2017-06-11 17:55:36 -07:00
Christopher Snowhill
19d93c8b17 Forgot some missing files from latest VGMStream. 2017-06-11 17:55:10 -07:00
Christopher Snowhill
5df7a8f5c6 Updated VGMStream to r1050-532-gba4e6d1f. 2017-06-11 17:35:03 -07:00
Christopher Snowhill
d2dc14a72c Added DMXOPL patch set by sneakernets. 2017-06-02 14:36:52 -07:00
Christopher Snowhill
c5c451b152 Updated VGMStream to r1050-521-g8b936cc7. 2017-05-21 21:15:12 -07:00
Christopher Snowhill
67332f4982 Last minute fix for files with multiple streams, which includes APE files with attached pictures. 2017-05-20 18:29:27 -07:00
Christopher Snowhill
df28a1ad34 Updated VGMStream to r1050-518-g3103029c. 2017-05-20 17:42:28 -07:00
Christopher Snowhill
e398375e2a Updated FFmpeg binaries. 2017-05-20 17:31:59 -07:00
Christopher Snowhill
36d4f80e18 Enabled Monkey's Audio codec, which was somehow forgotten. 2017-05-20 17:31:42 -07:00
Christopher Snowhill
9bc3b55cb7 Fixed XG mode. 2017-05-18 17:51:33 -07:00
Christopher Snowhill
473990139d Updated VGMStream to r1050-499-g3624cb06. 2017-05-18 17:51:04 -07:00
Christopher Snowhill
0217d5dee2 Fix EMIDI looping by implementing Global Loop Start/End support. 2017-04-25 18:31:02 -07:00
Christopher Snowhill
e3a2d255f3 Updated FFmpeg. 2017-04-22 21:27:12 -07:00
Christopher Snowhill
22fa3a3df0 Updated VGMStream to r1050-449-gd2fac791. 2017-04-22 21:26:52 -07:00
Christopher Snowhill
c291a4885b Fix VGMStream copying Vorbis framework on build. 2017-04-03 19:01:35 -07:00
Christopher Snowhill
5ec5fb90ea Updated copyright dates. 2017-04-03 18:56:33 -07:00
Christopher Snowhill
6a28695c5e Fixed Ogg Vorbis plug-in locating its Vorbis framework. 2017-04-03 18:45:41 -07:00
Christopher Snowhill
877ed3514c Updated VGMStream to r1050-398-gfbe2c96c. 2017-04-03 18:02:52 -07:00
Christopher Snowhill
efd25795bc Now build inside source tree instead of using GUI Archive feature. 2017-04-03 17:52:17 -07:00
Christopher Snowhill
e2b728f4d1 Updated FFmpeg. 2017-04-03 17:51:48 -07:00
Christopher Snowhill
aa26a713a0 Updated VGMStream to r1050-390-g72f34ec. 2017-03-26 18:42:01 -07:00
Christopher Snowhill
a142a06576 Updated VGMStream to r1050-386-g886a25c. 2017-03-25 19:02:05 -07:00
Christopher Snowhill
368bb003c2 Make resume-playback-on-startup optional, and disabled by default. 2017-03-21 22:08:35 -07:00
Christopher Snowhill
47aa97e164 Updated VGMStream to r1050-375-g6d4d310. 2017-03-20 13:28:53 -07:00
Christopher Snowhill
f6cf915fc2 Updated VGMStream to r1050-359-g00523fb. 2017-03-13 18:34:31 -07:00
Christopher Snowhill
786868d191 Updated VGMStream to r1050-352-g698269d. 2017-03-12 22:20:40 -07:00
Christopher Snowhill
01b91961ff Fix HighlyComplete for new mGBA header arrangement. 2017-03-12 21:38:46 -07:00
Christopher Snowhill
309be174c8 Update mGBA project file. 2017-03-12 21:38:16 -07:00
Christopher Snowhill
8a2c48bbda Fix for new GME code. 2017-03-12 21:38:00 -07:00
Christopher Snowhill
a70f6b57a5 Updated mGBA. 2017-03-12 21:23:00 -07:00
Christopher Snowhill
fce57925c0 Update Syntrax decoder with speed improvements. 2017-03-12 21:15:16 -07:00
Christopher Snowhill
d963710c28 Revert IIR filter changes from modplay resampler. 2017-03-12 21:12:59 -07:00
Christopher Snowhill
c594690aab Update GME, including support for tag-specified fade times for formats which support it, which are SPC and SFM. 2017-03-12 21:10:35 -07:00
Christopher Snowhill
b8110b85de Updated FFmpeg. 2017-03-12 21:00:18 -07:00
Chris Moeller
3d0d0ee24f Updated FFmpeg for proper iTunes gapless MP3 support. 2017-01-27 13:14:02 -08:00
Chris Moeller
e274ec01eb Updated FFmpeg and VGMStream. 2017-01-26 17:28:06 -08:00
Christopher Snowhill
89a2ab07a1 Updated VGMStream. 2016-12-26 16:45:02 -08:00
Christopher Snowhill
bcff934561 Updated playptmod to version 1.31. 2016-12-22 20:44:37 -08:00
Christopher Snowhill
68f8979bbe Updated playptmod plugin to handle MO3 and UMX archives. 2016-12-22 20:43:11 -08:00
Christopher Snowhill
07fef42863 Updated BASSMODS plugin to only handle IT modules. 2016-12-22 20:42:30 -08:00
Christopher Snowhill
31a0f9155c Updated to handle UMX archives with empty type specifier. 2016-12-22 20:42:06 -08:00
Christopher Snowhill
5959e6cb69 Changed FFmpeg build options and included more stuff. 2016-12-22 15:56:57 -08:00
Christopher Snowhill
3cd248f126 Fix seeking for SCVA. 2016-12-20 16:59:44 -08:00
Christopher Snowhill
3ff4892a1a Updated VGMStream. 2016-12-18 19:55:43 -08:00
Christopher Snowhill
b0e2332ce5 Updated VGMStream. 2016-12-18 11:32:02 -08:00
Christopher Snowhill
e1e2c2d431 Updated mGBA. 2016-12-08 20:51:42 -08:00
Christopher Snowhill
07395b1e61 Enable VGMStream FFmpeg 'accurate' looping. 2016-12-08 16:18:26 -08:00
Christopher Snowhill
5e7180fe34 Updated VGMStream. 2016-12-08 14:47:10 -08:00
Christopher Snowhill
0d6447f3d2 Updated FFmpeg to version 3.2.2. 2016-12-08 14:46:59 -08:00
Christopher Snowhill
2771809af6 Update FFmpeg plugin with some minor changes. 2016-12-03 21:40:53 -08:00
Christopher Snowhill
26a9e2b3a1 Updated SCVA player with more stringent resetting. 2016-11-30 21:29:03 -08:00
Christopher Snowhill
3f0415eabb Update SFList parser to handle byte order markers. 2016-11-30 21:24:16 -08:00
Christopher Snowhill
897d5911d8 Updated mGBA. 2016-11-30 16:42:21 -08:00
Christopher Snowhill
f7bd04ace2 Updated mGBA. 2016-11-30 15:46:55 -08:00
Christopher Snowhill
590cf42521 Fix crash on startup when MIDI files are resumed. 2016-11-29 16:00:18 -08:00
Christopher Snowhill
ebfcd03c5d - Change MIDI overrides to support 'default (auto)' mode
- Change MIDI flavor default to 'default (auto)'
- Fix MIDI preference page to correctly enable the flavor option only where applicable
- Fix SCVA player to reset existing instances reliably
2016-11-29 15:46:38 -08:00
Christopher Snowhill
af69cd53c3 Increase OPL3 volume 4x, which is about what it needs with this core and these instruments. 2016-11-21 21:00:02 -08:00
Christopher Snowhill
87c90c4019 Replace OPL3 weighted average resampler with a sinc resampler. 2016-11-21 20:59:25 -08:00
Christopher Snowhill
3453e6a3c7 Updated VGMStream. 2016-11-20 11:49:08 -08:00
Christopher Snowhill
03dab36e26 Fix VGMPlay resampler for Pokey. 2016-11-17 22:56:57 -08:00
Christopher Snowhill
70805327d2 Fixed YMF-278B playback. 2016-11-17 21:49:20 -08:00
Christopher Snowhill
fbe9ae50dd Update mGBA and fix license file inclusion in Resources. 2016-11-11 17:55:36 -08:00
Christopher Snowhill
7d806ce452 Updated WavPack decoder with hybrid correction file support. 2016-11-03 22:43:37 -07:00
Christopher Snowhill
5a3e8005ea Finished updating mGBA. 2016-11-03 22:43:12 -07:00
Christopher Snowhill
8ad0b7e8e3 Updated projects to Xcode recommendations. 2016-11-03 22:42:21 -07:00
Christopher Snowhill
a3f87e9010 Updated mGBA. 2016-11-03 20:46:13 -07:00
Christopher Snowhill
985160cf5a Updated copyright notice with past and present authors. 2016-10-13 21:19:30 -07:00
Christopher Snowhill
b5967bb2e1 Fix HotKey initialization to deinitialize any existing instances, as the global hash table is not reference counted, and the previous design would result in the hash table being set twice, then cleared. 2016-10-10 22:33:00 -07:00
Christopher Snowhill
c2bf3225d1 Use new symbols from macOS 10.12 SDK, which have the same values as the deprecated symbols. 2016-10-10 22:31:46 -07:00
Christopher Snowhill
291e2ae676 Fix HotKey Modifier hashing, which has always occupied the upper 16 bits of the value since as early as 2003. 2016-10-10 22:30:52 -07:00
Christopher Snowhill
0c3d9755fc Updated st3play to version 0.75a, now with panning defaulting to center, like the GUS. 2016-10-05 11:19:39 -07:00
Christopher Snowhill
c4047f53a1 Welp, that didn't help anything. 2016-10-01 18:57:07 -07:00
Christopher Snowhill
8a78daa888 Third time's the charm with FFmpeg, I hope. 2016-10-01 18:20:28 -07:00
Christopher Snowhill
81684c9378 Update FFmpeg again with a last minute fix. 2016-10-01 18:15:59 -07:00
Christopher Snowhill
849a52230c Update mGBA. 2016-10-01 17:58:25 -07:00
Christopher Snowhill
4dfa01f476 Update FFmpeg to version 3.1.4. 2016-10-01 17:56:27 -07:00
Christopher Snowhill
7bb116a33b Added a fix so that a rapid succession of sub-10 second files do not get queued up until the player eventually crashes. 2016-09-17 20:59:58 -07:00
Chris Moeller
58378d2711 Fix GME M3U playlist support. 2016-09-16 02:49:17 -07:00
Chris Moeller
ffc8d5b610 Remove deleted file from mGBA project. 2016-09-16 02:49:03 -07:00
Chris Moeller
a2e5d1da4f Fix double-free in GME when using MSX Audio. 2016-09-16 02:48:10 -07:00
Chris Moeller
096e68531c Update a bunch of project files. 2016-09-16 02:10:22 -07:00
Chris Moeller
45b032fb35 Updated mGBA path. 2016-09-16 01:50:06 -07:00
Christopher Snowhill
952cc2100d Further fix Sparkle. 2016-09-04 13:07:29 -07:00
Christopher Snowhill
398e4ba94c Fix Sparkle project. 2016-09-04 13:03:34 -07:00
Christopher Snowhill
a95280626f Fix Projects. Fix a major deadlock introduced by previous commit. Introduce new mGBA based GSF player. 2016-09-04 12:49:43 -07:00
Christopher Snowhill
899cfd6b42 Update project files. 2016-09-01 18:50:33 -07:00
Christopher Snowhill
48d22e0961 Fixed FFmpeg broken due to MacPorts installed libraries. 2016-09-01 18:11:44 -07:00
Christopher Snowhill
ac44ca33b0 Hopefully fixed total play time synchronizing with adding new tracks to the playlist. 2016-09-01 17:20:53 -07:00
Christopher Snowhill
434d95fccc Updated FFmpeg to version 3.1.3. 2016-09-01 17:20:19 -07:00
Christopher Snowhill
d298087dec Updated WavPack to version 5.0.0 alpha 4, decode floating point sample data to actual floating point, and now support DSD decoded as PCM. 2016-08-28 13:03:54 -07:00
Christopher Snowhill
de77fef181 Enabled .mtaf extension decoding in VGMStream. 2016-08-24 17:36:39 -07:00
Christopher Snowhill
327a45c194 Fixed MTAF decoder for features that had yet to be discovered. 2016-08-24 17:36:17 -07:00
Christopher Snowhill
9c9f8952d3 Update VGMStream so its FFmpeg component performs loop pre-roll, since FFmpeg itself doesn't seem to do this. Now loops should be as seamless as they were intended. 2016-08-14 15:26:42 -07:00
Christopher Snowhill
e4f3d02473 Add .sgb and .sgd extensions to VGMStream decoder. 2016-08-10 18:36:53 -07:00
Christopher Snowhill
b13d74ecb2 Add .sgb to VGMStream RIFF WAV parser. 2016-08-10 18:36:13 -07:00
Christopher Snowhill
771a73d0b3 Update VGMStream bitrate calculator with correct safety check. 2016-08-10 18:35:37 -07:00
Christopher Snowhill
b3ccd47c4e Update FFmpeg again, this time fixing missing and/or still enabled items due to missing line end escapes in the script. 2016-08-10 18:21:36 -07:00
Christopher Snowhill
2b2f832535 Move intermediate paths of plugins that share names with their core libraries, so they don't clash when performing partial rebuilds. 2016-08-10 18:20:59 -07:00
Christopher Snowhill
5f8bcf8ff1 Update and fix FFmpeg, which fixes an MP3 parser crash. 2016-08-05 16:40:48 -07:00
Christopher Snowhill
a7d1853853 Support GME M3U playlists. 2016-08-04 18:55:13 -07:00
Christopher Snowhill
1dab2b6d27 Support GBS version 2? 2016-08-04 18:54:57 -07:00
Christopher Snowhill
92c089f785 Hopefully fix some note cutting issues with SSF and DSF playback. 2016-07-23 17:19:00 -07:00
Chris Moeller
91753a978f Update FFmpeg again with the whole iTunes fix. 2016-07-22 16:36:16 -07:00
Chris Moeller
93095f8e45 Fix update feed script. 2016-07-22 16:17:40 -07:00
Chris Moeller
dc9d9a006c Update FFmpeg to support iTunes MP3 gapless info again. 2016-07-22 15:44:59 -07:00
Chris Moeller
42a43316b8 Update VGMStream. 2016-07-22 15:03:01 -07:00
Chris Moeller
e94cb95bf5 Fix uploading deltas to S3. 2016-07-16 23:17:03 -07:00
Chris Moeller
ff46687597 Updated VGMStream with FFmpeg support, and moved the supported formats over to that plug-in. 2016-07-16 23:03:44 -07:00
Chris Moeller
96576da089 Hopefully fix delta uploading. 2016-07-16 15:33:18 -07:00
Chris Moeller
92d9af91a2 Correct a minor typo. 2016-07-15 22:51:49 -07:00
Chris Moeller
34fe5c3668 Force MIME type for uploaded ZIP and delta. 2016-07-15 22:50:29 -07:00
Chris Moeller
69382366f5 Invalidate CDN path automatically. 2016-07-15 22:43:19 -07:00
Chris Moeller
55ecd008ad Update feed location and script. 2016-07-15 22:41:17 -07:00
Chris Moeller
b9a39a48a8 Update feed location and script. 2016-07-15 22:33:02 -07:00
Chris Moeller
aaf516fb00 Further improved the FFmpeg plug-in, including cleaning up after a memory leak. 2016-07-15 21:41:23 -07:00
Chris Moeller
0c830b92f8 Enable RIFF WAV parser in FFmpeg. 2016-07-15 21:40:57 -07:00
Chris Moeller
b89c68a768 Updated FFmpeg to version 3.1.1, and enabled assembly optimizations. 2016-07-15 09:26:18 -07:00
Chris Moeller
ded21370b5 Update script for building newer FFmpeg. 2016-07-15 00:01:56 -07:00
Chris Moeller
b4ae0cc4eb Update FT2Play. 2016-07-13 19:47:13 -07:00
Chris Moeller
a2a519b3fd Fix initialization error with YM2151. 2016-07-08 17:24:53 -07:00
Chris Moeller
2b54fdbeae Undid some minor madness. 2016-07-07 17:11:33 -07:00
Chris Moeller
84e38a6213 Hopefully fix all threading issues with VGMPlay. 2016-07-07 16:42:36 -07:00
Chris Moeller
1375489a8b Fix previous commit so it compiles. 2016-07-07 16:41:27 -07:00
Chris Moeller
d94bd9a183 Minor fix to Highly Theoretical that won't be used (yet?) anyway. 2016-07-07 15:55:36 -07:00
Chris Moeller
540ca59b50 Correct fix for DSF ADPCM decoder. 2016-07-06 22:56:33 -07:00
Chris Moeller
0bc20e792d DSF: Rewrite AICA ADPCM decoder, now produces correct output. 2016-07-06 19:33:59 -07:00
Chris Moeller
5006d05222 Fix a VGM crash when loading unsupported files. 2016-07-02 17:08:41 -07:00
Chris Moeller
b262dfa508 Replaced Highly Theoretical SCSP/AICA core with original Neill Corlett version, with all the fixes that aren't MAME related. 2016-07-02 02:59:12 -07:00
Chris Moeller
86a6b2c22d Fix playlist metadata loading. 2016-07-02 02:58:38 -07:00
Chris Moeller
592d6a6a30 Fix for double free with new code. 2016-07-02 02:58:21 -07:00
Chris Moeller
7bb722cdec Updated VGMPlay. 2016-07-02 02:57:36 -07:00
Chris Moeller
f35d0773b9 Add ADX keys for Storm Lover Natsu Koigit diff and Dragon Ball Z: Dokkan Battle. 2016-06-30 16:06:55 -07:00
Chris Moeller
ed33e37214 Fix file handle leak in vgmstream decoder. 2016-06-30 15:40:43 -07:00
Chris Moeller
27e5402d88 Fix file handle allocation in MP4 and HCA readers, reverting an incorrect change. 2016-06-30 15:40:29 -07:00
Chris Moeller
6077a5086e Update HCA decoder to ignore relative volume adjustment header field, since it can sometimes be wrong. 2016-06-29 23:09:16 -07:00
Chris Moeller
aaf320a96c Add autorelease pools to various info loading functions, so that adding massive amounts of tracks to the playlist will not run out of file handles. 2016-06-29 22:14:13 -07:00
Chris Moeller
0d12f9e4e3 Fix file info load batching to operations of 16 files at a time. 2016-06-29 22:13:32 -07:00
Chris Moeller
a1fab29749 MIDI decoder only initializes synthesizer if decoding actually begins, which should speed up loading file metadata. 2016-06-29 22:12:58 -07:00
Chris Moeller
cd3901f00d Update HCA decoder. 2016-06-29 22:11:18 -07:00
Chris Moeller
b47fe40fcd Fix File_Extractor semaphore for newer Mac OS X. 2016-06-29 22:11:02 -07:00
Chris Moeller
17272ce43c Clean up lots of warnings and minor issues. 2016-06-29 22:10:29 -07:00
Chris Moeller
7876a4492f Handle background track metadata loading in a saner manner. 2016-06-28 19:33:48 -07:00
Chris Moeller
ffa31e696d Remove unused function declaration. 2016-06-28 19:33:21 -07:00
Chris Moeller
02fbe9258a Change debugging information settings. 2016-06-28 19:33:03 -07:00
Chris Moeller
64c401b5d8 Fixed a memory leak which would occur on every application switch. 2016-06-28 19:31:55 -07:00
Chris Moeller
98f0757089 Fixed file handle leak in vgmstream HCA and MP4 decoders, and minor casting fixes. 2016-06-28 19:28:34 -07:00
Chris Moeller
e703a3937c Updated HCA decoder. 2016-06-28 19:25:35 -07:00
Chris Moeller
5a015684ad Updated ft2play to version 0.77. 2016-06-28 00:34:37 -07:00
Chris Moeller
21b67c92ac Added HCA support to vgmstream. 2016-06-28 00:33:58 -07:00
Chris Moeller
78ccb5d2bf Rewrote the MIDI SFList loader, and added support for the new JSON based format. 2016-06-19 13:06:55 -07:00
Chris Moeller
03e7b666ae Added support for DMX and MSOPL true stereo extension. 2016-06-19 13:05:30 -07:00
Chris Moeller
597a342838 Adding a lot of MIDI files should hopefully be faster now. 2016-06-19 12:58:17 -07:00
Chris Moeller
03b825ced3 Hopefully fix the last of the Automatic Reference Counting issues that remained. 2016-06-19 12:57:18 -07:00
Chris Moeller
0213dd9741 Updated Blam Synthesis resampler, improving quality and performance significantly. 2016-06-02 00:31:13 -07:00
Chris Moeller
4fdbf35aba Imported OPL3 FM synthesizer drivers from 'OPL3 MIDI Driver for Windows' and 'Doom OPL Windows MIDI driver' 2016-05-28 21:39:10 -07:00
Chris Moeller
2df21a675a Fix remaining errors, hopefully compiling now. 2016-05-19 12:00:41 -07:00
Chris Moeller
7200229af3 Fix potential threading issues with resid and residfp. 2016-05-18 20:27:05 -07:00
Chris Moeller
f3b44f7730 Renamed and updated README. 2016-05-15 18:52:14 -07:00
Chris Moeller
715c4383db Stop it, Travis. Stop. 2016-05-15 18:29:30 -07:00
Chris Moeller
10cb39bd40 Travis is trying to compile old tags. It should not do this. 2016-05-15 18:29:21 -07:00
Chris Moeller
c3510809a3 Add preliminary Travis CI configuration. 2016-05-15 18:00:29 -07:00
Chris Moeller
33868a8b09 Share the Cog scheme. 2016-05-15 17:58:22 -07:00
Chris Moeller
8670ddf635 Fixed Ogg Vorbis related crash 2016-05-12 22:37:28 -07:00
Chris Moeller
dee388d22c Changed the Support Cog link. 2016-05-09 21:57:04 -07:00
Chris Moeller
026380fe40 Now MIDI decoder will stop playing if init/startup fails, rather than attempting to play with no SoundFonts loaded. 2016-05-09 21:56:44 -07:00
Chris Moeller
4c0e43863f Updated BASSMIDI. 2016-05-09 21:56:04 -07:00
Chris Moeller
e531f288b2 Fix a race condition with opening files externally through file associations or the 'open' terminal command. 2016-05-07 22:41:28 -07:00
Chris Moeller
a1bf797f56 Remove unnecessary autoreleasepool block. 2016-05-07 10:21:05 -07:00
Chris Moeller
ba9fe0534f Convert playlist metadata loader to use code blocks, which fixes references and stops crashes on adding new tracks. 2016-05-07 10:20:46 -07:00
Chris Moeller
f0bee5ea6c Fix FFMPEG library paths so release target builds. 2016-05-06 23:37:43 -07:00
Chris Moeller
af7485f26a Fix newly imported FFMPEG, so it actually uses and links to the new libraries. 2016-05-06 23:35:04 -07:00
Chris Moeller
5620a377db And then Xcode decided to reformat a couple of my XIB files. 2016-05-06 23:16:33 -07:00
Chris Moeller
8308f30d5f Fixed FFMPEG by replacing it with a proper build, should be faster now, too. 2016-05-06 23:16:12 -07:00
Chris Moeller
6c25858e66 Updated the feedback form URL. 2016-05-05 19:30:11 -07:00
Chris Moeller
7b940443af Minor fixes to hotkey event handler. 2016-05-05 14:03:58 -07:00
Chris Moeller
68db8edae3 Fixed setting keycode 0 as a hotkey. 2016-05-05 14:03:48 -07:00
Chris Moeller
23bf993ad1 Fixed configuring spam hotkey. 2016-05-05 14:03:24 -07:00
Chris Moeller
0e3644177e Updated everything else to ARC, and plugged a release cycle. 2016-05-05 13:05:39 -07:00
Chris Moeller
80aa1b7e25 Migrate DUMB plug-in to use ARC. 2016-05-03 00:58:19 -07:00
Chris Moeller
21c948212b Migrate FFMPEG plug-in to use ARC. 2016-05-03 00:58:05 -07:00
Chris Moeller
3c229f2017 Migrate APL plug-in to use ARC. 2016-05-03 00:57:52 -07:00
Chris Moeller
a2ff3dcb0a Eliminate all warnings in HighlyComplete and child frameworks. 2016-05-03 00:34:46 -07:00
Chris Moeller
0eec639b66 Upgrade some Sparkle project thing. 2016-05-03 00:34:17 -07:00
Chris Moeller
2f60cb42db Activated ARC for HighlyComplete plug-in, and made necessary fixes to it. 2016-05-03 00:32:28 -07:00
Adam Gashlin
4bbf15ea5c Accept 0x00010102 in header for CWAV
This is supposedly in files from Fire Emblem Fates and
Hyrule Warriors Legends.
2016-05-02 22:59:18 -07:00
Chris Moeller
e58e934db1 Fixed MIDI GS reset 2016-04-12 21:45:49 -07:00
Chris Moeller
7903c0e371 Fixed compilation error 2016-04-12 21:45:28 -07:00
Chris Moeller
6c8a08fff1 Implemented MIDI flavor override control for Sound Canvas VA Audio Unit 2016-04-12 21:16:25 -07:00
Chris Moeller
f10fa14668 Updated Game_Music_Emu with changes that don't currently affect playback. 2016-03-17 17:15:45 -07:00
Chris Moeller
87ea9f3428 Forgot to fix Syntrax-c framework install path. 2016-03-13 23:07:11 -07:00
Chris Moeller
a60970c754 Whoops. 2016-03-13 22:52:53 -07:00
Chris Moeller
3c75c03b70 Implemented new Syntrax/JayTrax Module decoder. 2016-03-13 22:51:17 -07:00
Chris Moeller
bd93d120a0 Added (disabled) AUPlayer configuration view, which is obviously not in real time due to the buffering, hence it is disabled. 2016-03-13 18:48:17 -07:00
Chris Moeller
dd5c25c125 GME: Fix incorrect length reporting for VGM files, caused by an uninitialized variable. 2016-02-10 17:52:28 -08:00
Chris Moeller
0078b0bccb Worked around a Clang optimizer bug by replacing a table generator with a static table. 2016-02-10 00:04:31 -08:00
Chris Moeller
8533dde6dd Fixed GME/VGMPlay metadata retrieval during playback, which fixes song lengths. 2016-02-09 22:20:00 -08:00
Chris Moeller
cf1857fa94 Updated VGMPlay, fixing YM2608 playback. 2016-02-07 21:03:10 -08:00
Chris Moeller
039788226d - MIDI player now loops non-looping files internally if Repeat One is enabled
- MIDI player now supports installed Audio Unit plug-ins, and defaults to the DLS MIDI synthesizer
2016-01-20 21:11:05 -08:00
Chris Moeller
fed76e9a49 Added new Audio Unit MIDI player, currently not in use. 2016-01-11 01:36:41 -08:00
Chris Moeller
5bd098fa88 Fixed playback of non-stereo Opus files 2015-12-22 00:39:00 -08:00
Chris Moeller
0f13825a04 Updated libopus to version 1.1.1 and opusfile to 0.6 2015-12-22 00:38:41 -08:00
Chris Moeller
d700174fa6 Fixed Game_Music_Emu input handling indefinite playback 2015-11-27 02:04:37 -08:00
Chris Moeller
09e546591a Updated Game_Music_Emu to latest VGMPlay branch 2015-11-27 02:02:41 -08:00
Chris Moeller
9020667054 Fixed a minor slip-up after attempting to switch out the PSF decoder 2015-11-12 21:39:56 -08:00
Chris Moeller
d7ea8402db Merge branch 'xcode7beta' 2015-11-12 21:37:10 -08:00
Chris Moeller
ae3d45cf45 Updated playptmod 2015-11-12 21:35:58 -08:00
Chris Moeller
b8763c6cad Updated modplay 2015-11-12 21:35:42 -08:00
Chris Moeller
ce2303ef24 Update project files for new Xcode 2015-11-12 21:31:10 -08:00
Chris Moeller
f984f09b4b Fixed memory leak in PTM reader error handlers 2015-08-10 21:17:19 -07:00
Chris Moeller
306a5de8e7 Update Sparkle 2015-08-10 21:16:48 -07:00
Chris Moeller
2d4d5f2d95 Fixed memory leak in PTM reader error handlers 2015-08-10 21:14:53 -07:00
Chris Moeller
52362e4341 Workaround bugs in the 10.11 SDK by using the 10.10 SDK instead 2015-08-05 17:03:12 -07:00
Chris Moeller
5a3250234e Change submodule to point to https url 2015-08-05 16:36:53 -07:00
Chris Moeller
897c9b069e Work around compilation issue with Xcode 7 beta targeting systems older than El Capitan 2015-08-03 18:09:46 -07:00
Chris Moeller
93c17e85bb Update .gitignore 2015-08-03 18:09:16 -07:00
Chris Moeller
fdb855eb4c Updated vgmstream to fix a 64 bit compilation issue 2015-08-02 00:19:19 -07:00
Chris Moeller
06d0f1834c Added slight sleep delay to retry cycle of input decoder chain 2015-08-02 00:18:22 -07:00
Chris Moeller
19e56122a9 Fixed FLAC assert.h issue 2015-08-02 00:17:47 -07:00
Chris Moeller
3b35ff2eda Updated midi_processing to fix RPG Maker loops 2015-08-01 19:16:41 -07:00
Chris Moeller
e9e446e1a2 Update feed updater script 2015-08-01 01:04:48 -07:00
Chris Moeller
e8ff4a9b63 Remove private data from repository 2015-07-31 23:55:14 -07:00
Chris Moeller
fdefcf4128 Updated genversion.sh for new Git repository 2015-07-31 23:48:08 -07:00
Chris Moeller
260b26e2dc Added Sparkle submodule 2015-07-31 23:42:47 -07:00
Chris Moeller
da9723fbf1 Removed Sparkle from main repository 2015-07-31 23:32:56 -07:00
Chris Moeller
c9bee1e7ae Updated modplay, primarily st3play 2015-06-02 00:35:19 -07:00
Chris Moeller
ab7e5e6966 Updated Sparkle framework 2015-06-02 00:34:50 -07:00
Chris Moeller
d4c971f9d2 Updated lazyusf2 2015-05-16 21:11:55 -07:00
Chris Moeller
3f55ef085a Hopefully fix munt madness for real this time 2015-05-16 19:22:06 -07:00
Chris Moeller
f760870f06 Fixed munt dependency that should have been removed 2015-05-16 19:15:22 -07:00
Chris Moeller
959a43b2de Updated vgmstream 2015-05-16 18:58:14 -07:00
Chris Moeller
65a1ecef0d Added MUNT to project tree, but it's not being used yet 2015-04-27 19:06:09 -07:00
Chris Moeller
92f8173129 Updated BASS library 2015-04-25 01:12:01 -07:00
Chris Moeller
f8db303293 Relaxed XMI IFF processing a bit 2015-04-21 21:52:55 -07:00
Chris Moeller
43d1c88d8c Updated playptmod to version 1.25 2015-04-20 17:58:57 -07:00
Chris Moeller
c48ddc8b43 Added lazyusf region detection from save states 2015-04-19 22:32:04 -07:00
Chris Moeller
18dac8e493 Added error checking to SID tune loading 2015-04-13 00:42:48 -07:00
Chris Moeller
a6b6369a6d Added class priority levels to metadata readers, properties readers, and containers, all so sidplay can be downvoted for mishandling id MUS format when trying to read its own MUS format 2015-04-13 00:39:24 -07:00
Chris Moeller
ddab71158e Change sidplay decoder priority so .mus hits the MIDI input first 2015-04-12 23:28:06 -07:00
Chris Moeller
28071df622 Fixed various signed/unsigned char issues that don't necessarily affect this application's build process 2015-04-10 13:05:38 -07:00
Chris Moeller
e6b68486f1 Fixed a .JOE file with 0 dataInterleave, assuming 16 byte interleave for such files. 2015-04-10 13:05:02 -07:00
Chris Moeller
5d380c859c Updated BASSMIDI 2015-04-06 18:36:18 -07:00
Chris Moeller
4a0382d874 Updated playptmod and st3play 2015-03-26 17:48:57 -07:00
Chris Moeller
5677527ffd Changed code signing procedures, removed unnecessary Plugin.h copies from numerous PlugIn bundles, and re-signed Growl.framework with a valid signature 2015-03-18 21:45:32 -07:00
Chris Moeller
b542152790 Updated modplay with a new st3play, with numerous fixes 2015-03-18 18:06:01 -07:00
Chris Moeller
d9e03f3d2c Updated vio2sf 2015-03-18 18:05:44 -07:00
Chris Moeller
3d15a63e91 Amend last commit, fixing vio2sf. 2015-03-14 17:41:02 -07:00
Chris Moeller
d62a6463af Updated vio2sf. 2015-03-14 17:30:00 -07:00
Chris Moeller
df157bd7ce Updated playptmod to version 1.22, fixing an issue with portamento when there's no period, which affected MOD.cry of doom 3. 2015-03-14 17:29:42 -07:00
Chris Moeller
1181393709 Updated lazyusf2 2015-03-10 22:32:26 -07:00
Chris Moeller
dfed1a3814 Fixed Sap_File song length reporting, even though it doesn't affect Cog 2015-03-10 21:22:04 -07:00
Chris Moeller
7930b02c83 Updated playptmod 2015-03-10 18:34:12 -07:00
Chris Moeller
438b4143de Updated lazyusf2 2015-03-10 18:34:02 -07:00
Chris Moeller
6262a97203 Updated lazyusf2, now supports Turok: Dinosaur Hunter and Turok 2: Seeds of Evil, possibly others 2015-03-03 23:39:38 -08:00
Chris Moeller
3e515ec4a3 Updated lazyusf2 2015-03-02 18:16:06 -08:00
Chris Moeller
62a171290b Update lazyusf2 2015-03-02 14:13:26 -08:00
Chris Moeller
b73c20985c Changed USF player to resample using lazyusf2 2015-03-01 23:04:22 -08:00
Chris Moeller
4d8ec1960f Switched from lazyusf to lazyusf2 2015-03-01 21:28:09 -08:00
Chris Moeller
24730bdfa2 Added extra logging to lazyusf 2015-02-27 18:54:44 -08:00
Chris Moeller
8c360b4555 Added debug build logging to lazyusf 2015-02-26 18:51:44 -08:00
Chris Moeller
83772785f8 Fixed HivelyTracker 5xx command bug, thanks to str00t for reporting it and passing_by for the standalone test case 2015-02-25 18:40:26 -08:00
Chris Moeller
f84cfcd647 Fixed MIDI drums 2015-02-22 12:15:07 -08:00
Chris Moeller
b1b115d510 Potential fix for seeking too far into archived files 2015-02-22 11:56:51 -08:00
Chris Moeller
6a66946823 Various MIDI input fixes 2015-02-21 18:09:33 -08:00
Chris Moeller
c17dcc01bc Formatting error 2015-02-21 01:10:55 -08:00
Chris Moeller
e7fb5f001e Added debugging traces to lazyusf 2015-02-21 00:55:46 -08:00
Chris Moeller
d066dfce6e Forgot a file 2015-02-21 00:31:21 -08:00
Chris Moeller
9bcf93a509 Added opcode disassembler code to lazyusf for debugging experiments 2015-02-21 00:30:48 -08:00
Chris Moeller
8808e1a55a Updated st3play and fixed two horrible bugs with ft2play 2015-02-20 00:16:52 -08:00
Chris Moeller
1503ece011 Updated vgmstream to fix a crash 2015-02-13 16:58:18 -08:00
Chris Moeller
739af5e36a Fixed vgmstream bitrate calculator for formats that leave some channels' streamfile pointers empty 2015-02-12 14:23:13 -08:00
Chris Moeller
b50ed67591 Fixed Repeat None correctly this time 2015-02-10 21:42:36 -08:00
Chris Moeller
1f0f4a75a0 Implemented bitrate reporting for vgmstream 2015-02-08 19:20:24 -08:00
Chris Moeller
7120ba2dd9 Hopefully fixed the file tree crashing on startup if it was configured to an invalid path 2015-02-08 18:15:42 -08:00
Chris Moeller
f55eb1d3bf Added a silence decoder, and fall back all decoder open failures on one second of silence 2015-02-08 18:15:02 -08:00
Chris Moeller
25236a254a On second thought, let's not allow other repeat modes to wrap around the playlist boundary, either 2015-02-07 23:38:16 -08:00
Chris Moeller
321a5ea23f Fix repeat none and repeat all being swapped 2015-02-07 23:36:23 -08:00
Chris Moeller
ff4b8dd912 Fixed Musepack seeking, which was outright crashing since the last MPCDec update 2015-02-07 22:24:42 -08:00
Chris Moeller
f98f9c7694 Update lazyusf rsp hle 2015-02-07 17:57:52 -08:00
Chris Moeller
d6c6b18431 Fixed Ogg Vorbis support that an outside project update broke 2015-02-05 16:37:42 -08:00
Chris Moeller
dab47057a3 Updated playptmod to fix some bugs with glissando slides 2015-02-05 16:37:21 -08:00
Chris Moeller
8c6f1fa152 Remove GB DMG hacks that were a poor attempt to mimic vgmplay 2015-01-27 19:11:40 -08:00
Chris Moeller
bf7e405ad8 Hopefully fixed library reference paths 2015-01-24 21:31:41 -08:00
Chris Moeller
faae95ddcb Updated vgmstream with support for G.722.1 and G.719 codecs 2015-01-24 21:22:21 -08:00
Chris Moeller
8f1d76bd92 Updated playptmod and modplay 2015-01-23 17:09:37 -08:00
Chris Moeller
08c0ac22c4 Nope, one more fix 2015-01-21 18:19:36 -08:00
Chris Moeller
951d9f1569 And forgot to add the two new files to Vgmstream project 2015-01-21 18:17:15 -08:00
Chris Moeller
ab233ed799 And I managed to break the Cog specific changes to vgmstream.c again 2015-01-21 18:15:08 -08:00
Chris Moeller
71bb684a0e Fix vgmstream project for new var arrays header 2015-01-21 18:10:47 -08:00
Chris Moeller
c5416111bd Updated vgmstream 2015-01-21 18:08:44 -08:00
Chris Moeller
9c57fdb469 Updated stack allocation system used by DUMB and Opus 2015-01-21 18:03:50 -08:00
Chris Moeller
ead4f8053b Fix partially reverted code for cpuid function with -fPIC, which isn't actually used in 64 bit builds anyway 2015-01-16 20:56:08 -08:00
kode54
040efbcc15 Merged in chrisedisson/cog/maximize-from-dock (pull request #2)
Cog will now re-maximize window(s) when dock icon clicked after minimization.
2015-01-15 18:03:11 -08:00
o1
8bd04594dd Cog will now re-maximize window(s) when dock icon clicked after minimization. 2015-01-15 16:57:22 +03:00
o1
185fff8465 Another crash fix 2015-01-15 09:19:17 +03:00
o1
ccd40d757b Merged recent encoding/stability changes. 2015-01-15 09:13:32 +03:00
o1
3c4cecd1e4 Fighting mp3 tag charset problem:
* id3v1 tags are now displayed in default windows charset rather than always being latin1
* only reading required bits from encoding byte (cures some faulty tag problem)
* faulty utf16 headers without endianness will now display correctly as well
2015-01-15 09:02:24 +03:00
Chris Moeller
38a8b8d0bd Bug fix for module resamplers and playptmod 2015-01-11 18:13:52 -08:00
Chris Moeller
a8e4c9dbbf Bugfix for playptmod 2015-01-11 16:16:42 -08:00
Chris Moeller
32f5ceb212 Fixed playptmod playing channels out of phase with each other 2015-01-10 23:28:41 -08:00
Chris Moeller
1950124506 Major overhaul of module playback routines, including a new band-limited linear interpolation mode, softer default pan separation, and better band-limited synthesis for MOD files 2015-01-10 23:07:51 -08:00
Chris Moeller
9c54354c44 Updated playptmod 2015-01-08 21:10:38 -08:00
o1
b3072709e4 Fixed possible track idx overflow causing crash 2015-01-07 15:10:33 +03:00
o1
9cb9a86248 Updated project settings 2015-01-07 15:09:29 +03:00
Chris Moeller
3e885e5ca7 Fixed bug making SSB4 music unopenable 2015-01-04 21:31:49 -08:00
Chris Moeller
66931cc4fd Updated BASS, BASSFLAC, and BASSMIDI 2014-12-23 17:16:17 -08:00
Chris Moeller
256040357e Made it possible to enable RSP disassembly via a compile time option 2014-12-23 17:15:30 -08:00
Chris Moeller
fcede20802 Updated vgmstream to fix BFSTM support 2014-12-14 21:56:07 -08:00
Chris Moeller
06fc740e5a Added .NUS3BANK extension to vgmstream decoder 2014-12-13 17:40:53 -08:00
Chris Moeller
78be8bbec3 Update vgmstream for Super Smash Bros. Wii U 2014-12-13 17:05:15 -08:00
Chris Moeller
bb7fcd31da Updated vgmstream 2014-12-11 21:27:31 -08:00
Chris Moeller
d70a5b5b88 Fixed sidplayfp install path for real this time 2014-12-07 22:52:29 -08:00
Chris Moeller
6a66043b7c Fixed residfp install path 2014-12-07 22:44:44 -08:00
Chris Moeller
08dc22009d Implemented basic residfp support 2014-12-07 22:26:31 -08:00
Chris Moeller
540069c019 Change to mimic iTunes to a limited degree instead, hopefully this is enough info for most applications 2014-12-04 15:22:27 -08:00
Chris Moeller
22e97735c6 On second thought, let's pretend we're Swinsian 2014-12-03 22:50:59 -08:00
Chris Moeller
12dc73430b Last minute bug fixes 2014-12-03 22:34:13 -08:00
Chris Moeller
da26e6757b Implemented a distributed notification for track information and playback status 2014-12-03 22:13:27 -08:00
Chris Moeller
42e6eb03c2 Updated lazyusf 2014-12-03 21:38:28 -08:00
Chris Moeller
2a0ef29ebe Updated notification system 2014-12-03 21:36:55 -08:00
Chris Moeller
1f3939c363 Minor bugfix for lazyusf 2014-11-23 23:46:10 -08:00
Chris Moeller
edf24c73d0 Fixed a few outstanding lazyusf bugs due to failing to migrate fixes 2014-11-23 22:09:46 -08:00
Chris Moeller
339ba527c5 Updated lazyusf 2014-11-23 21:39:42 -08:00
Chris Moeller
55d6e5050c Fixed playptmod song restarting by actually clipping the restart position field before using it, still assuming it may be a valid restart position in some non-STK songs 2014-11-10 16:31:03 -08:00
Chris Moeller
73d90aeeb2 Updated ft2play to v0.68 with a real fix instead of a stupid hack 2014-11-07 16:42:03 -08:00
Chris Moeller
e89bc870ad Oops, forgot a macro change in SSEQ player 2014-11-04 18:39:14 -08:00
Chris Moeller
d355b40fce Absolute value function added since Apple doesn't provide a suitable candidate with std::abs 2014-11-04 18:16:41 -08:00
Chris Moeller
88aafebc58 Fixed NCSF player project file 2014-11-04 17:59:56 -08:00
Chris Moeller
7896e73080 Updated NCSF player 2014-11-04 17:56:15 -08:00
Chris Moeller
9eb0037780 Fixed ft2play tone portamento 2014-11-04 17:55:02 -08:00
Chris Moeller
4acbb21f99 Updated Game_Music_Emu to support Game Boy DMG sound in VGM files 2014-11-02 18:28:28 -08:00
Chris Moeller
0290c1a3dd Ft2play now has much better row tracking for pattern loops, fixing loop counts for songs such as F0x-Test.xm 2014-11-02 18:19:30 -08:00
Chris Moeller
2a2c3dd5da Fixed LazyUSF TLB memory access functions to handle open bus accesses instead of attempting out of range access to the RAM block, which fixes Harvest Moon 64. 2014-10-22 19:03:59 -07:00
Chris Moeller
f22e47f740 Sparkle something 2014-10-22 19:03:29 -07:00
Chris Moeller
d8d6eeb89a Fixed FLAC assert.h with an absolute path that should work across system reinstalls 2014-10-22 19:03:10 -07:00
Chris Moeller
257416e98b Fixed modplay/ft2play F00 effect song restart 2014-10-20 18:46:39 -07:00
Chris Moeller
58eda0e491 Updated MPCDec to latest release, which now supports SV8 proper 2014-10-19 17:42:04 -07:00
Chris Moeller
587db5fdbe Added vgmstream missing file name extensions 2014-10-19 16:39:06 -07:00
Chris Moeller
9df980732a Fixed vgmstream interleaved BFWAV 2014-10-19 16:38:54 -07:00
Chris Moeller
3b5229e792 Forgot to add new file to vgmstream project 2014-10-19 16:11:39 -07:00
Chris Moeller
d1f6985f02 Updated vgmstream to support G1L files, f.ex. Hyrule Warriors 2014-10-19 14:18:39 -07:00
Chris Moeller
1222c96268 Updated vgmstream to support BFSTM files 2014-10-19 14:09:45 -07:00
Chris Moeller
fea1b147a6 Enabled lazyusf HLE support by default 2014-10-14 22:33:05 -07:00
Chris Moeller
da4c4cf510 Removed unused variable 2014-10-14 22:32:50 -07:00
Chris Moeller
fb323d11e9 Implemented lazyusf HLE audio IIR function, thanks to JoshW 2014-10-14 22:32:26 -07:00
Chris Moeller
7115566476 Fixed handling Rar 5.x solid archives 2014-10-03 00:36:52 -07:00
Chris Moeller
63d255db7d Fixed vgmstream fading to return the correct block length on the start of the fade 2014-09-30 16:57:14 -07:00
Chris Moeller
d1095c3f72 Correct state reference to vibrato sine table 2014-09-30 16:40:34 -07:00
Chris Moeller
0e6d262236 ft2play auto-vibrato was wrong on every type except for sine 2014-09-30 16:37:06 -07:00
Chris Moeller
91c10ea197 Added a hack to playptmod to detect 7-bit versus 8-bit panning 2014-09-29 19:30:11 -07:00
Chris Moeller
f6bf26c58a Updated playptmod to version 1.15 2014-09-29 16:45:35 -07:00
Chris Moeller
43ea955190 Fixed my faulty vgmstream fade out routine 2014-09-28 18:11:44 -07:00
Chris Moeller
ea067ee410 Fixed incorrectly applied playptmod patch 2014-09-28 17:55:49 -07:00
Chris Moeller
2eb678b190 Fix for poorly converted STK->PTMOD modules. 2014-09-28 17:14:32 -07:00
Chris Moeller
318b2cfed8 Minor bug fixes to new unrar code 2014-09-20 22:21:08 -07:00
Chris Moeller
bfb319988f Updated unrar to version 5.1.7 2014-09-20 06:52:10 -07:00
Chris Moeller
0ccc0f4dae Fixed XML playlist saving on Yosemite 2014-09-16 18:27:14 -07:00
Chris Moeller
e7ba50b24f Fixed new Ogg and Vorbis projects to build Release target for Standard Architectures 2014-09-16 18:02:11 -07:00
Chris Moeller
f724ee471c Fix linking Opus framework 2014-09-16 17:59:28 -07:00
Chris Moeller
8dd97a141d Removed unsupported compile option 2014-09-16 17:57:22 -07:00
Chris Moeller
4d6c7f4917 Updated libogg and libvorbis to hopefully fix code signing issues 2014-09-16 17:54:40 -07:00
Chris Moeller
e7a8352548 And once again replace the Xcode specific build fixes that I clobbered 2014-09-16 16:55:15 -07:00
Chris Moeller
9bc9e47781 Updated vgmstream to revision 1039 2014-09-16 16:46:42 -07:00
Chris Moeller
cb1a699647 Implemented more stringent loop checking in ft2play 2014-09-14 17:51:48 -07:00
Chris Moeller
a7671023c4 moo 2014-09-05 23:28:01 -07:00
Chris Moeller
f2e0be8c9e Fixed feed URL, I hope 2014-09-05 23:25:32 -07:00
Chris Moeller
7f083607a1 Fixed playptmod vblank mode kicking in when length probe for vblank mode exceeds safety limit 2014-09-05 23:16:17 -07:00
Chris Moeller
014e03bda5 Overhauled volume ramping in modplay, and outright fixed it in ft2play 2014-09-05 23:05:20 -07:00
Chris Moeller
efcbb5be50 Hopefully fixed Sparkle this time 2014-09-03 10:18:28 -07:00
Chris Moeller
59868fb2c3 Oops again 2014-09-03 10:08:46 -07:00
Chris Moeller
54aa2b639b Oops 2014-09-03 09:49:14 -07:00
Chris Moeller
74114a3af2 Updated Sparkle framework 2014-09-03 09:47:40 -07:00
Chris Moeller
a5c0125b23 Updated ft2play to version 0.66 2014-09-03 09:47:31 -07:00
Chris Moeller
4a8deb992e Fixed playptmod offset command, and disabled offset bug handling for FT2 files 2014-08-19 23:02:10 -07:00
Chris Moeller
6ea578a23e Updated ft2play to version 0.65 2014-08-15 05:26:16 -07:00
Chris Moeller
1e33cabb7a Fixed building again 2014-08-02 21:29:00 -07:00
Chris Moeller
cc0f04d8f9 Updated vgmstream with experimental BFWAV support 2014-08-02 21:22:09 -07:00
Chris Moeller
3b5b53ca26 Removed old Sparkle files 2014-08-01 03:55:30 -07:00
Chris Moeller
41f6eb17bd Updated Sparkle framework 2014-08-01 03:53:07 -07:00
Chris Moeller
bce89e68ef Updated ft2play to version 0.64 2014-08-01 03:47:34 -07:00
Chris Moeller
ab5a8404d3 Fixed st3play Gxx with volume effect 2014-08-01 03:47:18 -07:00
Chris Moeller
7d4df7e1f2 Fixed code signing issues 2014-08-01 03:46:25 -07:00
Chris Moeller
05f57e9009 Fixed BASSMODS backward jumps counting toward loops 2014-07-07 20:19:29 -07:00
Chris Moeller
e3bc17302a Fixed BASSMODS seeking 2014-07-06 22:18:15 -07:00
Chris Moeller
75c565da0d Fixed HTTP streaming FFMPEG supported formats 2014-07-04 01:07:55 -07:00
Chris Moeller
3d26315db9 Project file fix 2014-07-04 01:07:30 -07:00
Chris Moeller
bda2b9e92e Implemented BASS IT and MO3 decoder, takes priority over DUMB 2014-07-02 23:05:25 -07:00
Chris Moeller
c469957035 Fixed IT playback to properly drop dead notes when performing volume ramping 2014-07-02 21:21:44 -07:00
Chris Moeller
b9136fcfd7 Fixed st3play initial pan position assignment in mono mode 2014-06-29 15:21:06 -07:00
Chris Moeller
0d8f42031e Updated vgmstream to r1034 2014-06-26 21:16:37 -07:00
Chris Moeller
a1f436587e Updated BASSMIDI library, now with SFZ instrument support, among other things 2014-06-24 16:13:34 -07:00
Chris Moeller
91b60e158a Fixed one case of PS2 MIB interleave detection 2014-06-24 16:13:10 -07:00
Chris Moeller
10316cfd06 Cleaned up ft2play loop handling and fixed bidirectional loops 2014-06-02 13:28:20 -07:00
soneek
cd5f1e0821 hcs's update for IMA decoder in vgmstream 2014-06-01 20:14:57 -07:00
soneek
bf5f0ebbaf Update RedSpark for M&L Dream Team 2014-05-26 00:10:40 -07:00
Chris Moeller
08453b00ae Fixed playptmod obeying MOD restart position 2014-05-24 17:53:02 -07:00
Chris Moeller
f090a8035c Update to work with some files found in Paper Mario: Sticker Star, thanks soneek 2014-05-23 16:42:46 -07:00
Chris Moeller
e3351e16c6 Fixed st3play handling 16 bit samples incorrectly 2014-05-22 00:02:16 -07:00
Chris Moeller
560efaf8b8 Fixed MIDI track repeat when the current file has no loop points 2014-05-11 19:27:09 -07:00
Chris Moeller
579451737c Fixed a cause for rounding errors in DUMB/modplay resamplers, which would have caused some extreme cases of samples to play too slowly 2014-05-11 17:41:09 -07:00
Chris Moeller
641302d597 Updated playptmod with several important bug fixes from eightbitbubsy 2014-05-10 18:12:34 -07:00
Chris Moeller
cb0c43fb5f Updated DUMB to fix two uninitialized variables 2014-05-10 18:11:58 -07:00
Chris Moeller
d8817e8f3b Fixed FFMPEG input hitting the end of the stream with samples already in the buffer causing it to live lock afterward 2014-04-26 15:38:45 -07:00
Chris Moeller
7876eed573 Fixed playptmod length detection when testing for vblank timing 2014-04-24 18:11:53 -07:00
Chris Moeller
1590770af6 Fixed vgmstream fsb5 path length limit 2014-04-23 22:26:53 -07:00
Chris Moeller
3e51816813 Undid damage to vgmstream.h on merging new changes 2014-04-23 22:13:33 -07:00
Chris Moeller
3e9f3f531e Fixed library include path 2014-04-23 22:02:40 -07:00
Chris Moeller
3c939042f1 Updated vgmstream to revision 1029 2014-04-23 21:55:48 -07:00
Chris Moeller
607f404361 Enabled MPEG audio support in vgmstream 2014-04-18 18:24:16 -07:00
Chris Moeller
be23bdb88a Oops 2014-04-16 19:02:12 -07:00
Chris Moeller
7028972f59 Hopefully final playptmod fix for IFF sample loops 2014-04-16 18:56:15 -07:00
Chris Moeller
59a94badcd Added a safety fix to playptmod for handling IFF headers in sample data with loops 2014-04-15 17:07:20 -07:00
Chris Moeller
10e80e2965 Updated ft2play to version 0.45 2014-04-12 14:06:49 -07:00
Chris Moeller
6c3c261ef9 Removed muffling cutoff from blip_buf and added a sinc generator, and changed playptmod vblank mode so it only applies to ProTracker mods and not any other tracker's formats 2014-04-11 18:23:53 -07:00
Chris Moeller
f0c3567214 Removed muffling cutoff from Hively Player blip buffer table, and threw in a generator 2014-04-11 17:42:00 -07:00
Chris Moeller
7b38371ca7 Updated Hively Player with cleaner filter generator source, and updated DUMB with more faithful tempo calculation 2014-04-11 16:35:54 -07:00
Chris Moeller
e0b4748d85 Replaced Hively Player filter function with original AHX player filter function 2014-04-10 17:35:16 -07:00
Chris Moeller
496f7870f8 ft2play is now safe for use on big endian machines 2014-04-08 18:06:00 -07:00
Chris Moeller
1737f4021d Updated ft2play to version 0.43a, which optimizes the RelocateTon function used by glissando tone slides and arpeggio effects 2014-04-08 17:06:24 -07:00
Chris Moeller
efcfa5bdb5 Don't include MSVC header since we're not compiling with MSVC 2014-04-08 15:11:41 -07:00
Chris Moeller
d3ba707339 Fixed modplay volume ramping terminating normal voices when something sets the volume to zero 2014-04-08 02:19:06 -07:00
Chris Moeller
dcf97c1ede Reverted a stupid change which broke 64 bit compilation of lazyusf 2014-04-07 18:21:12 -07:00
Chris Moeller
d53e363b1d Fix URL in update feed generator 2014-04-07 18:08:43 -07:00
Chris Moeller
cc0faa0b2e Fixed update script so it actually produces proper delta patches 2014-04-07 18:01:17 -07:00
Chris Moeller
033c086a37 Fixed gsub in update script 2014-04-07 17:45:18 -07:00
Chris Moeller
0fb8aa57bb Update LazyUSF and increased silence detection threshold for USF files to 10 seconds, which fixes Majora's Mask - Staff Roll 2014-04-07 17:42:09 -07:00
Chris Moeller
ef2c8efdf9 Update feed script again 2014-04-07 17:41:03 -07:00
Chris Moeller
a9eb5760ec Updated lazyusf 2014-04-07 12:46:26 -07:00
Chris Moeller
0a4046f2bf Added safety check to lazyusf for non-working sets; Now they'll fail with a useful error message instead of locking up in an infinite loop 2014-04-05 20:22:19 -07:00
Chris Moeller
47d3a8dffe Imported GCC fix for cpuid function 2014-04-04 21:50:18 -07:00
Chris Moeller
03fa21464f Updated sinc resampler with unscaled windowing, which improves resampling quality significantly when downsampling 2014-04-04 20:41:46 -07:00
Chris Moeller
01f086aa65 Updated st3play with accurate AdLib polyphony count and muting capability, not exposed in the UI 2014-04-04 20:41:12 -07:00
Chris Moeller
ec134e26e8 MSVC fix 2014-04-04 20:40:33 -07:00
Chris Moeller
bf4da4f5fb Updated vio2sf resampler as well 2014-04-04 17:05:26 -07:00
Chris Moeller
bc7de494e2 DUMB and modplay resampler now adds input delay and subtracts output delay according to whichever quality is selected, rather than being fixed for sinc only. This fixes blep synthesis mode defeating note on and off volume ramping. 2014-04-04 16:52:03 -07:00
Chris Moeller
00a014f270 Re-ported ft2play from original sources 2014-04-04 13:40:09 -07:00
Chris Moeller
0b436c8437 Compile fix for new changes to lazyusf 2014-04-04 13:39:54 -07:00
Chris Moeller
a8ca0c83ff More lazyusf rsp_hle fixes 2014-04-02 18:46:59 -07:00
Chris Moeller
e6da9d6db7 Updated lazyusf, mostly (unused by this plugin) HLE audio code 2014-04-02 17:54:43 -07:00
Chris Moeller
299704cc24 Updated lazyusf 2014-04-02 17:02:44 -07:00
Chris Moeller
ac71543e87 Changed comment for accuracy 2014-04-02 17:02:01 -07:00
Chris Moeller
0ddc1e9855 Oops 2014-04-01 14:16:07 -07:00
Chris Moeller
3264ce9154 Updated modplay 2014-04-01 14:12:54 -07:00
Chris Moeller
52e8c8f07d Updated vio2sf with multiple configurable resampling modes 2014-03-31 20:38:24 -07:00
Chris Moeller
c4288a8e61 Updated st3play with experimental AdLib support 2014-03-31 19:00:27 -07:00
Chris Moeller
55eec18bfe Updated ft2play and fixed up dbopl 2014-03-30 17:19:18 -07:00
Chris Moeller
0839cbbd9d Converted Dosbox fast FM emulator to C and imported it for inclusion in st3play 2014-03-30 03:19:18 -07:00
Chris Moeller
9a87f61e77 Removed some blank lines 2014-03-30 03:19:00 -07:00
Chris Moeller
f072c08a3c Updated ft2play to approximate parallel with version 0.40a 2014-03-28 19:48:38 -07:00
Chris Moeller
18fad4692b Fixed uploading feed xml to correct prefix 2014-03-28 18:08:39 -07:00
Chris Moeller
7a0aea53dd Made DUMB and modplay volume ramping more sensitive when transititioning to or from zero volume, and implemented Modplug ADPCM sample support into ft2play 2014-03-28 17:53:08 -07:00
Chris Moeller
4504bf1034 Changed update script 2014-03-28 03:11:15 -07:00
Chris Moeller
5618d058a3 Updated DUMB and modplay, and added a setting to control the resampling used by both, as well as by BASSMIDI, which will use sinc if specified 2014-03-26 21:49:31 -07:00
Chris Moeller
9d5a1fc32e Handled FLAC seeking to the end of file, and stopping on seek errors in general 2014-03-26 02:46:36 -07:00
Chris Moeller
104e4c140f Fixed seeking to the end of files with FFMPEG plug-in 2014-03-26 02:27:51 -07:00
Chris Moeller
aacffb9981 Fixed DUMB notes cutting/hanging 2014-03-26 02:27:28 -07:00
Chris Moeller
16b96c8ec8 Oops, I somehow seriously broke volume ramping prior to the previous release 2014-03-26 01:40:06 -07:00
Chris Moeller
fa3fba09be Fixed update script 2014-03-25 21:00:12 -07:00
Chris Moeller
d00e1d227d Updated modplay and DUMB, with no real major effects on playback 2014-03-25 20:37:11 -07:00
Chris Moeller
d1afe662b5 Update script now generates delta patches against the previous release, which should save user and myself some bandwidth 2014-03-24 20:24:52 -07:00
Chris Moeller
51f71732e1 Project file change, so modplay.bundle is not spuriously archived separately from the main app it is already installed into 2014-03-24 20:24:09 -07:00
Chris Moeller
9059e8f308 PSF/PSF2 playback now obeys refresh tags on .psflib files 2014-03-24 18:37:10 -07:00
Chris Moeller
018d6824bf Oops, accidentally made DUMB twice as loud as it should be 2014-03-24 18:07:01 -07:00
Chris Moeller
003aaeee19 Fixed resampler for large increment counts 2014-03-24 17:21:25 -07:00
Chris Moeller
94fcb71671 Reworked DUMB volume ramping ever so slightly 2014-03-24 16:58:50 -07:00
Chris Moeller
9aae7b9c41 Changed sinc window to Nuttal 3 term, and added silence pre-fill to account for the window delay 2014-03-23 21:05:58 -07:00
Chris Moeller
46815ba392 Updated DUMB and modplay 2014-03-23 13:29:14 -07:00
Chris Moeller
93b427ae4e Renamed Lanczos resampler to sinc resampler, changed window type to Blackman 2014-03-22 19:16:42 -07:00
Chris Moeller
f90ef2bf0c Added UMX support to the modplay plugin 2014-03-21 16:31:45 -07:00
Chris Moeller
3a08374551 Oops. 2014-03-21 16:19:35 -07:00
Chris Moeller
9369314725 Oops, bad math leaked through 2014-03-21 15:51:39 -07:00
Chris Moeller
7ae9f88e2a Updated ft2play, and implemented SSE optimizations in the Lanczos sinc resampler 2014-03-21 15:42:00 -07:00
Chris Moeller
a8b47ea0ed Fixed ft2play handling version 1.02 format files 2014-03-21 09:24:43 -07:00
Chris Moeller
e8766f1594 Skipping samples and song length detection with playptmod is now a lot faster 2014-03-21 08:04:19 -07:00
Chris Moeller
1b9fc96ed1 Updated DUMB 2014-03-21 07:16:44 -07:00
Chris Moeller
741271e153 Worked around two issues in DUMB's XM reader; Fixes dark lighthouse.xm 2014-03-20 22:37:11 -07:00
Chris Moeller
a567183510 Updated modplay, bringing volume ramping to st3play 2014-03-20 22:02:55 -07:00
Chris Moeller
bdd43b2a4b Updated modplay/ft2play, fixing a crash bug 2014-03-20 20:07:59 -07:00
Chris Moeller
de8df552c2 Updated modplay, and added safety checks to signature verification 2014-03-20 18:29:48 -07:00
Chris Moeller
a2ced7c506 Replaced st3play with modplay, which now brings ft2play support 2014-03-20 00:27:34 -07:00
Chris Moeller
f05e4764cb Updated st3play 2014-03-18 23:29:06 -07:00
Chris Moeller
38d287ac75 Updated st3play 2014-03-18 23:04:26 -07:00
Chris Moeller
e4d76dd1ca Added st3play plugin 2014-03-18 20:17:45 -07:00
Chris Moeller
1c68ad1c8d Modify update script to just fucking sign the file repeatedly until it validates 2014-03-16 21:51:08 -07:00
Chris Moeller
65d1a32ad5 Added missing file to the repository and fixed a serious crash bug handling .vb files 2014-03-16 20:36:50 -07:00
Chris Moeller
e0fe917356 Updated vgmstream 2014-03-14 22:43:51 -07:00
Chris Moeller
053bda3d92 Fixed LDS playback 2014-03-14 17:57:48 -07:00
Chris Moeller
27fc345488 Fixed MP3 decoding hanging at the end of the file 2014-03-12 20:39:01 -07:00
Chris Moeller
1b46139563 Changed update script to generate zip files using ditto instead, hopefully that will be less likely to break my code signatures on occasion like tar/bz2 has 2014-03-12 19:19:55 -07:00
Chris Moeller
704f04b8ce Fixed stupid errors compiling with Xcode 5.1 2014-03-10 22:06:48 -07:00
Chris Moeller
f77e44f7ad Adjusted playptmod volume levels again, hopefully for the last time 2014-03-10 21:59:10 -07:00
Chris Moeller
24a3573503 Updated FFMPEG, and enabled some new formats, including Atrac3+ 2014-03-09 21:16:37 -07:00
Chris Moeller
895cb7440f Fixed playptmod running indefinitely 2014-03-08 23:50:43 -08:00
Chris Moeller
0b42254e4b Updated playptmod, and now playptmod is unclipped and supports indefinite looping 2014-03-08 20:09:30 -08:00
Chris Moeller
ec40c5041c Updated LazyUSF 2014-03-08 18:36:59 -08:00
Chris Moeller
c6e4436366 Renamed LazyUSF audio HLE parts to match their original file names 2014-03-05 16:28:08 -08:00
Chris Moeller
5b456915f3 Added HLE audio to LazyUSF, disabled because it's incomplete 2014-03-04 21:39:37 -08:00
Chris Moeller
c75cfa27bd Updated DUMB 2014-03-04 17:21:07 -08:00
Chris Moeller
579f385a14 Minor cleanup in LazyUSF 2014-03-02 00:12:58 -08:00
Chris Moeller
5f88c6d882 Fixed 2SF and USF to read emulator setup tags from nested library files for playback 2014-02-26 16:37:56 -08:00
Chris Moeller
2c2f5b18c9 Real Ogg Vorbis fix for vgmstream 2014-02-26 01:36:37 -08:00
Chris Moeller
888fea57d3 Enabled Ogg Vorbis correctly this time 2014-02-26 00:28:24 -08:00
Chris Moeller
e67b072d91 Enabled Ogg Vorbis support in vgmstream 2014-02-26 00:14:50 -08:00
Chris Moeller
a4d0959623 Added vgmstream plugin 2014-02-25 23:50:54 -08:00
Chris Moeller
85cc09e07f Updated and fixed VGM OKIM6258 support from VGMPlay 0.40.4 2014-02-24 16:38:46 -08:00
Chris Moeller
d3d370b76e Removed unnecessary void declaration 2014-02-20 17:20:48 -08:00
Chris Moeller
5c4a4602db Added error logging to LazyUSF, player now stops on errors. 2014-02-20 17:07:57 -08:00
Chris Moeller
486ce41c7f Added documentation to LazyUSF public interface header 2014-02-20 16:11:43 -08:00
Chris Moeller
c438cc7ed1 Decreased xSF silence detection threshold to 5 seconds for all formats except for PSF and PSF2, improved USF sample rate detection, and fixed USF leading silence removal 2014-02-19 16:59:06 -08:00
Chris Moeller
34e95ff1c2 Updated LazyUSF and bumped its optimization settings 2014-02-18 17:20:37 -08:00
Chris Moeller
5bf11d551e Updated to latest LazyUSF 2014-02-18 00:05:23 -08:00
Chris Moeller
5e39b592d5 Fixed a number of warnings and function inlining in LazyUSF 2014-02-16 16:20:13 -08:00
Chris Moeller
5eb4b34e81 Bug fix in LazyUSF 2014-02-16 00:02:37 -08:00
Chris Moeller
1d3770757b Updated LazyUSF library 2014-02-15 23:38:46 -08:00
Chris Moeller
b02a0db5a4 Whoops. 2014-02-15 01:46:20 -08:00
Chris Moeller
f086d8c9bf Imported lazyusf in its new library form and removed the external app 2014-02-15 01:37:59 -08:00
Chris Moeller
6985aa3ae6 Updated LazyUSF binary 2014-02-14 01:23:04 -08:00
Chris Moeller
6e234756c1 LazyUSF input now ignores SIGPIPE, so the lazyusf process terminating abnormally won't cause Cog to terminate 2014-02-13 21:37:35 -08:00
Chris Moeller
9cd138384d Setting Repeat One will now direct all synthesizing decoders to run forever, rather than merely restarting repeatedly. Playptmod now cuts off length detection after half an hour, in case some files' loops are not detected. 2014-02-13 21:16:18 -08:00
Chris Moeller
7531b3324f Improved the robustness of the lazyusf communication process to terminate cleanly if the external process crashes or otherwise terminates improperly. Also updated lazyusf to terminate if its input pipe is broken during decoding. 2014-02-13 20:21:44 -08:00
Chris Moeller
f2b981acba Rewrote and enabled lazyusf support, now working properly 2014-02-12 23:34:52 -08:00
Chris Moeller
06b1058b47 YOU DEATH IST KNoW ME NoW 2014-02-05 17:49:56 -08:00
Chris Moeller
a614cc17b9 Added support for a pipe-fed console lazyusf player, currently disabled because it's horribly unstable 2014-02-05 17:35:02 -08:00
Chris Moeller
74689e0ff1 Sign application outside of Xcode, since passing the deep option there doesn't seem to sign everything in the app bundle 2014-02-03 21:24:59 -08:00
Chris Moeller
cafc0182f8 Change certificate parameter again, this time generic for any Developer ID 2014-01-19 19:07:56 -08:00
Chris Moeller
ad156b20a4 Changed certificate again, correct this time. 2014-01-14 00:44:40 -08:00
Chris Moeller
25f049beee Changed signing certificate to Mac Developer 2014-01-14 00:21:09 -08:00
Chris Moeller
060c0ebc27 Updated DUMB's unmo3 library to version 2.4.0.5, which fixes decoding MP3 compressed samples 2014-01-05 19:10:19 -08:00
Chris Moeller
78261d6469 Committed Sparkle changes to local git repository 2013-12-14 19:57:23 -08:00
Chris Moeller
142a144b08 Fixed some MIDI looping issues, and added support for RPG Maker loops 2013-12-14 19:56:59 -08:00
Chris Moeller
a87312b2da DUMB: Fixed DSMI AMF panning and sample loops 2013-12-02 23:11:50 -08:00
Chris Moeller
b3d19ba78c GSF: Boosted GB noise channel volume and programmed a basic equalizer preset for the GB channels 2013-11-28 01:47:48 -08:00
Chris Moeller
4c0a172075 Removed blip_buf.c from DUMB and replaced it with 32x oversampling through the Lanczos resampler 2013-11-23 19:01:37 -08:00
Chris Moeller
2f35443b66 DUMB module decoder automatically switches on Lanczos resampling when it guesses the target system is fast enough to handle it 2013-11-23 18:57:46 -08:00
Chris Moeller
9e9c50b5cf Added M_PI definition in case it's ever removed, since it technically isn't ANSI spec 2013-11-18 22:38:25 -08:00
Chris Moeller
0921d843d8 Reverted previous commit and added a correct playptmod fix 2013-11-18 22:27:01 -08:00
Chris Moeller
94c1ebf2a7 Fixed playptmod handling an invalid sample offset 2013-11-18 15:34:07 -08:00
Chris Moeller
092fdda05a Fixed FFMPEG seeking 2013-11-14 23:28:02 -08:00
Chris Moeller
f56edd882e Added extra safety checks to TagLib string union handling 2013-11-11 06:30:19 -08:00
Chris Moeller
ce56e727c9 DUMB: Added more architecture type guards to _USE_SSE blocks 2013-11-10 23:22:49 -08:00
Chris Moeller
8adfb9643d Made the DUMB inline assembly cpuid function specific to GCC/Clang like it should have been in the first place. 2013-11-10 22:35:54 -08:00
Chris Moeller
21db2de0cb IT pan and pitch envelopes now carry regardless of new note action being cut 2013-11-07 19:41:01 -08:00
Chris Moeller
3f12de6acd It is now possible to use both Gxx/Lxx and hx in the volume column in the same row 2013-11-07 19:05:06 -08:00
Chris Moeller
df5adae374 Fixed IT mixing Dxx regular volume slide with cx/dx volume column slide effect 2013-11-07 18:19:53 -08:00
Chris Moeller
f07374ecfe Simplified IT pan law and surround calculation 2013-11-07 18:18:57 -08:00
Chris Moeller
aa4d1223e3 Corrected DUMB surround differently, by inverting the left channel instead of the right 2013-11-07 17:19:50 -08:00
Chris Moeller
19a8e2d954 Fixed DUMB surround volume level, which was too loud after the pan law change 2013-11-07 15:06:23 -08:00
Chris Moeller
a4a8a8cc63 HighlyComplete will now stop filling its internal buffer when it has emulated enough to reach the tagged end of the track 2013-11-05 16:17:24 -08:00
Chris Moeller
c524bd406e Fixed HighlyComplete to properly seek when there are samples buffered 2013-11-05 16:04:34 -08:00
Chris Moeller
625ced97f3 Shortened a bit of the ID3v2 ReplayGain code 2013-11-05 15:49:56 -08:00
Chris Moeller
a6608b57c4 Fixed ID3v2 TXXX ReplayGain reading so it will properly skip over text frames with no description field instead of crashing 2013-11-05 15:37:54 -08:00
Chris Moeller
955ea5cdb9 Changed TagLib library project to emit debugging symbols 2013-11-05 15:37:22 -08:00
Chris Moeller
f005ee852c Changed Hively plugin project to not install itself 2013-11-05 15:36:59 -08:00
Chris Moeller
b80b3b1199 Fixed MP3 seeking when resync occurs before the first packet 2013-11-05 12:10:22 -08:00
Chris Moeller
045faf23a2 Increased MP3 resync tolerance to 64KiB, fixed footer tag detection, and made full file walk length checking happen only if the file is seekable 2013-11-05 01:32:29 -08:00
Chris Moeller
c5499691b2 Added better fault tolerance to file walk length detection and file walk seeking, and added a file end check to the seek function just in case 2013-11-05 00:37:51 -08:00
Chris Moeller
1d2c753b90 Fixed a few bundle identifiers 2013-11-04 15:18:21 -08:00
Chris Moeller
8451c45931 Fixed home directory location inside archives 2013-11-03 00:58:25 -07:00
Chris Moeller
dd2386aba8 Fixed another BASS include path 2013-11-03 00:52:06 -07:00
Chris Moeller
266688e893 Fixed BASS include path so it's relative to the MIDI PlugIn project location 2013-11-03 00:49:16 -07:00
Chris Moeller
b28705d5d9 Fixed MIDI looping 2013-11-03 00:44:01 -07:00
Chris Moeller
00c13ec061 Fixed HighlyComplete silence detection to handle DC offset silence 2013-11-01 16:57:07 -07:00
Chris Moeller
d898cf4f71 Added MO3 support 2013-11-01 12:24:59 -07:00
Chris Moeller
c6529888fd Hard limit only if output would clip, and use a table for up to 2x volume level 2013-10-31 18:20:58 -07:00
Chris Moeller
355df0b3b0 Fixed GME track length limiting when seeking backwards 2013-10-31 17:35:18 -07:00
Chris Moeller
2cfdacf890 Added a hard limiter to SPC playback instead 2013-10-30 17:58:29 -07:00
Chris Moeller
a02bc5000b Reduced SPC/SFM gain to 1.0, as a number of SPC files are too loud 2013-10-30 17:32:11 -07:00
Chris Moeller
2badd3dbff Fixed MP3 length detection when there is no VBR header by performing a full file walk 2013-10-30 11:58:07 -07:00
Chris Moeller
557e48253d Added HVL and AHX file types to list of registered file types 2013-10-29 17:35:51 -07:00
Chris Moeller
a3dfee75f8 Cleaned up minor warnings and removed unnecessary imports 2013-10-29 17:32:41 -07:00
Chris Moeller
d20973235b Implemented Hively Player support 2013-10-29 15:51:55 -07:00
Chris Moeller
240d7ae8ff Fixed playptmod checking for ADPCM samples 2013-10-29 11:09:51 -07:00
Chris Moeller
ee5821b45d Fixed SFM writing 2013-10-28 23:17:14 -07:00
Chris Moeller
bb0f0ed511 GME: Implemented functionality to update the metadata on an instance of gme_t, for SFM only. Also extended the SFM metadata to include log looping, track length/fade, and textual information. 2013-10-28 21:55:13 -07:00
Chris Moeller
9b7b8d5fd7 Fixed disassembler for MSVC 2013-10-27 15:21:51 -07:00
Chris Moeller
0a2dd30a51 Run SMP and DSP in less of a lockstep arrangement 2013-10-27 15:00:13 -07:00
Chris Moeller
9211827957 Removed unnecessary parentheses that I added 2013-10-27 13:25:23 -07:00
Chris Moeller
749ee9845c Seriously cut back on the crap with the SPC disassembler 2013-10-27 13:14:02 -07:00
Chris Moeller
117c574bbb Added another safety check, and fixed range checking on System Exclusive messages 2013-10-27 06:17:33 -07:00
Chris Moeller
969ec470e4 Implemented the SMP disassembler, for debugging purposes 2013-10-27 05:42:03 -07:00
Chris Moeller
031f36524e Added SMP ports to the SFM state, for keeping the last state of the ports in the event that the register log has or will run empty 2013-10-26 15:26:00 -07:00
Chris Moeller
2b40e87fee Yes, the SPC control register is supposed to clear its read ports, but SPC files aren't supposed to trigger that with their initial control register 2013-10-26 15:25:06 -07:00
Chris Moeller
fb07d985ea Simplified SPC register initialization and eliminated an unnecessary function 2013-10-26 14:47:36 -07:00
Chris Moeller
ec58587742 Yeah, byuu had SMP control port reset right the first time, I misinterpreted some other emulator code 2013-10-26 13:08:12 -07:00
Chris Moeller
4be3186b4c Implemented SPC/SFM tempo control, which the GME plugin doesn't use anyway 2013-10-26 11:12:50 -07:00
Chris Moeller
c07a38e59c Eliminated an extra 64 sample skip from seeking when playing at the native sample rate 2013-10-26 10:31:03 -07:00
Chris Moeller
be33e61644 Fixed SPC/SFM seeking 2013-10-26 10:30:36 -07:00
Chris Moeller
2aa6ee4378 Removed unnecessary files 2013-10-26 10:29:57 -07:00
Chris Moeller
b8b93103bf Added saving capability to GME, currently only supported by SFM 2013-10-26 09:00:59 -07:00
Chris Moeller
1c9b19af74 Added SFM to supported file types 2013-10-26 09:00:03 -07:00
Chris Moeller
49326f5492 Correctly use string::npos 2013-10-26 05:25:14 -07:00
Chris Moeller
0f4109284a Cleaned up some of Game_Music_Emu 2013-10-26 03:18:31 -07:00
Chris Moeller
cae86b582f Replaced snes_spc with higan accurate core, and enabled SFM support 2013-10-26 01:54:06 -07:00
Chris Moeller
d9971ee32f Added a multitude of safety checks to the MIDI file processor 2013-10-25 14:00:51 -07:00
Chris Moeller
80fe43cdd7 Fixed arpeggio 2013-10-24 20:11:52 -07:00
Chris Moeller
19af37059f Added -3dB normalized pan law to playptmod 2013-10-24 18:10:50 -07:00
Chris Moeller
c61b592f71 Increased xSF silence detection threshold even more for some stupid DSF rips. 2013-10-24 09:06:03 -07:00
Chris Moeller
5de4d2b3d7 Increased silence detection threshold 2013-10-24 04:35:30 -07:00
Chris Moeller
d99477f49f Fixed silence detection 2013-10-24 04:35:16 -07:00
Chris Moeller
af3a40bdc2 Added support for per-file SoundFonts, either named filename.ext.ext2, filename.ext2, or parentdirectoryname.ext2, where ext2 is sflist, sf2pack, or sf2, preferred in that order. 2013-10-23 22:53:39 -07:00
Chris Moeller
70dd117ba9 Updated the download link 2013-10-23 18:50:38 -07:00
Chris Moeller
6f8dc14ce1 Smarter actual fix for Sparkle 2013-10-23 16:25:58 -07:00
Chris Moeller
7af4e94b03 Removed signature application from individual projects and added --deep option to the main app project 2013-10-22 18:41:57 -07:00
Chris Moeller
9eb5e28cce Fixed compiling Sparkle with the 10.9 SDK 2013-10-22 18:41:32 -07:00
Chris Moeller
591730eea3 Fix the default updates feed URL setting, and override the current setting if it matches the former default 2013-10-22 17:46:33 -07:00
Chris Moeller
64149aa8c5 Rearranged playptmod a bit and fixed some warnings 2013-10-22 10:48:57 -07:00
Chris Moeller
231112389d Fixed the update feed script for real this time, I swear. 2013-10-22 10:12:55 -07:00
Chris Moeller
82d4d7b548 Implemented a MOD-only plugin based on my fork of eightbitbubsy's playptmod 2013-10-22 10:03:18 -07:00
Chris Moeller
87bf7bf833 Finalized the uploader script. 2013-10-22 10:02:28 -07:00
Chris Moeller
35ccee268e Update script once again attempts to compile the App bundle first, and pulls it from the Xcode DerivedData tree. 2013-10-22 04:18:58 -07:00
Chris Moeller
0f80bf3bc0 Hopefully fixed the update script. Of course, I can't seem to make xcodebuild compile the whole thing, so instead, I assume there is an archive built and extracted copy of Cog.app in ~/Documents. 2013-10-22 02:07:46 -07:00
Chris Moeller
da47da2631 Added Sparkle back 2013-10-21 19:17:51 -07:00
Chris Moeller
6b5a920751 Signed the BASS libraries 2013-10-21 19:06:51 -07:00
Chris Moeller
8e5dc2c250 And changed the update script 2013-10-21 18:31:48 -07:00
Chris Moeller
96c0081d73 Changed the AppCasts to https 2013-10-21 18:31:23 -07:00
Chris Moeller
1cc992f677 Whoops, made the update feed script executable 2013-10-21 18:29:57 -07:00
Chris Moeller
31580d41b8 Added back scripts, and modified the update_feed script 2013-10-21 18:29:13 -07:00
Chris Moeller
ad9a949c26 Turned on code signing 2013-10-21 18:28:53 -07:00
Chris Moeller
21102d3d77 Changed the default and included list of AppCasts 2013-10-21 18:27:36 -07:00
Chris Moeller
ce1d7bcbdc Restored the original feedback address 2013-10-21 18:26:57 -07:00
Chris Moeller
9a4be28903 The rest of the fix, it should fill the FIFO completely 2013-10-21 14:49:38 -07:00
Chris Moeller
c302db8755 Fixed Mother 3, and possibly other weird stuff 2013-10-21 14:32:14 -07:00
Chris Moeller
9c660b593a Whoops, fixed observer handling 2013-10-21 11:24:48 -07:00
Chris Moeller
63fba5930e Implemented support for multiple decoders per file name extension, with a floating point priority control per interface. In the event that more than one input is registered to a given extension, and we match that extension, it will be passed off to an instance of the multi-decoder wrapper, which will try opening the file with all of the decoders in order of priority, until either one of them accepts it, or all of them have failed. This paves the way for adding a VGMSTREAM input, so I can give it a very low priority, since it has several formats that are verified by file name extension only. All current inputs have been given a priority of 1.0, except for CoreAudio, which was given a priority of 0.5, because it contains an MP3 and AC3 decoders that I'd rather not use if I don't have to. 2013-10-21 10:54:11 -07:00
Chris Moeller
afa61559a5 Fixed URL open sheet 2013-10-21 06:43:46 -07:00
Chris Moeller
7835fe4930 Upgraded xib to Xcode 5 format, bah 2013-10-21 06:43:17 -07:00
Chris Moeller
01dd0b4306 On second thought, let's do that a little differently 2013-10-21 05:34:52 -07:00
Chris Moeller
c3ffa116c0 Fixed a serious bug with silence buffer filling 2013-10-21 05:33:48 -07:00
Chris Moeller
d44b2e8fce Fixed GSF playback for real this time 2013-10-21 05:33:22 -07:00
Chris Moeller
4c80ec01aa Improved NCSF playback and seeking by using a permanent buffer instead of allocating a new one on every readData or seek operation 2013-10-21 05:16:33 -07:00
Chris Moeller
290ed6c239 Fixed GSF playback 2013-10-21 05:13:48 -07:00
Chris Moeller
a8b01f16e3 Added start silence skipping and end silence detection 2013-10-21 02:52:43 -07:00
Chris Moeller
1e0303b1a3 Fix possible serious error which could result in overrunning the caller's buffer 2013-10-21 00:40:35 -07:00
Chris Moeller
849dcf6c29 Updated MPCDec to version 1.2.6 2013-10-21 00:39:44 -07:00
Chris Moeller
755147b48a Through a bit of ugliness and interface exposure, the InputNode will now pause the OutputNode while it is making the decoder seek, which prevents cases of the output continuing to run for seconds at a time during a slow seek operation by decoders such as HighlyComplete 2013-10-20 22:04:09 -07:00
Chris Moeller
761ea97e0e Corrected seeking function for Neill's emulators, most of which have a maximum number of samples they'll render per call; the seeking function also breaks out the instant that any of those cores return an error status 2013-10-20 22:02:59 -07:00
Chris Moeller
4764c5eacd Fix seeking before readAudio is called 2013-10-20 21:25:25 -07:00
Chris Moeller
1b4ef20d19 Added 'days' to playlist total time, but only if the total hours is 24 or greater 2013-10-20 21:16:07 -07:00
Chris Moeller
17b6af6417 Updated WavPack to 4.70.0, and this time around, updated the project preprocessor macro definitions and moved them out of the compiler command line arguments 2013-10-20 20:06:14 -07:00
Chris Moeller
e930372d1e Updated sflist preset control to match latest foo_midi, now supports multiple preset commands per group, and channel commands support hyphenated ranges 2013-10-20 17:30:59 -07:00
Chris Moeller
2e07cf29a0 Added sflist channel and preset redirection control, just like foo_midi 2013-10-18 21:01:19 -07:00
Chris Moeller
16396ad20a Fixed MIDI fading and stopping at the end 2013-10-18 18:52:59 -07:00
Chris Moeller
bc9d9458b4 Added a stop button to the play controls, handy for when playing a stream, which shouldn't really be paused. Also handy for other reasons. 2013-10-18 06:36:19 -07:00
Chris Moeller
5b13ee3f97 Fixed Ogg chained streams which I broke with the previous commit 2013-10-18 05:56:41 -07:00
Chris Moeller
8c80981827 Minor changes that may or may not have any impact on gaplessness 2013-10-18 05:33:38 -07:00
Chris Moeller
b9ce8462c4 Corrected gaplessness with my new converter setup 2013-10-18 05:33:20 -07:00
Chris Moeller
b461e774fd Fixed undo/redo handling when the playlist is sorted, including undo/redo interleaved with different sorting orders 2013-10-18 01:47:48 -07:00
Chris Moeller
3b8b948a1e Playlists are now saved as they have been rearranged in the UI 2013-10-18 00:43:55 -07:00
Chris Moeller
aa2676f605 Made duplicate and dead item removal correctly remove the items by their arranged indexes 2013-10-18 00:25:37 -07:00
Chris Moeller
2f5769d668 Made arranged item remover actually remove the correct arranged items and use the correct indexes 2013-10-18 00:17:03 -07:00
Chris Moeller
7a9e4a720c Added Remove Dead Items command 2013-10-18 00:14:53 -07:00
Chris Moeller
2d5f340011 Added Remove Duplicate Items command 2013-10-18 00:13:27 -07:00
Chris Moeller
22e7474e0e Fixed compiling the debug build; stupid search path behavior... 2013-10-17 23:55:38 -07:00
Chris Moeller
e149583f23 Fixed projects using multiple preprocessor definitions, where I accidentally used semicolons to separate them instead of spaces 2013-10-17 23:45:48 -07:00
Chris Moeller
39f4c60f19 Enabled DEBUG=1 macro in debug builds of several older projects 2013-10-17 23:39:26 -07:00
Chris Moeller
c94baaa299 Redid Growl icon conversion, this time cropping off empty space before resizing 2013-10-17 20:59:46 -07:00
Chris Moeller
de5fe2857f MIDI page now displays the filename of the currently selected SoundFont, or None if none has been loaded yet 2013-10-17 20:46:11 -07:00
Chris Moeller
53a52835dd Widened preferences panes to accomodate the added icons 2013-10-17 20:30:00 -07:00
Chris Moeller
eed50e0e2e Remade some of the icons, including 2x versions where possible 2013-10-17 20:07:25 -07:00
Chris Moeller
015a09d419 Fixes for non-looping file playback and precision handling on 32 bit targets 2013-10-16 10:03:40 -07:00
Chris Moeller
711da5fe24 Added MIDI container processor and metadata reader 2013-10-16 08:59:44 -07:00
Chris Moeller
870357a385 Archive container handler now skips files unsupported by the installed decoder plugins 2013-10-16 07:31:30 -07:00
Chris Moeller
34632b8a36 Whoops, forgot to increment the reference counter when a cache open finds a match 2013-10-16 03:30:49 -07:00
Chris Moeller
22f9e86fd1 Fixed std::chrono::duration shenanigans 2013-10-16 03:21:12 -07:00
Chris Moeller
cf3318c2c9 Replaced pthread and system time primitives with std::mutex, std::chrono, and std::this_thread::sleep_for, and fixed the thread iterator loop to continue iterating properly on object removal 2013-10-16 03:05:16 -07:00
Chris Moeller
71dcd91c6b Whoops, we weren't incrementing the sample counter for the PSG channels when using Lanczos resampling. Let's supersample them through the Lanczos resampler instead. 2013-10-15 20:51:28 -07:00
Chris Moeller
7128273201 Fixed fading, and fixed files to stop when they've reached the end 2013-10-15 12:58:45 -07:00
Chris Moeller
c3a4189ef4 Improved loop handling 2013-10-15 12:46:44 -07:00
Chris Moeller
2e553c7186 Fixed loop handling if only a loop start or end marker is found 2013-10-15 11:52:20 -07:00
Chris Moeller
1b9f74db68 Made some things static like they should be 2013-10-15 11:48:33 -07:00
Chris Moeller
e3fa04a57c Remove newly added entry from the cache if the font failed to load 2013-10-15 11:41:57 -07:00
Chris Moeller
99c1942eb3 Added a SoundFont handle cache, since BASSMIDI doesn't appear to employ reference counting on its SoundFont handles 2013-10-15 11:34:55 -07:00
Chris Moeller
7d600e1911 Fixed files ending when seeking 2013-10-15 11:30:18 -07:00
Chris Moeller
2c8f085a3d Clear the selection when adding items to the playlist, so that the info dialog will hopefully have some valid data next time a track is selected 2013-10-15 10:38:37 -07:00
Chris Moeller
617eae5c8e Added Properties item to playlist context menu to show the Info window 2013-10-15 08:22:40 -07:00
Chris Moeller
9d4da8ad7b Not installing MIDI bundle globally 2013-10-15 08:08:46 -07:00
Chris Moeller
2a6bca122a Whoops, forgot to copy midi_processing into the MIDI bundle, and also set its install path correctly 2013-10-15 08:01:30 -07:00
Chris Moeller
842932c322 Implemented a MIDI plug-in 2013-10-15 07:49:53 -07:00
Chris Moeller
ab97f832ed Added AMR-NB and AMR-WB decoders to FFMPEG, not needed for AMR files, though, since Core Audio handles them 2013-10-14 07:34:46 -07:00
Chris Moeller
fe90454d23 Updated the help book 2013-10-14 00:28:28 -07:00
Chris Moeller
33843a13d9 Changed resampler to use long sizes and pointers instead of int 2013-10-13 22:33:18 -07:00
Chris Moeller
ad7979f16e Updated psflib 2013-10-13 22:23:48 -07:00
Chris Moeller
05483d9c24 Fixed seeking backwards 2013-10-13 21:45:14 -07:00
Chris Moeller
22e518f242 Whoops, forgot to add the new files to the project 2013-10-13 21:39:46 -07:00
Chris Moeller
c3f90b4608 Updated vio2sf 2013-10-13 21:38:58 -07:00
Chris Moeller
e6d83fc936 Cleaned up most of the warnings, including a few cases where operator precedence would have caused unintended behavior 2013-10-13 19:54:09 -07:00
Chris Moeller
e7b3b61bff Fixed save state loading 2013-10-13 19:25:21 -07:00
Chris Moeller
e7d7295436 vio2sf now tries to queue up at least 1024 samples per execution loop 2013-10-13 19:10:42 -07:00
Chris Moeller
9d6f583eff Bypass sending notifications to Growl if Last.fm is enabled and running, as Last.fm has its own display notifications 2013-10-13 15:13:27 -07:00
Chris Moeller
2655f22b7d Remove const declaration from setrom, fix BOOL type for Win32, and fix a major mapping glitch that crept in during my massive transcription 2013-10-13 15:06:18 -07:00
Chris Moeller
ff03b6705b Handle the sync type as well 2013-10-13 13:39:53 -07:00
Chris Moeller
e86d0b488c Now passes on the initial frames and clockdown settings 2013-10-13 13:38:47 -07:00
Chris Moeller
cc31d2ddce Enabled linear interpolation 2013-10-13 13:29:53 -07:00
Chris Moeller
7e34ccd15a Shuffled around init/deinit of vio2sf state a bit 2013-10-13 13:21:56 -07:00
Chris Moeller
11fb240606 Fixed a memory leak 2013-10-13 13:16:11 -07:00
Chris Moeller
5f1c111bc7 Bumped minimum system version in the Info.plist 2013-10-13 13:02:49 -07:00
Chris Moeller
24b53c6e71 Implemented 2SF format support 2013-10-13 13:02:19 -07:00
Chris Moeller
9041ba977f Fixed Last.fm command queue crashing 2013-10-13 08:08:15 -07:00
Chris Moeller
70e571fed9 Now handling a race condition where the buffer is emptied between where it is read and where it is told how much has been read from it 2013-10-13 05:59:19 -07:00
Chris Moeller
a52c54a12c Initialize some pointers properly, and redesign to reallocate the converter buffer instead of freeing it every time 2013-10-13 05:14:57 -07:00
Chris Moeller
2997033e6b Added missing binding from PlaylistLoader to PlaybackController 2013-10-13 04:58:48 -07:00
Chris Moeller
088594dc8c Implemented clipboard support for the playlist view 2013-10-12 22:08:34 -07:00
Chris Moeller
1850f3be7d Fixed full view playlist undo/redo actions 2013-10-12 21:09:54 -07:00
Chris Moeller
208bf19ace Fixed track length/fade times in the event that someone has files with multiple values for those fields 2013-10-12 19:46:25 -07:00
Chris Moeller
b9a014ab16 Upgraded a couple of projects, raised the minimum OS version to 10.7, and removed libstdc++ setting from any projects that needed it 2013-10-12 19:18:46 -07:00
Chris Moeller
aa665c9a54 Silenced some warnings 2013-10-12 19:17:47 -07:00
Chris Moeller
759aeab4fb Implemented pause on startup 2013-10-12 19:16:47 -07:00
Chris Moeller
ee29955db0 Fixed build version info generator 2013-10-12 17:53:59 -07:00
Chris Moeller
e6a2773e8a XML playlists will no longer store metadataLoaded for files where an error occurred 2013-10-12 17:20:57 -07:00
Chris Moeller
26cf87a62e Oops, ChainQueue items should not be removed twice 2013-10-12 16:03:59 -07:00
Chris Moeller
e87fd1b4b7 Ryan Brignoni: Updating AppleRemote with latest files from VideoLAN repo and adding support for new 2009 Apple remote buttons in Cog. 2013-10-12 14:47:39 -07:00
Chris Moeller
505d145f94 Forgot to add SPMediaKeyTap files 2013-10-12 14:45:45 -07:00
Chris Moeller
5091d13fcb mamburu: Prevent starting Last.fm if Last.fm 2.x.x is already running 2013-10-12 14:43:46 -07:00
Chris Moeller
078caa7980 mamburu: Added an option to enable/disable giving up media keys control to Last.fm app 2013-10-12 14:41:57 -07:00
Chris Moeller
af76c33bb0 mamburu: Happy New Year commit (which accidentally fixes #83 - enqueueing from FileTree now respects playlist settings while FileTree context menu items still do what they say and don't depend on playlist settings). Also, the code should be cleaned up a bit, but i'm too sleepy to do it now. 2013-10-12 14:31:28 -07:00
Chris Moeller
85937086d2 mamburu: SPMediaKeyTap (https://github.com/nevyn/SPMediaKeyTap) is now used to handle media keys - iTunes won't start on Play button while Cog is running 2013-10-12 14:26:52 -07:00
Chris Moeller
35e8aa4db1 mamburu: 'Add to playlist' and 'Set to playlist' from the file tree context menu should now 'do what it says on the tin' (and not depend on playlist preferences setting) 2013-10-12 14:02:40 -07:00
Chris Moeller
c088011fd5 mamburu: Some more fixes 2013-10-12 14:01:21 -07:00
Chris Moeller
1b818bcaa7 mamburu: Fixed InputNode's thread not being stopped at all 2013-10-12 13:59:34 -07:00
Chris Moeller
56848daad6 mamburu: Fixed crashes when seeking near the end of stream 2013-10-12 13:52:58 -07:00
Chris Moeller
28e55334a6 Stupid Mercurial 2013-10-12 13:52:30 -07:00
Chris Moeller
97e94c0330 Updated TagLib 2013-10-12 13:51:36 -07:00
Chris Moeller
697ed357a9 mamburu: Being unable to remove an entry from playlist is fixed 2013-10-11 12:39:05 -07:00
Chris Moeller
521eb67183 mamburu: Randomizing playlist is now undoable, adding playlist entry no longer causes un-randomization 2013-10-11 12:33:58 -07:00
Chris Moeller
7b416e5877 mamburu: Info window now shows info for currently playing track in mini mode 2013-10-11 12:10:30 -07:00
Chris Moeller
012ef22b40 Major UI overhaul; Now supports mini mode 2013-10-11 12:02:05 -07:00
Chris Moeller
8cf6b86ba2 Moved NDHotKey to its own framework, and removed useless Edit buttons from the hotkeys preference pane 2013-10-11 09:37:45 -07:00
Chris Moeller
2fe9e86eb9 Added optional colorful dock icons by tuurngait; Imported the Growl configuration page for disabling notifications if Growl.app is not installed 2013-10-11 08:35:57 -07:00
Chris Moeller
613c71c41f mamburu: Fix for a crash caused by some weird flacs that have multiple STREAMINFO metadata blocks with wrong values 2013-10-11 07:25:41 -07:00
Chris Moeller
d5573c1e14 tuurngait: New Icons 2013-10-11 07:22:15 -07:00
Chris Moeller
d1f6ec850e tuurngait: Major UI Improvements 2013-10-11 07:16:47 -07:00
Chris Moeller
97f6e8b472 mamburu: Made clicking on pop-up menu items of path control inside spotlight panel work 2013-10-11 06:35:53 -07:00
Chris Moeller
ca0b43de0f mamburu: Reading dates from cue fixed 2013-10-11 06:20:08 -07:00
Chris Moeller
5e886338d8 Changed contact address in compiling guide 2013-10-11 06:17:29 -07:00
Chris Moeller
7f449edc14 mamburu: Fixed hanging/crashing on directory change in spotlight panel 2013-10-11 06:13:57 -07:00
Chris Moeller
eef7ac383c mamburu: Added cycling through shuffle and repeat modes with keyboard shortcuts 2013-10-11 06:10:54 -07:00
Chris Moeller
053b09ba1b mamburu: Whether to show remaining time or elapsed time now survives restarts 2013-10-11 05:53:37 -07:00
Chris Moeller
74db595a2d mamburu: Better titles for game music containers 2013-10-11 05:48:19 -07:00
Chris Moeller
eab60596eb mamburu: Display track titles from cue in file tree 2013-10-11 05:45:08 -07:00
Chris Moeller
06378252c0 Fixed adding single contained entry to playlist for cue, dumb, and gme containers 2013-10-11 05:41:36 -07:00
Chris Moeller
d98b5549d1 mamburu: Only launch last.fm client if it isn't already running (prevents last.fm client's window from popping up on Cog restarts) 2013-10-11 05:37:11 -07:00
Chris Moeller
73524776e7 mamburu: Added a toolbar button to shuffle the playlist 2013-10-11 05:27:19 -07:00
Chris Moeller
e5a648578b mamburu: Logging improved, no more excessive logging in release builds 2013-10-11 05:03:55 -07:00
Chris Moeller
602aaa6938 Enter Full Screen menu item and separator are now hidden until the main window wakes and detects toggleFullScreen selector 2013-10-11 03:39:57 -07:00
Chris Moeller
3f35b5e07f mamburu: Expandedness state of file drawer is now persisted over app restarts 2013-10-11 03:03:23 -07:00
Chris Moeller
0ad3106355 mamburu: Added bar that shows name of currently playing entry 2013-10-11 02:09:26 -07:00
Chris Moeller
984502469a mamburu: Added menu item for going fullscreen so that systemwide keybindings for fullscreen mode work 2013-10-11 01:46:18 -07:00
Chris Moeller
62695ecf30 Added automatic version generator script 2013-10-11 01:31:13 -07:00
Chris Moeller
1aedb01c6b Changed feed and feedback URLs 2013-10-11 01:30:49 -07:00
Chris Moeller
6afc7a0bad Added more file types to documents list; Changed feed URL 2013-10-11 01:30:07 -07:00
Chris Moeller
4d7b96107b Added TrueAudio support 2013-10-10 23:51:19 -07:00
Chris Moeller
570fd380f8 Added a whole bunch of formats for WAV support 2013-10-10 23:25:26 -07:00
Chris Moeller
21b78fde9f Added DCA/DTS/DTS-HD support 2013-10-10 22:13:27 -07:00
Chris Moeller
de467b38d6 Added AC3 decoder to FFMPEG plugin 2013-10-10 21:53:28 -07:00
Chris Moeller
fd9d9a7065 Fixed several bugs with decoding audio 2013-10-10 21:52:32 -07:00
Chris Moeller
4aab503658 Removed APE tag reader from APL plugin and enabled stub APE tag reading of APE tags from APL files in the TagLib plugin 2013-10-10 21:49:16 -07:00
Chris Moeller
a9982e9c80 Removed the separate Monkey's Audio decoder and MAC framework 2013-10-10 20:55:51 -07:00
Chris Moeller
51dc6fae15 Enabled APE support and reworked FFMPEG decoder according to the mamburu fork 2013-10-10 20:55:32 -07:00
Chris Moeller
84474c5002 Added APE decoder to FFMPEG 2013-10-10 20:53:17 -07:00
Chris Moeller
c29583ec42 Fixed ConverterNode listener 2013-10-10 20:02:02 -07:00
Chris Moeller
442501c43f Lion full screen mode support 2013-10-10 18:14:35 -07:00
Chris Moeller
02ac3299ed Changed bundle identifiers again 2013-10-10 17:44:25 -07:00
Chris Moeller
27ad43346f Changed application category; Minor changes to Info.plist caused its structure to be reordered a bit 2013-10-10 17:44:12 -07:00
Chris Moeller
df76c887fb Added tag k54 for changeset ddfc3989351f 2013-10-10 17:38:05 -07:00
Chris Moeller
25fa7dd929 Added tag r516 for changeset 4abdff3798f8 2013-10-10 17:37:11 -07:00
Chris Moeller
cee6ab4b8f Changed more bundle identifiers; Added NCSF player to HighlyComplete, which necessitates using libc++, forcing this plugin to require 10.7 2013-10-10 17:13:18 -07:00
Chris Moeller
dda7bf994d Whoops, forgot to enable generating debugging symbols for the release targets in those projects 2013-10-10 04:52:15 -07:00
Chris Moeller
0ca7c2ee2f Enabled DWARF with dSYM for release target on all projects 2013-10-10 04:41:25 -07:00
Chris Moeller
5ade3931d3 Corrected bundle identifiers 2013-10-10 04:28:04 -07:00
Chris Moeller
ba75b15385 Updated minimum system version and document types list 2013-10-10 04:27:50 -07:00
Chris Moeller
cade82ee64 Removed unnecessary variable 2013-10-10 03:41:59 -07:00
Chris Moeller
3e057adf56 Replaced every instance of NSEnumerator with for/in loops 2013-10-10 01:44:45 -07:00
Chris Moeller
8d19b2538a XML playlist now stores and loads the playback queue 2013-10-10 01:43:04 -07:00
Chris Moeller
7d6cfe50df Prevent XML playlists from being saved by the GUI 2013-10-10 00:39:35 -07:00
Chris Moeller
81c62891bd Added support for iTunSMPB to MP3 parser; Replaced crappy MP3 seek function with accurate full file parse with 8 packet pre-roll; Changed top level decoder plugin to truncate output at the specified duration 2013-10-09 21:23:50 -07:00
Chris Moeller
754a22166a XML playlists now store album art in an MD5 hash indexed dictionary, but continue to read the older format for backwards compatibility 2013-10-09 16:14:23 -07:00
Chris Moeller
555ccc9e87 Now storing all album art internally as its original format and synthesizing NSImage objects on demand 2013-10-09 13:53:13 -07:00
Chris Moeller
a63e27f95c Fixed preferences page to only list output devices 2013-10-09 13:52:39 -07:00
Chris Moeller
d1e51ee9a1 We shouldn't be releasing objects that belong to something else 2013-10-09 11:51:41 -07:00
Chris Moeller
742f1388a6 Sort directory nodes above file nodes 2013-10-09 11:30:09 -07:00
Chris Moeller
203109ebc3 Sort paths by name 2013-10-09 11:29:59 -07:00
Chris Moeller
6008d93a6d Added bindings for repeat and shuffle buttons, which fixes their tool tips 2013-10-09 10:48:38 -07:00
Chris Moeller
1743016e71 Fixed serialization of FilePlaylistEntry; Added serialization and unserialization of album art 2013-10-09 10:34:32 -07:00
Chris Moeller
66f3d69648 Changed to use non-deprecated function 2013-10-09 10:33:22 -07:00
Chris Moeller
b5fd1207b8 Now saves and loads the default playlist in an XML plist format, so loaded metadata is cached 2013-10-09 08:45:16 -07:00
Chris Moeller
b4ffb2684f Removed pause on startup, since it doesn't seem to have any effect 2013-10-09 02:08:35 -07:00
Chris Moeller
3e579801a1 AppController now stores the last playback status and position in the defaults container and resumes playback on restart 2013-10-09 02:02:49 -07:00
Chris Moeller
bbb5549873 Added MPEG Audio support to FFMPEG plugin, which also supports proper seeking in VBR files; Fixed decoding of files which contain multiple streams 2013-10-08 23:57:58 -07:00
Chris Moeller
707bc85e24 Removed MAD plugin 2013-10-08 23:56:49 -07:00
Chris Moeller
b23733277c Added m3u8 extension to m3u plugin 2013-10-07 20:27:38 -07:00
Chris Moeller
1123dc6b91 Whoops, forgot to remove the volume scaling option observer when cleaning up ConverterNode 2013-10-07 20:21:34 -07:00
Chris Moeller
380993ff16 Move forced metadata lookup to PlaybackController so ReplayGain information will always be available when it's needed 2013-10-07 16:15:15 -07:00
Chris Moeller
cdafef8a9c Fixed handling ReplayGain info on automatic track changes 2013-10-07 13:03:34 -07:00
Chris Moeller
2837b12d32 Fix unsigned reporting, and can't match unsigned type declaration exactly 2013-10-07 11:26:23 -07:00
Chris Moeller
0d89cf2e6f Quick fix in case something throws 8 bit samples at us 2013-10-07 11:19:02 -07:00
Chris Moeller
640a2f54c6 Fixed bitrate reporting 2013-10-07 11:12:25 -07:00
Chris Moeller
2f730e1822 Added TAK support 2013-10-07 11:09:38 -07:00
Chris Moeller
a8df4ddab5 Renamed WMA projects to FFMPEG, for future expansion 2013-10-07 10:33:35 -07:00
Chris Moeller
e1fc6da376 Fixed Asylum Music Format panning effect 2013-10-07 08:10:21 -07:00
Chris Moeller
15c545b10d Fixed input to float conversion and made it mandatory, so I could move volume scaling to the converter node 2013-10-07 03:59:04 -07:00
Chris Moeller
8aa01894ee Added downmixing of surround for stereo output devices 2013-10-07 00:24:26 -07:00
Chris Moeller
167524b6f2 Added basic output device channel mapping support 2013-10-07 00:24:00 -07:00
Chris Moeller
7a4e297828 Fixed fading 2013-10-05 15:47:35 -07:00
Chris Moeller
74b6188772 Implemented floating point sample format support into CogAudio and all relevant plug-ins 2013-10-05 14:15:09 -07:00
Chris Moeller
b16ccd59f7 Fixed bitrate handler 2013-10-05 02:47:25 -07:00
Chris Moeller
8838b65b30 Fixed nesting of Ogg framework 2013-10-05 02:35:27 -07:00
Chris Moeller
525e296cc7 Implemented Opus decoder and tag reader 2013-10-05 02:01:33 -07:00
Chris Moeller
ba69558a99 Hard coded bits per sample, as it should be 2013-10-05 02:00:25 -07:00
Chris Moeller
2426d7f7fd Implemented native file reader protocols for avformat so it uses CogSource to read files 2013-10-04 20:57:46 -07:00
Chris Moeller
66925054e9 Added J2B and UMX archive support 2013-10-04 19:25:45 -07:00
Chris Moeller
718829aabe Now limited to playing two loops with an 8 second fade, as the previous position fetching method was broken by my own changes to DUMB which cause the position to wrap back around on every loop 2013-10-04 17:23:11 -07:00
Chris Moeller
e733074c01 Whoops, forgot to bundle File_Extractor into FileSource 2013-10-04 16:43:19 -07:00
Chris Moeller
46607c8d65 Added subsong support 2013-10-04 16:34:29 -07:00
Chris Moeller
1def63e087 Removed non-archive extensions 2013-10-04 16:33:42 -07:00
Chris Moeller
33b49c3de4 Added transparent archive unpacking of the first contained within the archive, for any non-archive file name extension 2013-10-04 16:32:58 -07:00
Chris Moeller
145dd84c35 Whoops, last File_Extractor update broke rarvm, reverted that mess and fixed all the warnings with casting 2013-10-04 16:31:10 -07:00
Chris Moeller
d76c1c2210 Now using GME to regulate track length with an 8 second fade 2013-10-04 13:33:39 -07:00
Chris Moeller
54349ba1f2 Added fade length to C API 2013-10-04 13:33:14 -07:00
Chris Moeller
52c947db10 Changed all sub-component projects to skip install, since copy steps bundle them all into the target app 2013-10-04 13:11:32 -07:00
Chris Moeller
121d7a73e9 Fixed a C11 warning by adding a macro lock around blip_t declaration 2013-10-04 13:11:04 -07:00
Chris Moeller
71e05cd4b6 Fixed up warnings 2013-10-04 12:55:02 -07:00
Chris Moeller
5e73c363fb Project changes 2013-10-04 12:54:45 -07:00
Chris Moeller
d0c84ed9e5 Removed user settings from repository 2013-10-04 10:58:21 -07:00
Chris Moeller
8ac55b2e27 Added missing files and updated .hgignore file 2013-10-04 10:54:40 -07:00
Chris Moeller
936e8a07f5 Fix and enable SSE support 2013-10-04 10:50:16 -07:00
Chris Moeller
b032f06f6f Fixed header comments 2013-10-04 09:01:34 -07:00
Chris Moeller
432ba909cc Added VGZ to extensions list 2013-10-04 09:00:32 -07:00
Chris Moeller
23d4f90a1c Fixed GME container parser to support CogSource 2013-10-04 09:00:18 -07:00
Chris Moeller
44da1bda00 Fixed a serious bug with Std_File_Reader setting unbuffered mode 2013-10-04 08:59:33 -07:00
Chris Moeller
810d58b4fe Made necessary changes to facilitate metadata reading from arbitrary file sources, like archives 2013-10-04 08:14:47 -07:00
Chris Moeller
1c37cefae6 Added ArchiveSource to project 2013-10-04 08:14:22 -07:00
Chris Moeller
1be4894b25 Added ArchiveReader plug-in based on File_Extractor 2013-10-04 08:13:30 -07:00
Chris Moeller
7c5eaed629 Added now playing spam hotkey, currently format hard coded 2013-10-04 04:16:09 -07:00
Chris Moeller
a5d8401477 Added more safety checks and basic seeking support to WMA plugin 2013-10-03 03:44:39 -07:00
Chris Moeller
132fe98e84 Added APE and ASF tag support 2013-10-03 02:56:41 -07:00
Chris Moeller
9827964b63 Added XWMA extension and some other MIME type 2013-10-03 02:56:07 -07:00
Chris Moeller
3c49691393 Fixed the preferences window, which became borderless with the switch to a newer base SDK 2013-10-03 01:42:45 -07:00
Chris Moeller
ec0e45381e Cleaned up most of the warnings, eliminated use of deprecated APIs, and fixed the hotkeys crashing. 2013-10-03 01:00:58 -07:00
Chris Moeller
51cc8a69e5 Fixed FPM selection for debug and release targets 2013-10-02 15:12:16 -07:00
Chris Moeller
712b7ac789 Whoops. 2013-10-02 15:11:56 -07:00
Chris Moeller
5a4a450dea Changed all projects to use latest SDK and build 32/64 bit Universal, and target for deployment on 10.6 2013-10-02 14:59:22 -07:00
Chris Moeller
965c6e2446 Updated WMA plug-in to latest ffmpeg, and enabled WMA Pro, WMA Voice, and WMA Lossless support 2013-10-02 14:58:18 -07:00
Chris Moeller
4c0cf34250 More ReplayGain support, now with metadata handling, but only if the metadata is already loaded 2013-10-02 02:30:04 -07:00
Chris Moeller
6ea103b1c3 Implemented ReplayGain support, so far only in the HighlyComplete component. 2013-10-01 23:00:16 -07:00
Chris Moeller
5d141f1d70 Added file storage dictionary, so that psflib can recycle CogSource objects passed into the decoder. Also fixes issues of various file objects being leaked 2013-09-30 18:20:31 -07:00
Chris Moeller
4d51c93c39 Reworked Highly Complete to only initialize the respective decoder core when starting playback, which greatly speeds up playlist metadata info retrieval 2013-09-30 13:35:03 -07:00
Chris Moeller
b002fed263 Wink, wink, nudge, nudge 2013-09-30 13:33:52 -07:00
Chris Moeller
e644c56511 Added link for binaries 2013-09-30 12:54:46 -07:00
Chris Moeller
2a58a18d84 Amended README 2013-09-30 12:53:50 -07:00
Chris Moeller
c31415f4b6 Fix new WavPack inclusion in OS X project 2013-09-30 12:43:21 -07:00
Chris Moeller
43704d16ce Updated WavPack to version 4.60.1 2013-09-30 12:33:50 -07:00
Chris Moeller
63b8f55dcf Fixed WavPack floating point input handling 2013-09-30 12:31:16 -07:00
Chris Moeller
87198d04c0 Minor bugfix so GSF decoder doesn't slowly overbuffer into oblivion 2013-09-30 09:17:56 -07:00
Chris Moeller
0b966e9014 Whoops, fixed installation directories so the frameworks load properly when bundled 2013-09-30 04:09:11 -07:00
Chris Moeller
fdabbca701 Replaced AudioOverload with HighlyComplete 2013-09-30 03:36:30 -07:00
Chris Moeller
b9d451c96f Corrected base classes to silence warnings 2013-09-29 18:59:04 -07:00
Chris Moeller
3921d51df5 Forgot one nil return condition 2013-09-29 18:58:24 -07:00
Chris Moeller
83d59d0c13 BlankZeroFormatter now returns an empty NSString instead of nil, which was causing an unhandled exception that locked up the window 2013-09-29 17:30:23 -07:00
Chris Moeller
d8787c2016 Only keep DUMBFILE and DUMBFILESYSTEM local to open function, and eliminate unnecessary close callback 2013-09-29 17:28:58 -07:00
Chris Moeller
25bf55459e Silenced some warnings 2013-09-29 17:27:55 -07:00
Chris Moeller
a93ec7b95f Added automatic detection of SSE support for x86 and force on for x64 2013-09-29 17:27:13 -07:00
Chris Moeller
fa6b5d4290 Changed debug target to 32-bit so I can debug with the 10.6 SDK target 2013-09-29 17:25:22 -07:00
Chris Moeller
8970aedb17 Updated Growl framework 2013-09-27 20:33:51 -07:00
Chris Moeller
3d11f8b144 Removed Scripts 2013-09-27 20:33:11 -07:00
Chris Moeller
7ada3013c4 Removed Sparkle 2013-09-27 20:32:42 -07:00
Chris Moeller
0ee11cb9a1 Minor fixes to Game_Music_Emu 2013-09-27 20:31:49 -07:00
Chris Moeller
5c0cf35a1a Updated Game_Music_Emu 2013-09-27 20:24:46 -07:00
Chris Moeller
17682d4397 Updated DUMB 2013-09-27 20:24:23 -07:00
vspader
d969f5a6a7 Merged changes from master. 2010-10-26 20:47:38 -07:00
vspader
8d8f36824e Fix bug in HTTP response header parsing. 2010-10-26 20:47:14 -07:00
mscott
1269de06f9 Add artwork fetch from image file in directory when no embedded image is found (looks for image files named or ending with "cover", "folder", "album" or "front").
Clean up playlist popup menu validation.
2010-04-05 12:40:17 -05:00
vspader
f1b965bf12 Patch from T. Million for 24-bit mad output. 2009-11-30 20:18:47 -08:00
vspader
ede099be25 Revert incorrect leak fix. 2009-09-02 20:10:55 -07:00
vspader
288c5cbee5 Misc leaks fixes. 2009-09-01 21:14:07 -07:00
vspader
50326dfed8 Tweaked compiler settings for Shorten framework. 2009-09-01 21:00:10 -07:00
vspader
56b50c509f Updated all subprojects to use the 10.5 SDK. 2009-08-16 10:58:44 -07:00
vspader
7b2cc6481a Updated hgignore to exclude build directories. 2009-08-16 10:58:28 -07:00
vspader
656fc0a113 Moved project to 10.5 SDK. Fixed warnings. 2009-08-16 10:56:49 -07:00
mscott
11352ab6de Enhancements to File Tree (contextual menu, sort order, etc.).
Added File Tree contextual menu (Add to Playlist, Show in Finder, etc.).
File Tree and additions to play list now use Finder sort order.
File Tree Root can be set via its popup menu or drag and drop from File Tree.
Alias names are now shown in File Tree (aliases are still resolved).
Added option to skip reading of cue sheets when adding a folder to play list.
2009-08-16 11:49:34 -05:00
vspader
90ae894156 Added error check for GME plugin to stop crashes on unsupported files. 2009-07-15 19:11:55 -07:00
vspader
a531e31d42 Force stereo output. Ugly hack, but it's unlikely non-stereo was working properly anyways. 2009-06-28 11:57:48 -07:00
vspader
b795030bde Merged in changes. 2009-06-28 10:52:58 -07:00
vspader
170c8cb2f3 Fixed bug where audio device was set after the format. 2009-06-28 10:51:30 -07:00
vspader
a0778d5c4f Fixed up last.fm scrobbling. 2009-03-27 20:00:45 -07:00
vspader
7e3f257090 Fix shuffle. 2009-03-24 20:12:52 -07:00
vspader
81bd339bca Added minimum system version. 2009-03-21 09:54:55 -07:00
vspader
5422a1cddd Assume / for path if none is present in a url. 2009-03-13 23:33:11 -07:00
vspader
26d44d6f37 Fix Growl so it only shows up on non-error tracks and display album art in the notification. 2009-03-11 20:26:29 -07:00
vspader
16625112af Fix bug when loading saved orientation. 2009-03-11 20:26:02 -07:00
vspader
0d1398e0fb Added ToolTipTextField class, whos tooltip is the same as the text displayed, but untruncated. 2009-03-09 21:59:27 -07:00
vspader
9a59a03d3b Added blank zero formatter to year.
Added tooltips to info fields.
2009-03-09 21:59:00 -07:00
vspader
c6adec506b Fixed info inspector resizability and such. 2009-03-09 21:44:53 -07:00
vspader
7819210b96 Added interface for shuffle albums mode. 2009-03-09 21:04:46 -07:00
vspader
30f6ac7e70 Fixed compilation error. 2009-03-08 22:12:44 -07:00
vspader
290aba1af4 More memory leak fixes in cue sheets. 2009-03-08 13:19:25 -07:00
vspader
28c77f0814 Fixed memory leak in cue sheets. 2009-03-08 13:17:45 -07:00
vspader
7491fd3bf0 Support for album art metadata. 2009-03-08 13:04:09 -07:00
vspader
bd523075a4 Some small info inspector tweaks. 2009-03-07 20:44:39 -08:00
vspader
ebc58a996e Merged pbx changes. 2009-03-07 18:40:09 -08:00
vspader
4bed0971b3 Forgot to add/remove files for Preferences. 2009-03-07 18:38:25 -08:00
Vurlix
d248b28c17 remove user-specific project settings for Preferences/General; ignore such files from now on 2009-03-07 21:32:51 -05:00
vspader
2062f3e2d1 Added trimming to the inspector fields. 2009-03-07 17:54:42 -08:00
vspader
38a98a1a8e Reworked and reorganized the preference panes. 2009-03-07 17:49:50 -08:00
vspader
620c03b5eb Removed unused update window. 2009-03-07 15:11:48 -08:00
vspader
6bf90d29f4 Removed unused Update Window from xib. 2009-03-07 15:11:39 -08:00
vspader
9e61f300ef Fixed up Feedback class. Moved it into its own xib. 2009-03-07 15:08:43 -08:00
vspader
9da889630d Fixed file tree colors so they are the same when not activated. 2009-03-07 14:44:04 -08:00
vspader
53a43e5e20 Fixed info button and file tree buttons. 2009-03-07 14:40:22 -08:00
vspader
4a8e59c91e Fixed initial sideview defaults. 2009-03-07 14:35:39 -08:00
vspader
4c7ee96f76 Added Info Inspector.
Moved Formatters into their own folder.
2009-03-07 14:31:57 -08:00
vspader
a1a50b6f8b Moved Spotlight panel into English.lproj. 2009-03-07 13:38:25 -08:00
vspader
b79346e3b1 Fixed up file tree. 2009-03-07 13:31:44 -08:00
vspader
404e309160 Fixed shuffle in the menu. 2009-03-07 12:02:22 -08:00
vspader
d2235536c5 Fixed nil sent to NSAttributedString. 2009-03-07 11:52:42 -08:00
vspader
515be1f20e Fixed xib so position slider bindings are correct. 2009-03-07 11:49:04 -08:00
vspader
98b5d78425 Removed useless setContentBorderThickness call from the mini window because it messed with dragging the window. 2009-03-07 02:41:06 -08:00
vspader
f363423323 Fixed off by one error. 2009-03-07 02:20:30 -08:00
vspader
d391d8c616 Added a couple of explanatory comments. 2009-03-07 02:11:33 -08:00
vspader
54c0d3b38d Moved HTTPSource back to plain ol' objc. 2009-03-07 02:09:04 -08:00
vspader
93fb841f60 Removed JNetLib. 2009-03-07 02:07:31 -08:00
vspader
d468f240e7 Tweaked the HTTP Connection class so it uses ASCII encoding. 2009-03-07 02:06:09 -08:00
vspader
a19e3f3b8c Removed JNetLib reference. 2009-03-07 01:25:38 -08:00
vspader
870620c2b8 Brought back custom socket class. Added HTTPConnection class to handle blocking HTTP connections. 2009-03-07 01:25:13 -08:00
vspader
bf7b2c0a2b Added timeout and chillout logic to the HTTP source so it doesn't freak out when there's no data available. 2009-03-06 21:58:50 -08:00
vspader
2b55b8978b Reverted boneheaded change. 2009-03-06 21:40:58 -08:00
vspader
4eee66d16a Fixed bug where connection errors caused 100% cpu. 2009-03-06 20:39:33 -08:00
vspader
7cbebef352 Fixed up metadata loading so metadata isn't always read when you play. 2009-03-05 20:46:42 -08:00
vspader
d6a0b0670e Playback events for last.fm and growl are now done in the background via an operation queue. Removed hack to load metadata for autoplay. Now metadata is reloaded for each file you play. 2009-03-05 20:37:44 -08:00
vspader
e2d590c167 Added PlaybackEventController. 2009-03-05 09:04:16 -08:00
vspader
4bd8f6142c Moved growl/scrobbler notifications into PlaybackEventController. 2009-03-05 09:03:30 -08:00
vspader
a48b1242df Formatting changes. 2009-03-05 08:09:29 -08:00
vspader
5d91bda8fe Cleaned up HTTP code a little. 2009-03-05 08:09:02 -08:00
vspader
acf8f8f3be Updated HTTPSource to use JNetLib. 2009-03-05 00:01:36 -08:00
vspader
bbd2c6c7f6 Always accept non-file URLs into the playlist. 2009-03-04 22:56:52 -08:00
vspader
5d42fbe4ce Removed user prefs for xcode project. 2009-03-04 22:56:34 -08:00
vspader
5080a71c4e Fixed up Pls reading so it doesn't try including any old entry with an =. 2009-03-04 22:55:51 -08:00
vspader
545e658192 Modified HTTPSource plugin so it uses JNetLib. 2009-03-04 22:29:47 -08:00
vspader
dd409e19d2 Added JNetLib framework. 2009-03-04 22:29:21 -08:00
vspader
ba32cf22fb Fixed endianness for WavPack plugin. 2009-03-03 08:19:46 -08:00
vspader
5d0372d368 Fix nil key or value in AO metadata. 2009-03-01 17:13:54 -08:00
vspader
31a55fa219 Get AO working on PPC. 2009-03-01 17:07:57 -08:00
vspader
d643b4f559 Fixed install path for AO framework. 2009-03-01 16:42:28 -08:00
vspader
717c3861b8 Modified AO decoder so it always asks for sampleRate/60. This is a limitation of the psf decoders. 2009-03-01 16:29:43 -08:00
vspader
7cc09327e2 Added some debugging aids to AO. 2009-03-01 13:31:29 -08:00
vspader
b655ea2da1 Fixed errant leak fix. 2009-03-01 12:22:55 -08:00
vspader
605b261646 Fix leaks involving QSF files. 2009-03-01 11:33:58 -08:00
vspader
7e79da16be Added more mini format file types. 2009-03-01 11:27:54 -08:00
vspader
1dd18cf856 Fish for memory leaks in sega saturn SSF files. 2009-03-01 11:15:19 -08:00
vspader
40c723df79 Fixed issues with dreamcast dsf playback. 2009-03-01 11:00:46 -08:00
vspader
a49cd40952 Fixed memory leaks. 2009-02-28 23:13:35 -08:00
vspader
4dacefe989 Fix leak of dock image. 2009-02-28 22:28:37 -08:00
vspader
1805393e20 Added more file extensions for AO decoder. 2009-02-28 22:05:38 -08:00
vspader
c86364cbf3 Added AudioOverload plugin. 2009-02-28 22:04:03 -08:00
vspader
82d9ce01bd Fixed file source plugin so URL still exists after closing. 2009-02-28 22:03:51 -08:00
vspader
6525d593f2 Fixed indentation. 2009-02-28 22:03:27 -08:00
vspader
87c0109773 Corrected logic for resetting streams. 2009-02-28 22:02:26 -08:00
vspader
d7ddda160e Modified plugin logic so one class can be multiple plugin types. 2009-02-28 20:12:47 -08:00
vspader
b5b5b45eda Fixed thread leak when next streams are reset. 2009-02-28 19:14:52 -08:00
vspader
38743b7dbf Added badges to the icon to indicate the current playback status. 2009-02-28 15:54:36 -08:00
vspader
047e1e2f9c Removed unused images. 2009-02-28 15:44:48 -08:00
vspader
a926624a2d Fixed nib so time remaining is not 0.. 2009-02-28 15:13:11 -08:00
vspader
af6c5f343a Cleaned up logic a little. 2009-02-28 14:40:30 -08:00
vspader
03937f480b Cleaned up modified add behavior. 2009-02-28 14:22:33 -08:00
vspader
1fcf3bb2ff Fixed up fading logic. 2009-02-28 13:19:26 -08:00
vspader
fd4fa4c62d Fixed playback buttons on mini mode. Play now turns to pause. 2009-02-28 13:13:06 -08:00
vspader
606cdef1d0 Fixed last commit. 2009-02-28 12:53:24 -08:00
vspader
3cd7402d3d Re-request the next stream when the shuffle/repeat mode changes. 2009-02-28 12:26:43 -08:00
vspader
384911beb6 Playback continues as expected when you moved a song that was at the end of the playlist. 2009-02-28 11:11:22 -08:00
vspader
85630c836a Fixed bug when you changed the playlist without having a next song queued up. 2009-02-28 11:01:49 -08:00
vspader
fda5d50712 If you change the playlist near the end of a song, it should now play the correct song. 2009-02-28 10:57:21 -08:00
vspader
c96c3448d8 Volume is now saved across launches. 2009-02-28 10:19:15 -08:00
vspader
489063ad33 Register defaults for shuffle/repeat. 2009-02-28 10:18:56 -08:00
vspader
bafb6485f4 Tooltip for volume slider now includes a %. 2009-02-28 10:18:32 -08:00
vspader
df2fa22a93 Shuffle/Repeat are now remembered. 2009-02-28 10:06:21 -08:00
vspader
2883e93725 Removed unused method. 2009-02-28 09:52:40 -08:00
vspader
9ad32e82ad Moved commonly used file to a new location. 2009-02-28 09:45:08 -08:00
vspader
3b9d20fdc5 Fixed sorting for non-0 padded files. 2009-02-28 09:41:37 -08:00
vspader
983699ab2f Fixed shuffle/repeat in mini mode. 2009-02-27 22:45:37 -08:00
vspader
c902c96a19 Fixed shuffle images. 2009-02-27 22:40:50 -08:00
vspader
b78bae6e99 Small gapless fixes. 2009-02-27 21:25:54 -08:00
vspader
672c05ec14 Further tweaks to mp3 gapless logic. 2009-02-26 22:46:05 -08:00
vspader
94259fd366 Fix up gapless logic a little. 2009-02-26 22:12:05 -08:00
vspader
876efcde38 Rearranged comparison to prevent underflow. 2009-02-26 21:31:20 -08:00
vspader
d8df7afcbb Hooked back up the playback buttons in mini mode. 2009-02-22 16:21:02 -08:00
vspader
9a30701f80 Removed unused files. 2009-02-22 14:59:03 -08:00
vspader
a2f360177e Organized things a little better. 2009-02-22 14:57:02 -08:00
vspader
271f314376 Fixed up mouse wheel in mini mode. 2009-02-22 14:47:28 -08:00
vspader
8bd1cc32d5 Fixed position slider max. 2009-02-22 14:40:22 -08:00
vspader
faf0df17f2 Removed unused methods from playbackcontroller. 2009-02-22 14:29:11 -08:00
vspader
a1f6139ea4 Fixed up position slider and time display. 2009-02-22 14:28:09 -08:00
vspader
c522a69499 Fixed title in mini window when nothing is playing. 2009-02-22 11:57:51 -08:00
vspader
fcf886321f Mini window will now reopen on launch if it. 2009-02-22 11:56:28 -08:00
vspader
8bdb68ae19 Tweaked mini window. 2009-02-22 11:40:07 -08:00
vspader
ce2f61564c Removed old classes. 2009-02-22 11:22:51 -08:00
vspader
c107c67ba7 Added dual window classes. 2009-02-22 11:22:35 -08:00
vspader
cff2ef5178 Added dual window support. 2009-02-22 11:21:55 -08:00
vspader
f0dce0e1d6 Finished nightly updater's conversion to mercurial. 2009-02-21 15:27:03 -08:00
vspader
dbe1443f4b Updated nightly script for subversion => mercurial conversion. 2009-02-21 15:15:13 -08:00
vspader
56daa2dff8 Returned m4a support to taglib. 2009-02-21 14:20:13 -08:00
vspader
51bfdd59ed Fix up taglib. 2009-02-21 07:21:21 +00:00
vspader
66910de2d2 Updated project file for Taglib-1.5 2009-02-21 06:19:01 +00:00
vspader
c391097b00 Taglib 1.5 2009-02-21 06:16:30 +00:00
vspader
70b19e6cfa Removed taglib. Prepare for upgrade! 2009-02-21 06:04:16 +00:00
vspader
511b18cdd6 Mouse wheel now works when the volume slider is being displayed. 2009-02-09 16:09:29 +00:00
vspader
1817e58d2d Removed excessive logging. 2009-02-09 06:18:46 +00:00
vspader
f24afa4c86 Fixed up timers so they are still in effect while in the tracking runloop mode. 2009-02-09 06:16:16 +00:00
vspader
f9c9bfad18 Mouse wheel over the volume button now works. 2009-02-09 06:04:27 +00:00
vspader
c9e542f570 Added better tooltip feedback. 2009-02-09 05:53:38 +00:00
vspader
081ca505dc Removed debug log. 2009-01-19 17:16:24 +00:00
vspader
c6dbeb64ca Rearrange order of evaluation so URL is not dereferenced for file URLs unless there is no metadata. 2009-01-18 08:00:39 +00:00
vspader
750e5cbf01 Rename the playlist tableview to eliminate any missing-column problems when updating. 2009-01-17 18:30:44 +00:00
lmsilva
6c4f9c7745 2008-12-15 10:34:45 +00:00
lmsilva
25b52f1ec2 2008-12-15 10:27:28 +00:00
lmsilva
ec992377f4 2008-12-15 10:06:07 +00:00
lmsilva
0df5123d05 fixed a bug introduced before, double clicking on a song in the tableview wouldnt work 2008-11-21 15:43:34 +00:00
lmsilva
dda74d0608 fixed seek slider from becoming active & disabling it when STOP occurs 2008-11-21 15:14:23 +00:00
vurlix
38e6e9af62 fix some bugs reported by the clang static analyzer 2008-08-26 17:45:16 +00:00
vspader
5132465651 Save previous height when hidden. 2008-06-22 19:44:09 +00:00
vspader
ab6f61c591 Updated preference key. 2008-06-22 19:04:15 +00:00
vspader
2e819f4970 Remember mini mode. 2008-06-22 19:02:53 +00:00
vspader
f4184dac20 Forgot to connect split view delegate 2008-06-22 17:56:42 +00:00
vspader
2606a20020 Updated SideView, split into SideBar and SideWindow. 2008-06-21 19:54:01 +00:00
vspader
3daa06ebae Fixed up first responders so it goes back to the playlist view when hiding side view. 2008-06-21 06:04:09 +00:00
vspader
6fb1c77e62 Added first responder to be set for the side view. 2008-06-21 05:42:40 +00:00
vspader
f06ff8d17d Enter now adds files from the file tree. 2008-06-21 05:25:38 +00:00
vspader
030e8d0359 Added side view classes. 2008-06-21 05:09:29 +00:00
vspader
208a541c4c Updated project files. 2008-06-21 05:04:23 +00:00
vspader
f53bfc861d Side pane say what? 2008-06-21 04:05:30 +00:00
vspader
6d820b8864 Updated bindings in preferences. 2008-06-12 22:48:08 +00:00
vspader
53aa279763 Version bump. 2008-06-12 22:41:26 +00:00
vasfed
7fc14f18ea probably this would fix broken in 891 opening files behavior 2008-06-11 21:09:58 +00:00
vspader
713382ebce Updated Growl framework to 1.1.2. 2008-05-31 15:43:45 +00:00
vspader
b790c09c8f Updating growl framework. 2008-05-31 15:42:56 +00:00
vspader
32a5c7257f Slightly improved file-tracking playlist entry. Now will default to the last URL it looked up/received of the file if the path is no longer found, which helps in the case where a network share was disconnected. 2008-05-21 11:27:01 +00:00
vasfed
0b4b5df86f Previous commit fix (add new src files) 2008-05-18 09:40:33 +00:00
vasfed
584710ffb1 Changed playlist behavior preferences to be pop-up buttons with choices 2008-05-18 09:38:53 +00:00
vasfed
f9f0891f6c Fixed a bug in APL plugin with image files containing # in name 2008-05-18 08:04:46 +00:00
vasfed
e063790e93 Updated APL plugin to use new protocol
Added support for behavior modifiers on addition/opening of files
Added Command+Control as modifier for open/enqueue
2008-05-09 21:24:49 +00:00
vspader
23124f7792 Fixed bug when play on add is enabled and the playlist is empty. 2008-05-04 22:29:02 +00:00
vspader
549a0cf2da Fix for MAD sample scaling routine. 2008-05-03 19:37:10 +00:00
vspader
10669a2db3 Added preference for begin playback on add and clear on add. 2008-05-03 16:01:27 +00:00
vspader
345e57698f Cog now begins playback and clears the playlist when adding songs. 2008-05-03 15:15:45 +00:00
vspader
bedc3a2ade Updated tracking slider so it works again. The time is updated while dragging, and seeking is only done when the mouse button is released. 2008-05-01 23:35:39 +00:00
vspader
c78a553532 Bug fix for cue sheet changes. 2008-05-01 23:34:23 +00:00
vspader
03ad906fb4 Fixed shorten and cue sheet decoders so they conform with the updated protocols. 2008-03-30 15:43:28 +00:00
vspader
7314c6cba1 Fixed bug with loading non-multitrack files. 2008-03-24 12:31:55 +00:00
vspader
0a1630db7e Fix for multi-track files and the file move watching. 2008-03-15 04:45:37 +00:00
vspader
ae469a43ec Fix for spotlight crash. 2008-03-13 02:07:49 +00:00
vspader
2a6d847f70 Fixed pls file loading. 2008-03-13 02:00:51 +00:00
vspader
fe3fd5cb21 Added file tracking to file playlist entries using filerefs. 2008-03-13 01:43:33 +00:00
vspader
db65925ff0 Fixed now playing in dock menu. 2008-03-13 01:21:54 +00:00
vspader
9d45f3a05b Hide hidden files in file tree. 2008-03-13 00:55:37 +00:00
vspader
76b730d0d7 Fixed multiple selection enabled/disabled. 2008-03-13 00:50:15 +00:00
vspader
dc891b5c5b Fixed track numbers for game music plugin. 2008-03-13 00:44:41 +00:00
vspader
0da67249fc Fixed up playlist context menu.
Removed album/artist name from menu thanks to Fiona Apple and some clever person who thought it would be funny to shove the entire album name into the tag.
2008-03-11 23:31:19 +00:00
matthewleon
e24ee695a6 Spotlight window properly saves location. 2008-03-11 22:10:18 +00:00
areff
f4ba4f102a Fixed error in Scrobbling resulting in all songs taking 3:55 minutes before scrobble (cause was that PlaylistEntry.length is no longer an int, but an NSNumber). 2008-03-09 16:19:14 +00:00
vspader
dbfa0363de Some cleanup and fixes for the toggle menu. 2008-03-09 02:53:13 +00:00
vspader
208065494c Fix for spotlight playlistentry dealloc and added missing fields to playlistentry dealloc. 2008-03-09 02:05:00 +00:00
matthewleon
c94d31f6d9 Dealloc for PlaylistEntry seems to shrink memory leak. 2008-03-09 00:22:48 +00:00
vspader
637c0d598e Added transformers for menu item title. There must be a better way... 2008-03-08 23:58:52 +00:00
vspader
3375e15a83 Queue is now a toggle. 2008-03-08 23:57:54 +00:00
matthewleon
2124066761 Wrote dealloc for SpotlightPlaylistEntry. Still need to find large leak. 2008-03-08 23:47:29 +00:00
vspader
ed261fb51a Disabled WMA plugin for now because of strange xcode 3.1 error. 2008-03-07 13:44:12 +00:00
vspader
aaf8c833ac Fixed sorting for title column. 2008-03-07 13:30:23 +00:00
vspader
646c71fefb Made xibs and project files binary so they dont show up in diffs.
Removed horizontal scrolling from playlist.
2008-03-07 01:28:56 +00:00
matthewleon
2d00f4b70b Spotlight panel font size bindings completed. 2008-03-05 13:16:06 +00:00
matthewleon
34fc115253 Playlist sorts are case insensitive. 2008-03-05 12:26:30 +00:00
vspader
ac1eeda1a3 Clear predicate on insert to fix bug with dragging while filtering. 2008-03-05 01:36:09 +00:00
vspader
477bdbd4ef Fixed strange whitespace issue. Also, increased bottom border a bit to make it match other status bar heights. 2008-03-05 01:22:42 +00:00
vspader
569a3e79cc Fixed scrolling behaviour. 2008-03-04 01:14:51 +00:00
vspader
f0e6c8bb2b Updated about dialog year and tagline. 2008-03-04 01:05:52 +00:00
vspader
9ded206919 Fixed tab in spotlight panel. 2008-03-04 01:03:13 +00:00
vspader
5346f0dbde Fixed font-size changing. 2008-03-04 01:00:09 +00:00
vspader
79cd625152 Changed year to an NSNumber. Fixed up taglib plugin. Tracks/Years with 0 now show up as nothing. 2008-03-04 00:43:47 +00:00
vspader
16ccf5622d Fixed issues with big big playlists. 2008-03-04 00:35:20 +00:00
matthewleon
69e802052e Spotlight sorts by track number properly. 2008-03-03 23:02:52 +00:00
vspader
9af41d7542 A few taglib fixes. Reads id3v2 before ape for mp3 files. Added AutoReleasePool to backgrounded method. 2008-03-03 03:26:19 +00:00
vspader
cf46d16a56 Remove concurrency! Mwahaha! Also, moved updateTotalTime so it's done after all operations. Now it's actually usable while loading time. 2008-03-03 02:25:52 +00:00
vspader
dd89208ee0 Removed singleton nonsense. 2008-03-03 02:18:27 +00:00
vspader
276176a80c Updated playlistLoader to be CONCURRENT! Mwahahaha!
total time is now automatically updated by observing PlaylistController.arrangedObjects.length
2008-03-03 02:09:56 +00:00
vspader
6a4b661208 Modified taglib plugin to not use the C bindings since they are not thread safe. Used C++ classes instead, which are. 2008-03-03 01:55:25 +00:00
vspader
671d7021ae Added Current Entry Object controller to fix issue with currently playing not being updated when loading. 2008-03-02 20:03:22 +00:00
vspader
58a61a7b21 Removed debugging message. 2008-03-02 19:21:35 +00:00
vspader
76e8bbb2c2 Logitech keyboards work with media keys on 10.5! Added prev/next support. 2008-03-02 19:20:08 +00:00
matthewleon
92be178bf2 Playlist entries are now processed on main thread. 2008-03-02 10:51:37 +00:00
matthewleon
d84a12d596 Hack to fix display of newly added songs (no idea why this is should be necessary, maybe something wrong with KVO). 2008-03-01 19:56:10 +00:00
matthewleon
8dee65b8b6 Small threading memory leak fix. 2008-03-01 18:38:47 +00:00
matthewleon
4168bb43eb Redid threading for reading file info and metadata. Still a bit buggy. 2008-03-01 18:29:14 +00:00
matthewleon
a0cdf1a03e Fixed CogAudio bool bug. 2008-03-01 15:32:28 +00:00
matthewleon
6b35fee9e3 Cleaning CogAudio code. 2008-03-01 15:28:17 +00:00
matthewleon
666d803897 Code cleanup. 2008-03-01 15:04:46 +00:00
areff
e5187b9a48 Some WMA cleanup, more to come. 2008-03-01 14:11:30 +00:00
vspader
d7826ee144 Clear stopAfter status when changing the song. Fixed bug where status wasn't dependant on stopAfter. 2008-03-01 03:35:27 +00:00
vspader
3cdca94207 Split status up into bunches of properties and made it a readonly property. 2008-03-01 03:29:21 +00:00
vspader
6c5ecf3701 Updated PlaylistView so status column header is blank. 2008-03-01 02:48:12 +00:00
matthewleon
23396a9747 More PlaylistEntry cleanup. 2008-02-29 21:56:01 +00:00
matthewleon
9e8173bc74 PlaylistEntry cleanup. 2008-02-29 21:54:09 +00:00
matthewleon
9ce92f2ac1 Playlistentry code cleanup. Also converted track to NSNumber to fix Spotlight hang from forum discussed here: http://www.cogx.org/forums/viewtopic.php?id=332 2008-02-29 20:30:37 +00:00
matthewleon
5346d85099 Fixed compiler warnings by converting PlaylistEntry length property to NSNumber. 2008-02-29 20:09:59 +00:00
areff
e073f48dd5 WMAs now play. Seek is still lacking, also metadata readers. Code needs cleanup. 2008-02-28 19:29:22 +00:00
areff
d59e118e1d Set default seek to 5, added menu separator to context menu, fixed silly wma crasher 2008-02-28 13:11:37 +00:00
areff
04ef1c2fa3 initial code for WMA readAudio:frames method added, severely broken 2008-02-28 12:49:19 +00:00
areff
c5a869d406 Some basic WMA code added, reads file properties correctly, code of function tag_recode in asf.c changed due to crasher (this needs to be investigated) 2008-02-28 05:33:56 +00:00
areff
37d159e009 Initial WMA framework and plugin structure added to project. 2008-02-26 20:53:18 +00:00
areff
0aa5b56250 Fixed a bug in Stop after current that was causing some odd behaviour. 2008-02-26 11:59:47 +00:00
areff
089dfe975b Changed Stop after current shortcut to Option-Cmd-Period 2008-02-26 07:35:56 +00:00
areff
89cd984b7d Moved stopAfterCurrent check to requestNextStream, so it won't interfere other than when the player is reaching the end of a track by natural means. Added menu item validation. 2008-02-25 17:02:06 +00:00
areff
771a6de380 Added Stop after Current, hooked it into Ctrl-Z for now, for lack of anything better (it needs to be easily accessible one way or the other), added image to signify status by adding a little red square to the play icon. 2008-02-25 15:39:04 +00:00
areff
386078fdc5 Reworked contextual menu, added more menu validation items 2008-02-24 18:46:32 +00:00
vspader
588fa5ddc6 Modified total time to also used arrangedObject observing. 2008-02-24 17:32:50 +00:00
vspader
a10898f4c9 Index column is now set by observing arrangedObjects instead of the updateIndexesFromRow method. 2008-02-24 17:16:19 +00:00
vspader
f451cd1712 Fixed playlist moving. 2008-02-24 15:47:04 +00:00
areff
c6640cc3f5 Fix for playlist scrolling even if song is in view. This might break something I haven't thought of. 2008-02-24 14:28:46 +00:00
vspader
2320039745 Added APE tag support to mp3 files. APE is preferred to id3 at the moment. 2008-02-24 14:28:30 +00:00
areff
761f86cf9c Added menu validation for fade entry 2008-02-23 22:55:21 +00:00
areff
d2e95a50f8 Completely redesigned all menus, fixed crashers due to new PlaylistEntry structure, validated menu items, added menu entry for fading, synthesized playbackStatus, updated KnownIssues 2008-02-23 22:20:14 +00:00
areff
86f691b769 Fixed removing queued songs, hooked File Tree icon up to correct method toggleWindow. 2008-02-23 20:08:27 +00:00
vspader
7109dec4ad Some playlistentry cleanup. 2008-02-23 19:46:23 +00:00
vspader
b7beb276f2 Moved SpotlightController registerDefaults to awakeFromNib to hopefully prevent crash. 2008-02-23 14:09:34 +00:00
vspader
c31eae4541 Performance improvements for the status column. 2008-02-23 13:57:33 +00:00
areff
e58c172eeb Fixed small oversight, queuePosition not being reset to -1 when removed from queue by being played. 2008-02-22 15:34:09 +00:00
areff
e3216e0ef1 Added Remove from Queue right click menu item, still lacks validation. Updated KnownIssues. 2008-02-22 15:26:46 +00:00
vspader
85b830f76b Forgot to add these files last night. 2008-02-22 13:27:24 +00:00
vspader
5808b34a16 Fix for mod files with missing? sample data. Fixes #71. 2008-02-22 04:45:21 +00:00
vspader
3ab720427e Made stop update synchronous since there were issues when moving on to the next song. 2008-02-22 03:46:04 +00:00
vspader
304ddffbd1 Added error messages for entries whose properties cannot be read. Fixed length in such cases to not show up. 2008-02-22 03:44:06 +00:00
vspader
c6dc1fd141 Fixed #70. 2008-02-22 03:09:03 +00:00
vspader
d1adc3d53e Fixed queue status when clearing queue. 2008-02-22 02:21:08 +00:00
vspader
fe331624f5 Added status column with playing and queued status support. 2008-02-22 02:19:46 +00:00
areff
184525a47a Implemented Repeat All through NSPredicate and filtering, method should be applicable when Shuffle is fixed too. 2008-02-21 19:14:20 +00:00
areff
390c98b18c Fixed oversight in FileTreePanel.xib 2008-02-21 11:31:04 +00:00
areff
7d83fab7e8 Updated KnownIssues 2008-02-21 11:01:26 +00:00
areff
a624737861 Both File Drawer and Spotlight Panel will now show and hide when their shortcuts are pressed. 2008-02-21 10:45:09 +00:00
areff
52f8c6f31f Fixed adding files in File Tree. Now adds when you press enter, and supports multiple selections. 2008-02-21 09:05:06 +00:00
areff
8bff745c38 Implemented Add to Queue as choice in Right click menu, added Clear Queue to Playlist menu. 2008-02-21 07:30:28 +00:00
areff
ea57907678 Fixed double click in File Tree. Updated KnownIssues to reflect problem with double click automatically adding directories. 2008-02-20 23:22:39 +00:00
areff
a9aa9be81a Added double click support in the File Tree. Ticket #37. 2008-02-20 19:36:34 +00:00
areff
91e5833a40 Partially fixed Total duration: field, is missing duration for currently playing song. 2008-02-20 15:31:00 +00:00
vspader
138c575dda Clarified comparison. 2008-02-20 13:25:24 +00:00
vspader
4c8630e808 Cleaned up/fixed previous/next album. 2008-02-20 13:20:07 +00:00
areff
dea4553bfc Fixed ticket #59, bind Show in Finder to Cmd-R. 2008-02-20 09:40:32 +00:00
vspader
a54f6ecfe5 Fixed bitrate calculation. 2008-02-20 01:09:15 +00:00
vspader
86a63b1efc Updated KnownIssues and TODO. 2008-02-20 01:03:03 +00:00
vspader
7462169ba3 Fixed some things. Made pathnode url KVC compliant. 2008-02-20 01:01:15 +00:00
vspader
b15e4f626a Moved most enumerators to fast enumeration. 2008-02-20 00:54:45 +00:00
vspader
00ef56a0ed A little more cleanup. 2008-02-20 00:45:23 +00:00
vspader
eeba50f6e1 Cleaned up PlaylistEntry. 2008-02-20 00:44:40 +00:00
vspader
38e23ef442 Some more cleaning up. 2008-02-20 00:12:25 +00:00
vspader
76594c1062 Cleaned up repeat one/all code. 2008-02-19 23:49:51 +00:00
areff
402b403794 Fixed small bug in Repeat All and pressing next at last playlist entry. Enabled Shuffle button. 2008-02-19 20:16:56 +00:00
areff
f20b10fdd4 Most of the Repeat logic is in place (needs some brush up here and there). Still missing Repeat Album. Disabled some annoying debug output from MADDecoder. Updated KnownIssues. 2008-02-19 19:59:35 +00:00
areff
9a43ad56f8 Added Repeat One logic to playbackController's requestNextStream. This is the only point on playback where repeat one should do anything at all, IMO. Repeat All logic added at same place, but this is only a temporary solution, as it does not heed shuffle in any way and generally feels less than optimal. Updated KnownIssues to reflect these changes. 2008-02-19 07:49:06 +00:00
vspader
1e7bfb19c4 Updated KnownIssues. 2008-02-19 04:10:35 +00:00
vspader
ae4c112076 Fixed up repeat menu and added back repeat album. 2008-02-19 04:02:05 +00:00
vspader
8434f6e3b3 Added RepeatTransformers with the beginnings of support for the repeat modes. MenuItems's reflect the repeat state (yet do not work to set the state yet), and the repeat button toggles w/images as expected.. 2008-02-19 03:39:43 +00:00
matthewleon
94f23c4fdb Spotlight: Search scopes work and crash solved. We now return to regular programming. 2008-02-18 20:46:53 +00:00
matthewleon
b6a46c5ca1 Search scopes no longer work but the program won't crash :) 2008-02-18 20:40:02 +00:00
matthewleon
67816346e0 Spotlight: Elegant solution to storing search scopes. 2008-02-18 20:09:02 +00:00
areff
08a4bbe08e Fixed my own sillyness in scroller code - needs fixing. 2008-02-18 19:37:32 +00:00
areff
ad5ac13a9c Bound Scroll to currently playing to Command-L (iTunes). Changed the code slightly so that the currently playing song is also automatically selected when you scroll to it. Ten playlist entries will also be visible above it, to create some space. 2008-02-18 19:21:50 +00:00
areff
f845a519b1 Added repeat sub menu in Playlist menu, all items need more work. 2008-02-18 18:31:26 +00:00
matthewleon
aa3b716e09 Fixed Spotlight import. 2008-02-18 16:55:31 +00:00
areff
d23b6b4ee5 Considerable cleanup of Path column, added Filename column, both hidden by default, path now abbreviates home directory to ~ for cleaner look. 2008-02-18 16:06:54 +00:00
areff
90a32bd646 Changed seeking to Shift-Left/Right. Skip album uses Option, skip track uses Command. 2008-02-18 14:24:21 +00:00
matthewleon
b68a2c3a69 Overhauled Spotlight metadata importing to make it more easily expandable and reuse NSValueTransformer code. 2008-02-18 12:59:20 +00:00
areff
567711e85e Fixed Trac bug 65: Doesn't show correct position after 203:50 mins - caused by an unsigned long overflow. 2008-02-18 11:37:33 +00:00
matthewleon
678f6e2dbb Eliminated SpotlightPlaylistView, which is redundant for the time being. 2008-02-18 10:28:24 +00:00
areff
6873a2730b Fixed broken window title display when no artist tag is found 2008-02-18 10:25:04 +00:00
matthewleon
a02859a3fc Moved rowHeight binding of PlaylistView from IB into code. 2008-02-18 10:21:34 +00:00
matthewleon
ea427c9033 Moved FontSizetoLineHeightTransformer registration code to AppControler's +initialize. 2008-02-18 09:27:27 +00:00
vspader
e65deb9d82 Updated KnownIssues. 2008-02-18 03:31:29 +00:00
vspader
8bf061bb14 A little bit of cleanup. 2008-02-18 03:31:09 +00:00
vspader
9414c97c09 File tree panel now uses FSEvent API instead of kqueues. 2008-02-18 03:27:59 +00:00
vspader
e2399c12ca Updated KnownIssues. 2008-02-18 01:59:50 +00:00
vspader
6dfef23ec7 Moved file tree preference to the file tree panel itself.
Removed file tree preference pane.
2008-02-18 01:46:34 +00:00
matthewleon
7f52608e6c Font size implemented through bindings. 2008-02-18 00:11:38 +00:00
vspader
6663d149b7 Updated TODO 2008-02-17 21:22:40 +00:00
vspader
23719ada8e Updated KnownIssues. 2008-02-17 21:22:04 +00:00
vspader
c2a2f531a8 Moved StringToURLTransformer initialize code. 2008-02-17 21:18:01 +00:00
vspader
3ba929f51a Moved File Tree preferences to use a NSPathControl. 2008-02-17 21:04:36 +00:00
vspader
eb84d83c8e Fixed error caused by moving StringToURLTransformer. 2008-02-17 20:53:49 +00:00
vspader
7bb24f5179 Moved StringToURLTransformer to its own file. 2008-02-17 20:46:55 +00:00
areff
facdea9b7e Updated Total duration field at the bottom of main Cog window, now shows hours and minutes after minutes and seconds 2008-02-17 20:16:06 +00:00
vspader
b0432fc736 Changed borders for file tree panel. 2008-02-17 20:15:34 +00:00
vspader
5434fe510b Fixed mp3 bitrate calculation. 2008-02-17 19:59:01 +00:00
vspader
1503c2868f Fixed File Tree preferences. 2008-02-17 19:27:29 +00:00
matthewleon
fabb91d691 Spotlight Panel adopts utility style similar to file tree panel. 2008-02-17 19:16:38 +00:00
vspader
83d84a38d8 Moved File Drawer to File Tree Window. 2008-02-17 18:59:54 +00:00
areff
1b83061c49 Moved volume controls into AudioPlayer, logarithmic helper functions now have their own file, fixed broken seekbar resize 2008-02-17 18:44:11 +00:00
areff
9d8be7851a Added feature request File path column. Hidden by default. 2008-02-17 13:18:19 +00:00
matthewleon
ba0610b973 Context menu works in spotlight window. 2008-02-17 11:06:01 +00:00
matthewleon
438467000a Probably final, probably ideal fix to Spotlight flicker! 2008-02-17 09:56:44 +00:00
matthewleon
ba0746b503 New fix to Spotlight flicker issue. Still not ideal. 2008-02-16 22:59:27 +00:00
matthewleon
ab520a8cb8 Fixed Spotlight update code. 2008-02-16 20:59:04 +00:00
matthewleon
e0a937b3e5 Cleaned up Spotlight update code. 2008-02-16 20:40:47 +00:00
matthewleon
b5c46a0b3a Spotlight panel no longer uses utility style (it doesn't float). 2008-02-16 20:08:45 +00:00
matthewleon
332a062d93 Album and artist search is now exposed no matter where you click. 2008-02-16 19:40:34 +00:00
matthewleon
3c8b325a00 Search by artist and album works from context menu. 2008-02-16 16:38:44 +00:00
areff
6a915b458b Implemented fading up from pause, same key (shift-command-p) as fade down from play. Will clean code and move all audio components into the audioPlayer tomorrow, to fix the event* function names and consolidate all audio related methods. 2008-02-16 16:30:18 +00:00
matthewleon
abf2da423d Implemented UI elements necessary for right-click search by artist/album. 2008-02-16 16:13:21 +00:00
areff
5228709d0f Fixed fadeout code so it sounds a bit better (timer fires faster, steady drop in volume rather than incremental) 2008-02-16 15:28:39 +00:00
matthewleon
a5986373bd Spotlight: Right click menu includes Show entry in Finder. 2008-02-16 14:48:54 +00:00
vspader
53cff01123 Attempted fix of double-click drag allowing selection without playing. It causes a few issues. Mainly you need to have only one row selected for double-click play to work. We'll see how it works. 2008-02-16 14:09:19 +00:00
matthewleon
27cfc3d3c3 Spotlight's default search behavior only searches artist, album and title tags (boosts speed). Changed key combo to command-shift-f. 2008-02-16 14:04:59 +00:00
matthewleon
6b11d41fbe Fixed ridiculous Spotlight bug where absent track numbers would cause a crash. Cleaned directory structure. 2008-02-16 13:18:14 +00:00
matthewleon
d4ee1ac6ae Spotlight sorts properly (phew). Artist, album, track number... Should make several interface improvements easier to implement. 2008-02-16 13:05:30 +00:00
vspader
03b0abb92f Fixed memory leak in previous commit caused by anal retentive retention. 2008-02-16 02:52:49 +00:00
vspader
232fff4598 Add utils for new shuffle. 2008-02-16 02:46:37 +00:00
vspader
a4eb42eab0 Fixed crash, and in doing so introduced a huge memory leak!
Added patch from Eric Hanneken that improves shuffle.
2008-02-16 02:46:19 +00:00
vspader
35d4df9ca2 Added fix that brings back table columns for those that lost them in previous versions. 2008-02-16 01:44:01 +00:00
matthewleon
ad976c9edf Moved Spotlight Window nib loading code. 2008-02-15 22:47:27 +00:00
areff
0126a58679 Font increase/decrease now affect File Drawer too. This is experimental behaviour. 2008-02-15 22:43:34 +00:00
matthewleon
77fd3cbe95 Spotlight interface tweaks. 2008-02-15 22:41:35 +00:00
matthewleon
f1474e6ff0 Spotlight moved to Control menu. Window now saves position, size. 2008-02-15 22:26:55 +00:00
areff
b317d0ba01 Experimental font size increase and decrease added to Cmd-+ and Cmd--, fixed small bug in skipping to previous album, updated KnownIssues 2008-02-15 15:27:34 +00:00
matthewleon
085130dd34 Spotlight interface tweaks - can now import using only keyboard. 2008-02-15 14:23:24 +00:00
matthewleon
387015db22 Eliminated annoying flicker in Spotlight interface. Made tiny tweaks to PlaybackController and PlaylistController header to eliminate compiler warnings. 2008-02-14 23:09:51 +00:00
matthewleon
b4804ebb5e Added initDefaults to AppController.h to get rid of annoying compiler warning. 2008-02-14 21:09:07 +00:00
areff
02836236db Added skipping to next and previous album with Alt-Right and Alt-Left 2008-02-14 19:25:01 +00:00
matthewleon
70ae3cec1c Spotlight can do exact searches using quotation marks, IE %a"tom waits" will do a case insensitive search for all music by Tom Waits 2008-02-14 17:48:32 +00:00
matthewleon
d6e7efd2c1 Cleaned up the Spotlight code considerably and added the ability to do simple searches for artist, album and title using %a, %l and %t respectively. For example searching "%awaits" will return all tracks by Tom Waits, etc... 2008-02-14 14:07:10 +00:00
matthewleon
d795c59c10 Consolidated Spotlight code. 2008-02-13 23:51:36 +00:00
matthewleon
c25dfa6535 Changing Spotlight search path works properly. 2008-02-13 23:21:34 +00:00
matthewleon
c04f9565d6 Spotlight interface tweaks. 2008-02-13 20:47:00 +00:00
matthewleon
62c446160c Spotlight uses NSScanner to parse search strings, eliminating most crashes resulting from unusual search strings. 2008-02-13 18:47:24 +00:00
areff
f64ebf597f Added incremental seeking with remote, volumeUp/Down now take an amount argument, seekForward/Backward now take an amount argument, fixed incremental fadeout that will not register more than one timer, added status kCogStatusFading 2008-02-13 18:03:06 +00:00
matthewleon
3c712e2e45 Changed CogUrlsPbboardType to CogUrlsPboardType throughout project 2008-02-13 17:14:19 +00:00
matthewleon
037874d654 Spotlight is now drag-and-drop compatible. Moved spotlight files where they belong. 2008-02-13 16:10:59 +00:00
vspader
010f7de448 Added [audioPlayer volume].
Tweaked the volume control a little.
2008-02-13 01:50:39 +00:00
areff
26d2b28484 updated KnownIssues 2008-02-12 22:28:11 +00:00
areff
a39ce34ee9 Added fade to pause, key shift-cmd-p, changed volume controls around a bit, still needs fixing 2008-02-12 22:12:27 +00:00
matthewleon
4f9ac97dfc Spotlight can now search form multiple terms properly. Songs can be imported into the playlist again. 2008-02-12 16:24:09 +00:00
matthewleon
7c2d290871 Fixed major spotlight bug by retaining static key array (duh). Spotlight doesn't crash anymore and works very quickly. 2008-02-12 11:11:26 +00:00
matthewleon
a5c8447b8d Fixed mpcdec framework settings to get it to compile in debug configuration on case-sensitive FS. (Modified case from MPCDec to mpcdec, as I already did for release configuration). 2008-02-12 10:30:32 +00:00
matthewleon
ca76dbab7d Added necessary transformers for Spotlight path. 2008-02-11 18:51:51 +00:00
matthewleon
ff32a0a910 Spotlight search path is now properly saved to defaults. 2008-02-11 18:51:04 +00:00
matthewleon
0e6a9ee966 Spotlight gets all necessary tags from metadata now. Some interface tweaks. 2008-02-11 16:39:19 +00:00
matthewleon
d8ac96afbf Spotlight importing fixed. 2008-02-11 14:42:13 +00:00
matthewleon
a624165bc9 Spotlight now works with its own SpotlightPlaylistEntry class, drastically increasing performance and permitting it to gracefully handle corrupt metadata. 2008-02-11 14:10:25 +00:00
matthewleon
4be43e5256 Spotlight search can now be limited to a path. Still quite buggy. 2008-02-11 10:29:21 +00:00
matthewleon
ff8cd0d773 Spotlight tweaks. 2008-02-11 09:20:52 +00:00
matthewleon
e1762b2495 Put spotlight back in AppController. Should work now. 2008-02-11 07:56:26 +00:00
matthewleon
366ba22c55 Spotlight directory structure cleaned. 2008-02-11 07:46:41 +00:00
matthewleon
e04c67b4ad Spotlight added back in. 2008-02-11 07:45:34 +00:00
vspader
cbfc93bd62 Removed Spotlight stuff for now to get Cog to compile agian (Sorry matthew).
Moved nib files to .xib files.
2008-02-11 00:52:07 +00:00
vspader
803a3306a5 Forgot to add these files for undo support. 2008-02-10 22:55:16 +00:00
vspader
37820a586d Fixed up undo/redo support. Should be working great now. 2008-02-10 22:46:12 +00:00
vspader
03cdbd508d Changed PlaylistController to not clear predicate on insert. 2008-02-10 21:05:38 +00:00
matthewleon
3f9c83c581 Spotlight actually works this time... 2008-02-10 20:45:57 +00:00
matthewleon
28d85a0f42 Spotlight search now works. It's a pretty buggy hack at the moment. 2008-02-10 20:34:29 +00:00
vspader
d654c37fe3 Fixed validation for undo/redo menu items. Added sort descriptors and predicates to undo chain. 2008-02-10 20:32:46 +00:00
vspader
a24149dc10 Fixed undo for clear. 2008-02-10 19:46:45 +00:00
vspader
e2b40fe1a3 Added move operation to DNDArrayController. Streamlined undo. 2008-02-10 19:35:58 +00:00
areff
aaad9aa2dc Updated spelling of Seek forward/backward to Forward/Backward 2008-02-10 18:37:12 +00:00
areff
64f0a25a52 Added seeking menu entries, validation of Control menu entries, updated KnownIssues 2008-02-10 18:34:23 +00:00
vspader
299285f0cd Changed undo/redo menuitems back to firstResponder. Modified PlaylistView to validate undo/redo items. 2008-02-10 17:13:30 +00:00
vspader
ecf7f30fb4 Updated Musepack plugin to use new decoder protocol. 2008-02-10 16:18:23 +00:00
areff
9b05ce02d2 Added undo functionality in playlist, undo works for removals, moves and adds. 2008-02-10 16:16:45 +00:00
vspader
4bd896afb3 Updated GME to use new decoder protocol. 2008-02-10 16:04:28 +00:00
vspader
a6c7666143 Updated dumb plugin to use new decoder protocol. 2008-02-10 15:56:18 +00:00
vspader
445797157c Fixed bug in Dumb plugin when title is not found. 2008-02-10 15:40:01 +00:00
vspader
9fc6e4eeb1 Converted spaces to tabs. 2008-02-10 15:35:19 +00:00
matthewleon
b23b18406a Added Spotlight window (File->Open with Spotlight). It doesn't work at all yet, but it shows what the basic idea is. 2008-02-10 13:48:55 +00:00
vspader
3fd9ba5a40 SVN Hook with mailing list test. 2008-02-08 18:52:11 +00:00
vspader
0ea3d1cd23 Testing subversion hook. 2008-02-08 18:46:54 +00:00
vspader
3561a93410 Updated TODO. 2008-02-08 18:44:27 +00:00
vspader
3244e20608 Added patch for compilation case-sensitive filesystems from Matthew Grinshpun. 2008-02-08 00:08:56 +00:00
vspader
be9387d30d Added patch from Andre Reffhaug for ctrl+left/right seeking. 2008-02-07 23:57:21 +00:00
vspader
aced029a97 Updated project files to remove unworking localizations. 2008-01-31 01:08:30 +00:00
vspader
8b63c09179 Removed outdated localizations. 2008-01-31 01:02:38 +00:00
vspader
efe0bd06ad Fix for making rootPath KVC compliant for the file tree. 2008-01-31 00:50:50 +00:00
vspader
840ee839d0 Updated to IB3. Added Seperator to toolbar items. 2008-01-24 23:25:01 +00:00
vspader
7a578138a1 Removed MainMenu.nib 2008-01-24 23:19:09 +00:00
vspader
9bf75801b4 Fixed bug in seperator double-click when using formatters. 2008-01-24 02:33:55 +00:00
vspader
bb7de6897e Additional UI nicities.
Fixed bug in sparkle minimum version check.
2008-01-24 02:17:57 +00:00
vspader
2b1c305841 Added new hotness for the status bar. 2008-01-24 01:55:24 +00:00
vspader
56c8b9202f Fixed some table columns bugs. 2008-01-24 01:44:24 +00:00
vspader
c02e22601a Fixes for update feed. 2008-01-23 16:22:41 +00:00
vspader
1f7c192e87 Feed update script now specifies the minimum system version as 10.5 2008-01-23 04:03:35 +00:00
vspader
451536ff4b Updated ruby path. 2008-01-23 03:55:51 +00:00
vspader
ef259a374f Fixed bug in inverted toolbar behaviour so it restores the content view to the correct width. 2008-01-23 03:55:20 +00:00
vspader
d230f30a09 Fixed up toolbar and UI. 2008-01-23 03:03:46 +00:00
vspader
a9d103261f Fixed bug in flac decoder. 2008-01-23 02:45:57 +00:00
vspader
0a6a282f20 Added apple remote fix for leopard.
Updated icons for m3u and pls formats.
2007-12-08 22:53:54 +00:00
vspader
5715522470 Moved to frame-based reading/seeking instead of byte/second based. Some formats have still not been updated and are broken.
Added icons for other formats.
2007-11-24 20:16:27 +00:00
vspader
ff6d33691b Updated source to use new os version checking sparkle. 2007-11-04 03:51:51 +00:00
vspader
ccf45218fb Adding sparkle with minimum version checking. 2007-11-04 03:44:15 +00:00
vspader
678d406879 Bug fix for flac files. 2007-11-04 03:08:41 +00:00
vspader
60405d6431 Added missing images. 2007-11-02 11:56:28 +00:00
vspader
4a323168c6 Added some missing third party files. 2007-11-02 02:30:29 +00:00
vspader
f6c9658189 Removed debugging message. 2007-11-01 02:50:39 +00:00
vspader
4310532c50 Fixed bugs in miniplayer 2007-11-01 02:15:14 +00:00
vspader
aa856de92b Added toolbar UI. 2007-11-01 01:53:52 +00:00
vspader
de85236760 Fix for MAC so Cog builds on Leopard 2007-10-27 09:08:08 +00:00
vspader
11fd5b5454 Added "smarter" removal of playlist entries. 2007-10-22 00:04:34 +00:00
vspader
0eb32ff9f6 Fixed problem with track changes. 2007-10-21 21:01:40 +00:00
vspader
9fed5759ae Fixed typo. 2007-10-20 19:15:09 +00:00
vspader
8a5db0dd33 Removed alternate file extension code so Cog does not encourage broken cuesheets. 2007-10-20 19:14:12 +00:00
vspader
d376d2e3ca Removed user files. 2007-10-20 19:13:09 +00:00
vspader
6c22c97103 Removed commented code. Fixed bug which may cause tracks to not end. 2007-10-20 16:18:44 +00:00
vspader
d6c6dea8a6 Fixed Cuesheet bug so it doesn't load itself.
Added APL support (Vasfed).
2007-10-20 16:15:02 +00:00
vspader
7bee3acc79 Cleaned up code. 2007-10-20 16:01:18 +00:00
vspader
156ae4ef0d Fixed warning. 2007-10-20 15:54:42 +00:00
vspader
9a344922da Fixed the way plugin controller was setup and loaded.
Updated cuesheet to search for alternate types if wav is not there.
2007-10-20 15:53:52 +00:00
vspader
cc806285e0 Updated plugin architecture. No more plugin classes! Now loads classes based on protocol alone. 2007-10-20 15:46:39 +00:00
vspader
5ff84158cc Made playlist/cuesheet encoding a little more robust (Vasfed). 2007-10-20 15:08:06 +00:00
vspader
2e44b9833e Fixed some synchronization problems. 2007-10-20 03:24:27 +00:00
vspader
e78a961fa3 Fixed playlist loading bugs. 2007-10-20 03:22:13 +00:00
vspader
8d74a3ccef Fixed file types for multi-track game music files. 2007-10-20 03:17:43 +00:00
vspader
1889973c74 Fixed cuesheet decoding bug where tracks weren't changing if not played through completely. 2007-10-19 22:51:01 +00:00
vspader
16f0c942bc Bug fixes for playlist file loading. 2007-10-19 03:06:52 +00:00
vspader
d82fdcbf62 Bug fixes from 0.07 branch. 2007-10-19 02:23:10 +00:00
vspader
e54c72aae0 Forgot file drawer files. 2007-10-18 02:52:03 +00:00
vspader
97ff03f184 Preliminary gapless playback. 2007-10-18 02:33:12 +00:00
vspader
0e2dcf5014 Added m4a to taglib types. 2007-10-16 22:45:09 +00:00
vspader
8454204f44 Added taglib from songbird repository for m4a support. 2007-10-16 22:31:23 +00:00
vspader
da9e4e28fd Fixed extension check. 2007-10-16 01:27:15 +00:00
vspader
7582bbef02 Updated file drawer so it expands containers. 2007-10-16 01:22:57 +00:00
vspader
4cb4f5e32c Added alias support to file drawer. 2007-10-15 23:37:49 +00:00
vspader
3ef46a0c82 Fixed up smart folders. 2007-10-15 23:18:58 +00:00
vspader
47582ae4f4 Fixed playlist saving/loading bug. 2007-10-15 22:57:30 +00:00
vspader
bc212f3e96 Fixed bugs dealing with multi-track files and playlist saving/loading.
Fixed problem where cue sheets would play static.
2007-10-15 22:19:14 +00:00
vspader
4b814bdbf0 Added back update notifications back to the file drawer.
Removed no-longer-used files.
Removed debugging messages.
2007-10-15 03:29:30 +00:00
vspader
27d9ff122a Started cleanup of file drawer. Still needs to handle updating. 2007-10-14 23:24:54 +00:00
vspader
40b5de5279 Added feed arugment to build_nightly.
Moved build_nightly to update_feed.
2007-10-14 20:58:46 +00:00
vspader
7494f04511 Added fix where containers were not checked for uniqueness. 2007-10-14 20:36:10 +00:00
vspader
5084b555cb Removed nonexistent framework search paths. 2007-10-14 19:18:20 +00:00
vspader
535e0e802f Updated mime-types. 2007-10-14 18:56:23 +00:00
vspader
3ee193e975 Updated mime types. 2007-10-14 18:39:58 +00:00
vspader
f1b9141f4b Added mime type support. 2007-10-14 18:12:15 +00:00
vspader
c536ea06a5 Removed useless PropertiesReader classes.
PluginController now uses the decoder if a properties reader class is not found.
PropertiesReaders should still be created if performance can be improved if code is only reading properties.
2007-10-14 17:31:20 +00:00
vspader
7d53e8586a Fixed thread exit problem. 2007-10-14 16:57:32 +00:00
vspader
0e6f0a8576 Fixed up thread handling. 2007-10-14 16:37:06 +00:00
vspader
0091ccb447 HTTPSource now uses NSURLConnection. 2007-10-14 16:29:49 +00:00
vspader
eedc659f84 Fixed CueSheet Year/Genre reading. 2007-10-13 16:31:18 +00:00
vspader
ca2649d930 Cue sheet genre can now be quoted.
Cue sheet track now removes the trailing 0
Changed order of reading so tracks can appear before their associated file.
2007-10-13 16:21:46 +00:00
vspader
fca5ddc8d0 Fixed bug that was causing play/pause button not to work with a lot of short tracks. 2007-10-13 08:50:40 +00:00
vspader
acd71fd43b Fixed play/pause menu item. 2007-10-13 08:48:10 +00:00
vspader
be73aa8dd1 Added Simplified-Chinese localization, courtesy of BBBear2002. 2007-10-13 08:43:37 +00:00
vspader
c76c95529a Fixed end of playlist crash. 2007-10-13 08:25:44 +00:00
vspader
fc9069d7c7 Fixed unguarded critical sections. 2007-10-13 08:14:05 +00:00
vspader
d5919bc93e Further cleanup and memory leak fixes. 2007-10-13 07:51:42 +00:00
vspader
97a278a143 Cleaned up memory leaks. 2007-10-13 07:09:46 +00:00
vspader
6f6b01b15c Fixed bug where playlist saved as kss files.
Fixed bug where multi-track files were consolidated into a single entry on saving/loading a playlist.
2007-10-13 04:53:48 +00:00
vspader
74bfd92971 Added new supported file types to Info.plist 2007-10-13 04:36:43 +00:00
vspader
edf510908d Removed user files. 2007-10-13 03:58:50 +00:00
vspader
bfb3e1ed49 Updated FLAC to 1.2.1 2007-10-13 03:57:01 +00:00
vspader
d837819fd2 Forgot to add dumb framework! duh! 2007-10-13 02:28:53 +00:00
vspader
11b5a27b35 Added dumb metadatareader files. 2007-10-13 02:26:28 +00:00
vspader
08865a051f Added limited mod/it/xm metadata reading (Only title seems available from dumb). 2007-10-13 02:20:51 +00:00
vspader
286268e5ac Added metadata reader for game music files. 2007-10-13 01:36:55 +00:00
vspader
8c4f5fa41c Forgot cuesheet metadata reader files. 2007-10-13 01:36:42 +00:00
vspader
b51d8aedb5 Added metadata reading to cue sheets. 2007-10-13 01:07:19 +00:00
vspader
97e662208d Updated TODO.
Fixed runloop mode in AudioScrobbler.
2007-10-12 03:25:11 +00:00
vspader
139bab5e0e Fixed up streaming a bit.
Removed debugging code for http source. Was that in 0.06? Whoops.
2007-10-12 02:55:59 +00:00
vspader
5d2e4f6d4a Fixed backwards seeking. 2007-10-12 01:49:36 +00:00
vspader
2508c88b8a Modified dumb decoder to use sources. 2007-10-12 01:46:31 +00:00
vspader
40f0450343 Cue sheets now use index 01. 2007-10-12 01:15:11 +00:00
vspader
6b7550de97 Added mod/tracker support through Dumb. 2007-10-12 01:03:12 +00:00
vspader
2b0eaf3369 Added GME for game music emulation. 2007-10-11 23:11:58 +00:00
vspader
ad844b1df3 Finished comment. 2007-10-11 11:31:36 +00:00
vspader
b57bcc121c Added support for gapless multitrack files.
Modified cue sheet plugin to use it.
2007-10-11 02:08:29 +00:00
vspader
4bcf22ced2 Whoops, forgot to add a couple cue sheet related files. 2007-10-10 03:13:38 +00:00
vspader
50395e6e72 Basic cue sheet support working. Bug city. 2007-10-10 01:59:25 +00:00
vspader
4935c5ddfc Added beginnings of cuesheet plugin. 2007-10-09 02:25:40 +00:00
vspader
88aecc7de2 Added AudioContainer plugin and made pls and m3u loaders that use it. 2007-10-09 01:20:46 +00:00
vspader
0e2da5efc7 Cleaned up converter. Added Media Keys support for apple's new multimedia keyboard (has not been tested). 2007-10-03 22:26:39 +00:00
vspader
5fd24bd88b Fixed ConverterNode.m file. 2007-10-03 20:24:14 +00:00
vspader
5ad2728d3c Moved converter to a seperate node again. 2007-10-03 20:23:14 +00:00
vspader
0584150ffd Missed a couple of updated taglib files. 2007-07-15 02:41:10 +00:00
vspader
46df6f12f5 Removed Localization folder and scripts, since they won't be needed anymore.
Updated TagLib to latest svn trunk.
Cleaned up TagLib.
2007-07-15 02:32:48 +00:00
vspader
5903717dfb Updated TODO with first bugfix for 0.07. 2007-07-13 01:40:33 +00:00
5913 changed files with 3605685 additions and 499597 deletions

176
.clang-format Normal file
View file

@ -0,0 +1,176 @@
# The style used for all options not specifically set in the configuration.
BasedOnStyle: LLVM
# The extra indent or outdent of access modifiers, e.g. public:.
AccessModifierOffset: 0
# If true, aligns escaped newlines as far left as possible. Otherwise puts them into the right-most column.
AlignEscapedNewlinesLeft: false
# If true, aligns trailing comments.
AlignTrailingComments: false
# Allow putting all parameters of a function declaration onto the next line even if BinPackParameters is false.
AllowAllParametersOfDeclarationOnNextLine: false
# Allows contracting simple braced statements to a single line.
AllowShortBlocksOnASingleLine: true
# If true, short case labels will be contracted to a single line.
AllowShortCaseLabelsOnASingleLine: false
# Dependent on the value, int f() { return 0; } can be put on a single line. Possible values: None, Inline, All.
AllowShortFunctionsOnASingleLine: None
# If true, if (a) return; can be put on a single line.
AllowShortIfStatementsOnASingleLine: true
# If true, while (true) continue; can be put on a single line.
AllowShortLoopsOnASingleLine: true
# If true, always break after function definition return types. More truthfully called break before the identifier following the type in a function definition.
AlwaysBreakAfterDefinitionReturnType: false
# If true, always break before multiline string literals.
AlwaysBreakBeforeMultilineStrings: false
# If true, always break after the template<...> of a template declaration.
AlwaysBreakTemplateDeclarations: true
# If false, a function calls arguments will either be all on the same line or will have one line each.
#BinPackArguments: true
# If false, a function declarations or function definitions parameters will either all be on the same line or will have one line each.
BinPackParameters: true
# The way to wrap binary operators. Possible values: None, NonAssignment, All.
BreakBeforeBinaryOperators: None
# The brace breaking style to use. Possible values: Attach, Linux, Stroustrup, Allman, GNU.
BreakBeforeBraces: Attach
# If true, ternary operators will be placed after line breaks.
BreakBeforeTernaryOperators: false
# Always break constructor initializers before commas and align the commas with the colon.
BreakConstructorInitializersBeforeComma: false
# The column limit. A column limit of 0 means that there is no column limit.
ColumnLimit: 0
# A regular expression that describes comments with special meaning, which should not be split into lines or otherwise changed.
CommentPragmas: '^ IWYU pragma:'
# If the constructor initializers dont fit on a line, put each initializer on its own line.
ConstructorInitializerAllOnOneLineOrOnePerLine: false
# The number of characters to use for indentation of constructor initializer lists.
ConstructorInitializerIndentWidth: 0
# Indent width for line continuations.
ContinuationIndentWidth: 0
# If true, format braced lists as best suited for C++11 braced lists.
Cpp11BracedListStyle: false
# If true, analyze the formatted file for the most common alignment of & and *. PointerAlignment is then used only as fallback.
DerivePointerAlignment: true
# Disables formatting at all.
DisableFormat: false
# If true, clang-format detects whether function calls and definitions are formatted with one parameter per line.
ExperimentalAutoDetectBinPacking: false
# A vector of macros that should be interpreted as foreach loops instead of as function calls.
#ForEachMacros: ''
# Indent case labels one level from the switch statement. When false, use the same indentation level as for the switch statement. Switch statement body is always indented one level more than case labels.
IndentCaseLabels: true
# The number of columns to use for indentation.
IndentWidth: 4
# Indent if a function definition or declaration is wrapped after the type.
IndentWrappedFunctionNames: false
# If true, empty lines at the start of blocks are kept.
KeepEmptyLinesAtTheStartOfBlocks: false
# Language, this format style is targeted at. Possible values: None, Cpp, Java, JavaScript, Proto.
# Language: None
# The maximum number of consecutive empty lines to keep.
MaxEmptyLinesToKeep: 1
# The indentation used for namespaces. Possible values: None, Inner, All.
NamespaceIndentation: All
# The number of characters to use for indentation of ObjC blocks.
ObjCBlockIndentWidth: 4
# Add a space after @property in Objective-C, i.e. use \@property (readonly) instead of \@property(readonly).
ObjCSpaceAfterProperty: false
# Add a space in front of an Objective-C protocol list, i.e. use Foo <Protocol> instead of Foo<Protocol>.
ObjCSpaceBeforeProtocolList: true
# The penalty for breaking a function call after “call(”.
PenaltyBreakBeforeFirstCallParameter: 1000
# The penalty for each line break introduced inside a comment.
PenaltyBreakComment: 1000
# The penalty for breaking before the first <<.
PenaltyBreakFirstLessLess: 1000
# The penalty for each line break introduced inside a string literal.
PenaltyBreakString: 1000
# The penalty for each character outside of the column limit.
PenaltyExcessCharacter: 1000
# Penalty for putting the return type of a function onto its own line.
PenaltyReturnTypeOnItsOwnLine: 1000
# Pointer and reference alignment style. Possible values: Left, Right, Middle.
PointerAlignment: Left
# If true, a space may be inserted after C style casts.
SpaceAfterCStyleCast: false
# If false, spaces will be removed before assignment operators.
SpaceBeforeAssignmentOperators: true
# Defines in which cases to put a space before opening parentheses. Possible values: Never, ControlStatements, Always.
SpaceBeforeParens: Never
# If true, spaces may be inserted into ().
SpaceInEmptyParentheses: false
# The number of spaces before trailing line comments (// - comments).
SpacesBeforeTrailingComments: 1
# If true, spaces will be inserted after < and before > in template argument lists.
SpacesInAngles: false
# If true, spaces may be inserted into C style casts.
SpacesInCStyleCastParentheses: false
# If true, spaces are inserted inside container literals (e.g. ObjC and Javascript array and dict literals).
SpacesInContainerLiterals: false
# If true, spaces will be inserted after ( and before ).
SpacesInParentheses: false
# If true, spaces will be inserted after [ and before ].
SpacesInSquareBrackets: false
# Format compatible with this standard, e.g. use A<A<int> > instead of A<A<int>> for LS_Cpp03. Possible values: Cpp03, Cpp11, Auto.
Standard: Auto
# The number of columns used for tab stops.
TabWidth: 4
# The way to use tab characters in the resulting file. Possible values: Never, ForIndentation, Always.
UseTab: ForIndentation

12
.githooks/pre-commit Executable file
View file

@ -0,0 +1,12 @@
#!/bin/sh
MATCHES=$(git grep -n -E "(DevelopmentTeam|DEVELOPMENT_TEAM) =" .)
COUNT=$(echo -n "$MATCHES\c" | grep -cvE '(Shared.xcconfig|= "")')
if [ $COUNT -ne 0 ]; then
ERRORS=$(echo -n "$MATCHES\c" | grep -vE '= ""')
echo $COUNT
echo "Remove Development Team specifications from project files:"
echo "$ERRORS";
exit 1;
fi

4
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,4 @@
github: kode54
ko_fi: kode54
patreon: kode54
liberapay: kode54

31
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View file

@ -0,0 +1,31 @@
---
name: Feedback
about: Report bugs or suggest new features
title: ''
labels:
assignees: kode54
---
**Describe**
A clear and concise description of what the issue is.
**To Reproduce** (delete if not applicable)
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Version information:***
- macOS version: ...
- Cog version: ... (_cut and paste from title_)
**Additional context**
Add any other context about the issue here.

BIN
.github/images/HeSuVi-channel-map.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 2809.9 600" style="enable-background:new 0 0 2809.9 600;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FF6336;}
.st1{fill:#FFC501;}
.st2{fill:#A4A14A;}
</style>
<g>
<polygon class="st0" points="393.5,468.8 524.7,468.8 524.7,376.1 355.1,376.1 262.3,468.8 169.6,376.1 0,376.1 0,468.8
131.2,468.8 262.3,600 "/>
<rect y="190.6" class="st1" width="524.7" height="92.8"/>
<rect y="5.1" class="st2" width="524.7" height="92.8"/>
</g>
<path d="M733.3,5.1h83.4v455.2h-83.4V5.1z"/>
<path d="M946.7,447.3c-26.3-14.5-47.2-34.5-62.6-59.7c-15.4-25.3-23.1-53.1-23.1-83.4s7.7-58.2,23.1-83.4
c15.4-25.3,36.2-45.2,62.6-59.7c26.3-14.5,54.9-21.8,85.7-21.8c30.8,0,59.3,7.3,85.7,21.8c26.3,14.5,47.2,34.5,62.6,59.7
c15.4,25.3,23.1,53.1,23.1,83.4s-7.7,58.2-23.1,83.4c-15.4,25.3-36.3,45.2-62.6,59.7c-26.3,14.5-54.9,21.8-85.7,21.8
C1001.5,469.1,973,461.8,946.7,447.3z M1076.2,380.9c13.3-7.4,23.9-17.8,31.9-31.3s12-28.7,12-45.5s-4-32-12-45.5
s-18.6-23.9-31.9-31.3c-13.3-7.4-27.9-11.1-43.9-11.1s-30.7,3.7-43.9,11.1c-13.3,7.4-23.9,17.8-31.9,31.3s-12,28.7-12,45.5
c0,16.9,4,32,12,45.5s18.6,23.9,31.9,31.3c13.3,7.4,27.9,11.1,43.9,11.1C1048.3,391.9,1063,388.3,1076.2,380.9z"/>
<path d="M1247.9,5.1h83.4v271.2L1440,147.9h99.2l-122.6,144.8l131.5,167.5h-106.8l-110-144.8v144.8h-83.4L1247.9,5.1L1247.9,5.1z"/>
<path d="M1626.9,448.8c-23.4-13.5-42.4-32.8-56.9-57.8c-14.5-25.1-21.8-54-21.8-86.9c0-29.9,7-57.5,20.9-82.8s32.9-45.3,56.9-60.1
c24-14.7,50.3-22.1,79-22.1c20.2,0,38.7,3.4,55.3,10.1c16.6,6.7,29.4,15.8,38.3,27.2V148h83.4v312.3h-83.4v-28.4
c-13.1,12.2-27,21.5-41.7,27.8c-14.8,6.3-33.7,9.5-56.9,9.5C1674.6,469.1,1650.2,462.3,1626.9,448.8z M1778.9,366.7
c15.6-16.9,23.4-37.7,23.4-62.6s-7.8-45.7-23.4-62.6c-15.6-16.8-36.2-25.3-61.9-25.3c-25.7,0-46.4,8.4-62,25.3s-23.4,37.7-23.4,62.6
s7.8,45.7,23.4,62.6s36.2,25.3,62,25.3C1742.6,391.9,1763.3,383.5,1778.9,366.7z"/>
<path d="M1942.6,5.1h83.4v455.2h-83.4V5.1z"/>
<path d="M2091.2,89.8C2081,79.7,2076,67.4,2076,53.1c0-14.7,5.1-27.3,15.2-37.6C2101.3,5.2,2113.5,0,2127.8,0
c14.7,0,27.3,5.2,37.6,15.5s15.5,22.9,15.5,37.6c0,14.3-5.2,26.5-15.5,36.7c-10.3,10.1-22.9,15.2-37.6,15.2
C2113.5,104.9,2101.3,99.9,2091.2,89.8z M2086.7,147.9h83.4v312.3h-83.4V147.9z"/>
<path d="M2227.1,438.7l19-78.4h3.8c27.4,21.1,55.4,31.6,84.1,31.6c11.8,0,21.4-2.2,28.8-6.6c7.4-4.4,11.1-10.8,11.1-19.3
c0-8.8-4.3-16-13-21.5c-8.6-5.5-24.8-12.2-48.4-20.2c-24-8-42.7-19.6-55.9-34.8c-13.3-15.2-19.9-33.1-19.9-53.7
c0-29.1,10.8-52.5,32.6-70.2c21.7-17.7,49.2-26.6,82.5-26.6c16.9,0,31.8,1.6,44.9,4.7c13.1,3.2,25.5,8.3,37.3,15.5l3.2,79.6h-4.4
c-15.2-9.7-28.7-17-40.5-21.8s-25.1-7.3-39.8-7.3c-10.5,0-19.2,2.1-25.9,6.3s-10.1,9.7-10.1,16.4c0,8.9,4.2,16.1,12.7,21.8
c8.4,5.7,24.2,12.5,47.4,20.5c26.5,8.9,46.7,19.6,60.4,32.2s20.5,32.2,20.5,58.8c0,21.9-5.5,40.7-16.4,56.3
c-11,15.6-25.4,27.3-43.3,35.1c-17.9,7.8-37.6,11.7-59.1,11.7C2294.9,469.1,2257.8,459,2227.1,438.7z"/>
<path d="M2574.8,446.9c-26.1-14.7-46.7-34.9-61.6-60.4c-15-25.5-22.4-53.8-22.4-85c0-30.3,7.1-57.8,21.2-82.5
c14.1-24.7,33.7-44.1,58.8-58.5c25.1-14.3,53.4-21.5,85-21.5c32,0,59.7,7.5,83.1,22.4c23.4,15,41.1,34.9,53.1,59.7
c12,24.9,18,51.6,18,80.3v24.7h-239.6c5.1,23.6,15.9,41.5,32.6,53.7c16.6,12.2,38.7,18.3,66.1,18.3c41.7,0,78.2-13.7,109.4-41.1h8.9
l-3.2,79c-19,11-39,19.2-60.1,24.7s-41.3,8.2-60.7,8.2C2630.4,469.1,2600.9,461.7,2574.8,446.9z M2726.5,269.3
c-2.1-19-10-33.8-23.7-44.6c-13.7-10.7-30.5-16.1-50.3-16.1c-19.4,0-36.4,5.2-50.9,15.5s-24.3,25.4-29.4,45.2H2726.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
.github/images/MainWindow.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 808 KiB

BIN
.github/images/MiniWindow.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

56
.github/workflows/debug.yml vendored Normal file
View file

@ -0,0 +1,56 @@
name: Check if Cog buildable
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
build:
name: Build Universal Cog.app
runs-on: macos-15
env:
XCODE_DERIVEDDATA_PATH: build
steps:
- name: Switch to Xcode 16
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: 16
- name: Check out repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Unpack libraries
run: >
cd ThirdParty && tar xvf libraries.tar.xz
- name: Run xcodebuild
run: >
xcodebuild
-quiet
-project Cog.xcodeproj
-scheme Cog
-configuration Debug
-arch x86_64
-arch arm64
-derivedDataPath $XCODE_DERIVEDDATA_PATH
CODE_SIGNING_ALLOWED=NO
ONLY_ACTIVE_ARCH=NO
build
- name: Package archive
run: >
ditto
-c
-k
--sequesterRsrc
--keepParent
--zlibCompressionLevel 9
$XCODE_DERIVEDDATA_PATH/Build/Products/Debug/Cog.app
$XCODE_DERIVEDDATA_PATH/Cog.zip
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: Cog
path: ${{ env.XCODE_DERIVEDDATA_PATH }}/Cog.zip

56
.gitignore vendored Normal file
View file

@ -0,0 +1,56 @@
.DS_Store
xcuserdata
/build
# Special cog exceptions
!Frameworks/OpenMPT/OpenMPT/build
# User-specific xcconfig files
Xcode-config/DEVELOPMENT_TEAM.xcconfig
Xcode-config/SENTRY_SETTINGS.xcconfig
# Plist derived from template at build time
/Info.plist
# This indicates the libraries are up to date
/ThirdParty/libraries.updated
# Temporary file to indicate libraries are being extracted by one process
/ThirdParty/libraries.extracting
# The project will unpack these before building, if necessary
/ThirdParty/BASS/libbass.dylib
/ThirdParty/BASS/libbass_mpc.dylib
/ThirdParty/BASS/libbassflac.dylib
/ThirdParty/BASS/libbassmidi.dylib
/ThirdParty/BASS/libbassopus.dylib
/ThirdParty/BASS/libbasswv.dylib
/ThirdParty/avif/lib/libaom.a
/ThirdParty/avif/lib/libavif.a
/ThirdParty/fdk-aac/lib/libfdk-aac.2.dylib
/ThirdParty/fdk-aac/lib/libfdk-aac.a
/ThirdParty/fdk-aac/lib/libfdk-aac.dylib
/ThirdParty/fdk-aac/lib/libfdk-aac.la
/ThirdParty/fdk-aac/lib/pkgconfig/fdk-aac.pc
/ThirdParty/ffmpeg/lib/libavcodec.61.dylib
/ThirdParty/ffmpeg/lib/libavformat.61.dylib
/ThirdParty/ffmpeg/lib/libavutil.59.dylib
/ThirdParty/ffmpeg/lib/libswresample.5.dylib
/ThirdParty/flac/lib/libFLAC.12.dylib
/ThirdParty/libid3tag/lib/libid3tag.a
/ThirdParty/libmad/lib/libmad.a
/ThirdParty/libopenmpt/lib/libopenmpt.a
/ThirdParty/libopenmpt_old/lib/libopenmpt.old.a
/ThirdParty/libvgm/lib/libvgm-emu.a
/ThirdParty/libvgm/lib/libvgm-player.a
/ThirdParty/libvgm/lib/libvgm-utils.a
/ThirdParty/mpg123/lib/libmpg123.0.dylib
/ThirdParty/ogg/lib/libogg.0.dylib
/ThirdParty/opus/lib/libopus.0.dylib
/ThirdParty/opusfile/lib/libopusfile.0.dylib
/ThirdParty/rubberband/lib/librubberband.3.dylib
/ThirdParty/speex/libspeex.a
/ThirdParty/vorbis/lib/libvorbisfile.3.dylib
/ThirdParty/vorbis/lib/libvorbis.0.dylib
/ThirdParty/soxr/lib/libsoxr.0.dylib
/ThirdParty/WavPack/lib/libwavpack.a

21
.gitmodules vendored Normal file
View file

@ -0,0 +1,21 @@
[submodule "Frameworks/mGBA/mGBA/mgba"]
path = Frameworks/mGBA/mGBA/mgba
url = https://github.com/kode54/mgba.git
[submodule "Frameworks/AdPlug/AdPlug/adplug"]
path = Frameworks/AdPlug/AdPlug/adplug
url = https://github.com/kode54/adplug.git
[submodule "Frameworks/libbinio/libbinio/libbinio"]
path = Frameworks/libbinio/libbinio/libbinio
url = https://github.com/adplug/libbinio.git
[submodule "Frameworks/AdPlug/AdPlug/database"]
path = Frameworks/AdPlug/AdPlug/database
url = https://github.com/adplug/database.git
[submodule "Frameworks/libatrac9/libatrac9"]
path = Frameworks/libatrac9/libatrac9
url = https://github.com/Thealexbarney/LibAtrac9.git
[submodule "Frameworks/shpakovski/MASShortcut"]
path = Frameworks/shpakovski/MASShortcut
url = https://github.com/kode54/MASShortcut.git
[submodule "Frameworks/libsidplayfp/sidplayfp"]
path = Frameworks/libsidplayfp/sidplayfp
url = https://github.com/kode54/libsidplayfp.git

8
.hgignore Normal file
View file

@ -0,0 +1,8 @@
syntax: glob
*.mode1v3
*.mode2v3
*.pbxuser
xcuserdata
build
*/build
.DS_Store

2
.hgtags Normal file
View file

@ -0,0 +1,2 @@
4abdff3798f81313c3d98aa6ef3cf22c73777c88 r516
ddfc3989351f477a3431f749649e6d832ccfcdf2 k54

15
.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Debug Local File",
"type": "Ruby",
"request": "launch",
"program": "${workspaceRoot}/Scripts/update_feed.rb"
},
null
]
}

9
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,9 @@
{
"editor.formatOnSave": false,
"files.associations": {
"*.h": "objective-c",
"*.m": "objective-c"
},
"clang-format.executable": "/usr/local/bin/clang-format",
"clang-format.language.objective-c.style": "{ BasedOnStyle: Google, IndentWidth: 4, ObjCBlockIndentWidth: 4 }"
}

View file

@ -2,78 +2,117 @@
#import <Cocoa/Cocoa.h>
#import "NDHotKeyEvent.h"
@class FileTreeViewController;
@class PlaybackController;
@class PlaylistController;
@class PlaylistView;
@class FileTreeController;
@class FileOutlineView;
@class AppleRemote;
@class PlaylistLoader;
@class PreferencesController;
@interface AppController : NSObject {
IBOutlet NSObjectController *currentEntryController;
@interface AppController : NSObject
{
IBOutlet PlaybackController *playbackController;
IBOutlet PlaylistController *playlistController;
IBOutlet PlaylistController *playlistController;
IBOutlet PlaylistLoader *playlistLoader;
IBOutlet NSPanel *mainWindow;
IBOutlet NSWindow *mainWindow;
IBOutlet NSWindow *miniWindow;
IBOutlet NSSplitView *mainView;
IBOutlet NSButton *playButton;
IBOutlet NSButton *prevButton;
IBOutlet NSButton *nextButton;
IBOutlet NSButton *infoButton;
IBOutlet NSSegmentedControl *playbackButtons;
IBOutlet NSButton *fileButton;
IBOutlet NSButton *shuffleButton;
IBOutlet NSButton *repeatButton;
IBOutlet NSButton *randomizeButton;
IBOutlet NSDrawer *infoDrawer;
IBOutlet NSDrawer *fileDrawer;
IBOutlet FileTreeController *fileTreeController;
IBOutlet FileOutlineView *fileOutlineView;
IBOutlet NSTextField *totalTimeField;
IBOutlet PlaylistView *playlistView;
IBOutlet NSMenuItem *showIndexColumn;
IBOutlet NSMenuItem *showTitleColumn;
IBOutlet NSMenuItem *showAlbumArtistColumn;
IBOutlet NSMenuItem *showArtistColumn;
IBOutlet NSMenuItem *showAlbumColumn;
IBOutlet NSMenuItem *showGenreColumn;
IBOutlet NSMenuItem *showPlayCountColumn;
IBOutlet NSMenuItem *showLengthColumn;
IBOutlet NSMenuItem *showTrackColumn;
IBOutlet NSMenuItem *showYearColumn;
NDHotKeyEvent *playHotKey;
NDHotKeyEvent *prevHotKey;
NDHotKeyEvent *nextHotKey;
IBOutlet NSMenu *dockMenu;
IBOutlet NSMenuItem *currentArtistItem;
AppleRemote *remote;
BOOL remoteButtonHeld; /* true as long as the user holds the left,right,plus or minus on the remote control */
IBOutlet NSWindowController *spotlightWindowController;
IBOutlet FileTreeViewController *fileTreeViewController;
IBOutlet PreferencesController *preferencesController;
NSOperationQueue *queue; // Since we are the app delegate, we take care of the op queue
NSMutableSet *expandedNodes;
BOOL miniMode;
}
@property(strong) IBOutlet NSButton *infoButton;
@property(strong) IBOutlet NSButton *infoButtonMini;
- (IBAction)openURL:(id)sender;
- (IBAction)openFiles:(id)sender;
- (IBAction)delEntries:(id)sender;
- (IBAction)savePlaylist:(id)sender;
- (IBAction)donate:(id)sender;
- (IBAction)privacyPolicy:(id)sender;
- (IBAction)toggleInfoDrawer:(id)sender;
- (IBAction)toggleFileDrawer:(id)sender;
- (void)drawerDidOpen:(NSNotification *)notification;
- (void)drawerDidClose:(NSNotification *)notification;
- (IBAction)feedback:(id)sender;
//Fun stuff
- (void)initDefaults;
// Fun stuff
- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag;
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename;
- (void)application:(NSApplication *)theApplication openFiles:(NSArray *)filenames;
- (void)registerHotKeys;
OSStatus handleHotKey(EventHandlerCallRef nextHandler,EventRef theEvent,void *userData);
- (void)clickPlay;
- (void)clickPause;
- (void)clickStop;
- (void)clickPrev;
- (void)clickNext;
- (void)clickSpam;
- (void)clickSeek:(NSTimeInterval)position;
- (IBAction)increaseFontSize:(id)sender;
- (IBAction)decreaseFontSize:(id)sender;
- (void)changeFontSize:(float)size;
- (void)nodeExpanded:(NSNotification *)notification;
- (void)nodeCollapsed:(NSNotification *)notification;
- (IBAction)toggleMiniMode:(id)sender;
- (IBAction)toggleToolbarStyle:(id)sender;
- (BOOL)pathSuggesterEmpty;
+ (BOOL)globalPathSuggesterEmpty;
- (void)showPathSuggester;
+ (void)globalShowPathSuggester;
- (void)selectTrack:(id)sender;
- (IBAction)showRubberbandSettings:(id)sender;
+ (void)globalShowRubberbandSettings;
@property NSWindow *mainWindow;
@property NSWindow *miniWindow;
@property BOOL miniMode;
@property(nonatomic) BOOL floatingMiniWindow;
@end

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,33 @@
//
// DockIconController.h
// Cog
//
// Created by Vincent Spader on 2/28/09.
// Copyright 2009 __MyCompanyName__. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@class PlaybackController;
@interface DockIconController : NSObject {
NSImage *dockImage;
NSInteger lastDockCustom;
NSInteger lastDockCustomPlaque;
NSInteger dockCustomLoaded;
NSImage *dockCustomStop;
NSImage *dockCustomPlay;
NSImage *dockCustomPause;
IBOutlet PlaybackController *playbackController;
NSInteger lastPlaybackStatus;
NSInteger lastColorfulStatus;
NSNumber *lastProgressStatus;
NSImageView *imageView;
NSProgressIndicator *progressIndicator;
}
@end

View file

@ -0,0 +1,281 @@
//
// DockIconController.m
// Cog
//
// Created by Vincent Spader on 2/28/09.
// Copyright 2009 __MyCompanyName__. All rights reserved.
//
#import "DockIconController.h"
#import "PlaybackController.h"
#import <CogAudio/Status.h>
@implementation DockIconController
static NSString *DockIconPlaybackStatusObservationContext = @"DockIconPlaybackStatusObservationContext";
static NSString *CogCustomDockIconsReloadNotification = @"CogCustomDockIconsReloadNotification";
- (void)startObserving {
[playbackController addObserver:self forKeyPath:@"playbackStatus" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial) context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
[playbackController addObserver:self forKeyPath:@"progressOverall" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionOld) context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.colorfulDockIcons" options:0 context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.customDockIcons" options:0 context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.customDockIconsPlaque" options:0 context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshDockIcons:) name:CogCustomDockIconsReloadNotification object:nil];
}
- (void)stopObserving {
[playbackController removeObserver:self forKeyPath:@"playbackStatus" context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
[playbackController removeObserver:self forKeyPath:@"progressOverall" context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.colorfulDockIcons" context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.customDockIcons" context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.customDockIconsPlaque" context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
[[NSNotificationCenter defaultCenter] removeObserver:self name:CogCustomDockIconsReloadNotification object:nil];
}
- (void)startObservingProgress:(NSProgress *)progress {
[progress addObserver:self forKeyPath:@"fractionCompleted" options:0 context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
}
- (void)stopObservingProgress:(NSProgress *)progress {
[progress removeObserver:self forKeyPath:@"fractionCompleted" context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
}
static NSString *getBadgeName(NSString *baseName, BOOL colorfulIcons) {
if(colorfulIcons) {
return [baseName stringByAppendingString:@"Colorful"];
} else {
return [baseName stringByAppendingString:@"Normal"];
}
}
static NSString *getCustomIconName(NSString *baseName) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *basePath = [[paths firstObject] stringByAppendingPathComponent:@"Cog"];
basePath = [basePath stringByAppendingPathComponent:@"Icons"];
basePath = [basePath stringByAppendingPathComponent:baseName];
return [basePath stringByAppendingPathExtension:@"png"];
}
- (BOOL)loadCustomDockIcons {
NSError *error = nil;
NSData *dataStopIcon = [NSData dataWithContentsOfFile:getCustomIconName(@"Stop") options:(NSDataReadingMappedIfSafe) error:&error];
if(!dataStopIcon || error) {
return NO;
}
NSData *dataPlayIcon = [NSData dataWithContentsOfFile:getCustomIconName(@"Play") options:(NSDataReadingMappedIfSafe) error:&error];
if(!dataPlayIcon || error) {
return NO;
}
NSData *dataPauseIcon = [NSData dataWithContentsOfFile:getCustomIconName(@"Pause") options:(NSDataReadingMappedIfSafe) error:&error];
if(!dataPauseIcon || error) {
return NO;
}
dockCustomStop = [[NSImage alloc] initWithData:dataStopIcon];
dockCustomPlay = [[NSImage alloc] initWithData:dataPlayIcon];
dockCustomPause = [[NSImage alloc] initWithData:dataPauseIcon];
return (dockCustomStop && dockCustomPlay && dockCustomPause);
}
- (void)refreshDockIcon:(NSInteger)playbackStatus withProgress:(double)progressStatus {
// Really weird crash user experienced because the plaque image didn't load?
if(!dockImage || dockImage.size.width == 0 || dockImage.size.height == 0) return;
BOOL displayChanged = NO;
BOOL drawIcon = NO;
BOOL removeProgress = NO;
BOOL useCustomDockIcons = [[NSUserDefaults standardUserDefaults] boolForKey:@"customDockIcons"];
BOOL useCustomDockIconsPlaque = [[NSUserDefaults standardUserDefaults] boolForKey:@"customDockIconsPlaque"];
if(useCustomDockIcons && !dockCustomLoaded) {
dockCustomLoaded = [self loadCustomDockIcons];
if(!dockCustomLoaded) {
useCustomDockIcons = NO;
}
}
if(useCustomDockIcons != lastDockCustom ||
useCustomDockIconsPlaque != lastDockCustomPlaque) {
lastDockCustom = useCustomDockIcons;
lastDockCustomPlaque = useCustomDockIconsPlaque;
drawIcon = YES;
if(!useCustomDockIcons) {
dockCustomLoaded = NO;
dockCustomStop = nil;
dockCustomPlay = nil;
dockCustomPause = nil;
}
}
if(playbackStatus < 0)
playbackStatus = lastPlaybackStatus;
else {
lastPlaybackStatus = playbackStatus;
drawIcon = YES;
}
if(progressStatus < -2)
progressStatus = [lastProgressStatus doubleValue];
else {
if(progressStatus < 0 && [lastProgressStatus doubleValue] >= 0)
removeProgress = YES;
lastProgressStatus = @(progressStatus);
}
BOOL displayProgress = (progressStatus >= 0.0);
NSImage *badgeImage = nil;
BOOL colorfulIcons = [[NSUserDefaults standardUserDefaults] boolForKey:@"colorfulDockIcons"];
if((colorfulIcons && lastColorfulStatus < 1) ||
(!colorfulIcons && lastColorfulStatus != 0)) {
lastColorfulStatus = colorfulIcons ? 1 : 0;
drawIcon = YES;
}
NSDockTile *dockTile = [NSApp dockTile];
if(drawIcon) {
switch(playbackStatus) {
case CogStatusPlaying:
badgeImage = useCustomDockIcons ? dockCustomPlay : [NSImage imageNamed:getBadgeName(@"Play", colorfulIcons)];
break;
case CogStatusPaused:
badgeImage = useCustomDockIcons ? dockCustomPause : [NSImage imageNamed:getBadgeName(@"Pause", colorfulIcons)];
break;
default:
badgeImage = useCustomDockIcons ? dockCustomStop : [NSImage imageNamed:getBadgeName(@"Stop", colorfulIcons)];
break;
}
NSSize badgeSize = [badgeImage size];
NSImage *newDockImage = (useCustomDockIcons && !useCustomDockIconsPlaque) ? [[NSImage alloc] initWithSize:NSMakeSize(1024, 1024)] : [dockImage copy];
[newDockImage lockFocus];
[badgeImage drawInRect:NSMakeRect(0, 0, 1024, 1024)
fromRect:NSMakeRect(0, 0, badgeSize.width, badgeSize.height)
operation:NSCompositingOperationSourceOver
fraction:1.0];
[newDockImage unlockFocus];
imageView = [[NSImageView alloc] init];
[imageView setImage:newDockImage];
[dockTile setContentView:imageView];
progressIndicator = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(0.0, 0.0, dockTile.size.width, 10.0)];
[progressIndicator setStyle:NSProgressIndicatorStyleBar];
[progressIndicator setIndeterminate:NO];
[progressIndicator setBezeled:YES];
[progressIndicator setMinValue:0];
[progressIndicator setMaxValue:100];
[progressIndicator setHidden:YES];
[imageView addSubview:progressIndicator];
displayChanged = YES;
}
if(displayProgress) {
if(!imageView) {
imageView = [[NSImageView alloc] init];
[imageView setImage:[NSApp applicationIconImage]];
[dockTile setContentView:imageView];
}
if(!progressIndicator) {
progressIndicator = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(0.0, 0.0, dockTile.size.width, 10.0)];
[progressIndicator setIndeterminate:NO];
[progressIndicator setBezeled:YES];
[progressIndicator setMinValue:0];
[progressIndicator setMaxValue:100];
[imageView addSubview:progressIndicator];
}
[progressIndicator setDoubleValue:progressStatus];
[progressIndicator setHidden:NO];
displayChanged = YES;
}
if(removeProgress) {
if(progressIndicator)
[progressIndicator setHidden:YES];
displayChanged = YES;
}
if(displayChanged)
[dockTile display];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if([DockIconPlaybackStatusObservationContext isEqual:(__bridge id)(context)]) {
if([keyPath isEqualToString:@"playbackStatus"]) {
NSInteger playbackStatus = [[change objectForKey:NSKeyValueChangeNewKey] integerValue];
[self refreshDockIcon:playbackStatus withProgress:-10];
} else if([keyPath isEqualToString:@"progressOverall"]) {
double progressStatus = [lastProgressStatus doubleValue];
id objNew = [change objectForKey:NSKeyValueChangeNewKey];
id objOld = [change objectForKey:NSKeyValueChangeOldKey];
NSProgress *progressNew = nil, *progressOld = nil;
if(objNew && [objNew isKindOfClass:[NSProgress class]])
progressNew = (NSProgress *)objNew;
if(objOld && [objOld isKindOfClass:[NSProgress class]])
progressOld = (NSProgress *)objOld;
if(progressOld) {
[self stopObservingProgress:progressOld];
progressStatus = -1;
}
if(progressNew) {
[self startObservingProgress:progressNew];
progressStatus = progressNew.fractionCompleted * 100.0;
}
[self refreshDockIcon:-1 withProgress:progressStatus];
} else if([keyPath isEqualToString:@"values.colorfulDockIcons"] ||
[keyPath isEqualToString:@"values.customDockIcons"] ||
[keyPath isEqualToString:@"values.customDockIconsPlaque"]) {
[self refreshDockIcon:-1 withProgress:-10];
} else if([keyPath isEqualToString:@"fractionCompleted"]) {
double progressStatus = [(NSProgress *)object fractionCompleted];
[self refreshDockIcon:-1 withProgress:progressStatus * 100.0];
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)refreshDockIcons:(NSNotification *)notification {
lastDockCustom = NO;
dockCustomLoaded = NO;
[self refreshDockIcon:-1 withProgress:-10];
}
- (void)awakeFromNib {
dockImage = [[NSImage imageNamed:@"Plaque"] copy];
lastColorfulStatus = -1;
lastProgressStatus = @(-1.0);
imageView = nil;
progressIndicator = nil;
[self startObserving];
}
- (void)dealloc {
[self stopObserving];
}
@end

View file

@ -0,0 +1,13 @@
//
// MediaKeysApplication.h
// Cog
//
// Created by Vincent Spader on 10/3/07.
// Copyright 2007 __MyCompanyName__. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface MediaKeysApplication : NSApplication
@end

View file

@ -0,0 +1,76 @@
//
// MediaKeysApplication.m
// Cog
//
// Created by Vincent Spader on 10/3/07.
// Copyright 2007 __MyCompanyName__. All rights reserved.
//
#import "MediaKeysApplication.h"
#import "AppController.h"
#import "Logging.h"
#import <MediaPlayer/MPMediaItem.h>
#import <MediaPlayer/MPNowPlayingInfoCenter.h>
#import <MediaPlayer/MPRemoteCommand.h>
#import <MediaPlayer/MPRemoteCommandCenter.h>
#import <MediaPlayer/MPRemoteCommandEvent.h>
@implementation MediaKeysApplication {
AppController *_appController;
}
- (void)finishLaunching {
[super finishLaunching];
_appController = (AppController *)[self delegate];
MPRemoteCommandCenter *remoteCommandCenter = [MPRemoteCommandCenter sharedCommandCenter];
[remoteCommandCenter.playCommand setEnabled:YES];
[remoteCommandCenter.pauseCommand setEnabled:YES];
[remoteCommandCenter.togglePlayPauseCommand setEnabled:YES];
[remoteCommandCenter.stopCommand setEnabled:YES];
[remoteCommandCenter.changePlaybackPositionCommand setEnabled:YES];
[remoteCommandCenter.nextTrackCommand setEnabled:YES];
[remoteCommandCenter.previousTrackCommand setEnabled:YES];
[[remoteCommandCenter playCommand] addTarget:self action:@selector(clickPlay)];
[[remoteCommandCenter pauseCommand] addTarget:self action:@selector(clickPause)];
[[remoteCommandCenter togglePlayPauseCommand] addTarget:self action:@selector(clickPlay)];
[[remoteCommandCenter stopCommand] addTarget:self action:@selector(clickStop)];
[[remoteCommandCenter changePlaybackPositionCommand] addTarget:self action:@selector(clickSeek:)];
[[remoteCommandCenter nextTrackCommand] addTarget:self action:@selector(clickNext)];
[[remoteCommandCenter previousTrackCommand] addTarget:self action:@selector(clickPrev)];
}
- (MPRemoteCommandHandlerStatus)clickPlay {
[_appController clickPlay];
return MPRemoteCommandHandlerStatusSuccess;
}
- (MPRemoteCommandHandlerStatus)clickPause {
[_appController clickPause];
return MPRemoteCommandHandlerStatusSuccess;
}
- (MPRemoteCommandHandlerStatus)clickStop {
[_appController clickStop];
return MPRemoteCommandHandlerStatusSuccess;
}
- (MPRemoteCommandHandlerStatus)clickNext {
[_appController clickNext];
return MPRemoteCommandHandlerStatusSuccess;
}
- (MPRemoteCommandHandlerStatus)clickPrev {
[_appController clickPrev];
return MPRemoteCommandHandlerStatusSuccess;
}
- (MPRemoteCommandHandlerStatus)clickSeek:(MPChangePlaybackPositionCommandEvent *)event {
[_appController clickSeek:event.positionTime];
return MPRemoteCommandHandlerStatusSuccess;
}
@end

View file

@ -2,27 +2,53 @@
#import <Cocoa/Cocoa.h>
#import <Growl/GrowlApplicationBridge.h>
#import "AppController.h"
#import "CogAudio/AudioPlayer.h"
#import "CogAudio/Status.h"
#import "TrackingSlider.h"
#import "AudioScrobbler.h"
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AudioUnit/AudioUnit.h>
#import <CoreAudio/CoreAudioTypes.h>
#import "EqualizerWindowController.h"
#import "PlaylistEntry.h"
#define DEFAULT_VOLUME_DOWN 5
#define DEFAULT_VOLUME_UP DEFAULT_VOLUME_DOWN
#define DEFAULT_PITCH_DOWN 0.2
#define DEFAULT_PITCH_UP DEFAULT_PITCH_DOWN
#define DEFAULT_TEMPO_DOWN 0.2
#define DEFAULT_TEMPO_UP DEFAULT_TEMPO_DOWN
extern NSString *CogPlaybackDidBeginNotificiation;
extern NSString *CogPlaybackDidPauseNotificiation;
extern NSString *CogPlaybackDidResumeNotificiation;
extern NSString *CogPlaybackDidStopNotificiation;
extern NSDictionary *makeRGInfo(PlaylistEntry *pe);
@class PlaylistController;
@class PlaylistView;
@class PlaylistLoader;
@interface PlaybackController : NSObject <GrowlApplicationBridgeDelegate>
{
IBOutlet PlaylistController *playlistController;
@interface PlaybackController : NSObject {
IBOutlet AppController *appController;
IBOutlet PlaylistController *playlistController;
IBOutlet PlaylistView *playlistView;
IBOutlet PlaylistLoader *playlistLoader;
IBOutlet EqualizerWindowController *equalizerWindowController;
IBOutlet TrackingSlider *positionSlider;
IBOutlet NSSlider *volumeSlider;
IBOutlet NSTextField *timeField;
IBOutlet NSTextField *lengthField;
IBOutlet NSTextField *bitrateField;
IBOutlet NSButton *playButton;
IBOutlet NSSlider *pitchSlider;
IBOutlet NSSlider *tempoSlider;
IBOutlet NSButton *lockButton;
IBOutlet NSArrayController *outputDevices;
@ -30,23 +56,40 @@
AudioPlayer *audioPlayer;
int playbackStatus;
CogStatus playbackStatus;
double position;
double lastPosition;
BOOL seekable;
BOOL fading;
double currentVolume;
// progress bar display
NSProgress *progressOverall;
NSProgress *progressJob;
BOOL showTimeRemaining;
AudioUnit _eq;
}
AudioScrobbler *scrobbler;
}
@property CogStatus playbackStatus;
@property NSProgress *progressOverall;
@property NSProgress *progressJob;
- (IBAction)toggleShowTimeRemaining:(id)sender;
- (IBAction)changeVolume:(id)sender;
- (IBAction)volumeDown:(id)sender;
- (IBAction)volumeUp:(id)sender;
- (IBAction)changePitch:(id)sender;
- (IBAction)pitchDown:(id)sender;
- (IBAction)pitchUp:(id)sender;
- (IBAction)changeTempo:(id)sender;
- (IBAction)tempoDown:(id)sender;
- (IBAction)tempoUp:(id)sender;
- (IBAction)playPauseResume:(id)sender;
- (IBAction)pauseResume:(id)sender;
- (IBAction)skipToNextAlbum:(id)sender;
- (IBAction)skipToPreviousAlbum:(id)sender;
- (IBAction)play:(id)sender;
- (IBAction)pause:(id)sender;
@ -56,12 +99,37 @@
- (IBAction)next:(id)sender;
- (IBAction)prev:(id)sender;
- (IBAction)seek:(id)sender;
- (IBAction)seek:(id)sender toTime:(NSTimeInterval)time;
- (IBAction)eventSeekForward:(id)sender;
- (void)seekForward:(double)sender;
- (IBAction)eventSeekBackward:(id)sender;
- (void)seekBackward:(double)amount;
- (IBAction)fade:(id)sender;
- (IBAction)spam:(id)sender;
- (void)sendMetaData;
- (void)initDefaults;
- (void)audioFadeDown:(NSTimer *)audioTimer;
- (void)audioFadeUp:(NSTimer *)audioTimer;
- (void)updateTimeField:(double)pos;
- (void)playEntryAtIndex:(int)i;
- (void)playEntryAtIndex:(NSInteger)i;
- (void)playEntryAtIndex:(NSInteger)i startPaused:(BOOL)paused;
- (void)playEntryAtIndex:(NSInteger)i startPaused:(BOOL)paused andSeekTo:(id)offset;
- (void)playEntry:(PlaylistEntry *)pe;
- (void)playEntry:(PlaylistEntry *)pe startPaused:(BOOL)paused;
- (void)playEntry:(PlaylistEntry *)pe startPaused:(BOOL)paused andSeekTo:(id)offset;
// Playlist notifications
- (void)playlistDidChange:(PlaylistController *)p;
// For bindings
- (void)setPosition:(double)p;
- (double)position;
- (void)setSeekable:(BOOL)s;
- (BOOL)seekable;
@end

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,22 @@
//
// PlaybackEventController.h
// Cog
//
// Created by Vincent Spader on 3/5/09.
// Copyright 2009 __MyCompanyName__. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import <UserNotifications/UserNotifications.h>
#import "PlaybackController.h"
@interface PlaybackEventController
: NSObject <NSUserNotificationCenterDelegate, UNUserNotificationCenterDelegate> {
IBOutlet PlaybackController *playbackController;
IBOutlet NSWindow *mainWindow;
IBOutlet NSWindow *miniWindow;
}
@end

View file

@ -0,0 +1,388 @@
//
// PlaybackEventController.m
// Cog
//
// Created by Vincent Spader on 3/5/09.
// Copyright 2009 __MyCompanyName__. All rights reserved.
#import "PlaybackEventController.h"
#import "PlaylistEntry.h"
#if 0
NSString *TrackNotification = @"com.apple.iTunes.playerInfo";
NSString *TrackArtist = @"Artist";
NSString *TrackAlbum = @"Album";
NSString *TrackTitle = @"Name";
NSString *TrackGenre = @"Genre";
NSString *TrackNumber = @"Track Number";
NSString *TrackLength = @"Total Time";
NSString *TrackPath = @"Location";
NSString *TrackState = @"Player State";
typedef NS_ENUM(NSInteger, TrackStatus) { TrackPlaying,
TrackPaused,
TrackStopped };
#endif
@implementation PlaybackEventController {
NSOperationQueue *queue;
PlaylistEntry *entry;
Boolean didGainUN API_AVAILABLE(macosx(10.14));
}
- (void)initDefaults {
NSDictionary *defaultsDictionary = @{
@"notifications.enable": @YES,
@"notifications.itunes-style": @YES,
@"notifications.show-album-art": @YES
};
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultsDictionary];
}
- (id)init {
self = [super init];
if(self) {
[self initDefaults];
didGainUN = NO;
if(@available(macOS 10.14, *)) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center
requestAuthorizationWithOptions:UNAuthorizationOptionAlert
completionHandler:^(BOOL granted, NSError *_Nullable error) {
self->didGainUN = granted;
if(granted) {
UNNotificationAction *skipAction = [UNNotificationAction
actionWithIdentifier:@"skip"
title:@"Skip"
options:UNNotificationActionOptionNone];
UNNotificationCategory *playCategory = [UNNotificationCategory
categoryWithIdentifier:@"play"
actions:@[skipAction]
intentIdentifiers:@[]
options:UNNotificationCategoryOptionNone];
[center setNotificationCategories:
[NSSet setWithObject:playCategory]];
}
}];
[center setDelegate:self];
}
queue = [[NSOperationQueue alloc] init];
[queue setMaxConcurrentOperationCount:1];
[[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
entry = nil;
}
return self;
}
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:
(void (^)(UNNotificationPresentationOptions options))completionHandler
API_AVAILABLE(macos(10.14)) {
UNNotificationPresentationOptions presentationOptions = UNNotificationPresentationOptionAlert;
completionHandler(presentationOptions);
}
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler API_AVAILABLE(macos(10.14)) {
if([[response actionIdentifier] isEqualToString:@"skip"]) {
[playbackController next:self];
}
}
#if 0
- (NSDictionary *)fillNotificationDictionary:(PlaylistEntry *)pe status:(TrackStatus)status {
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
if(pe == nil || pe.deLeted || pe.url == nil) return dict;
[dict setObject:[pe.url absoluteString] forKey:TrackPath];
if(pe.title) [dict setObject:pe.title forKey:TrackTitle];
if(pe.artist) [dict setObject:pe.artist forKey:TrackArtist];
if(pe.album) [dict setObject:pe.album forKey:TrackAlbum];
if(pe.genre) [dict setObject:pe.genre forKey:TrackGenre];
if(pe.track)
[dict setObject:pe.trackText forKey:TrackNumber];
if(pe.length)
[dict setObject:@((NSInteger)([pe.length doubleValue] * 1000.0))
forKey:TrackLength];
NSString *state = nil;
switch(status) {
case TrackPlaying:
state = @"Playing";
break;
case TrackPaused:
state = @"Paused";
break;
case TrackStopped:
state = @"Stopped";
break;
default:
break;
}
[dict setObject:state forKey:TrackState];
return dict;
}
#endif
- (void)performPlaybackDidBeginActions:(PlaylistEntry *)pe {
if(NO == [pe error]) {
entry = pe;
#if 0
[[NSDistributedNotificationCenter defaultCenter]
postNotificationName:TrackNotification
object:nil
userInfo:[self fillNotificationDictionary:pe status:TrackPlaying]
deliverImmediately:YES];
#endif
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if([defaults boolForKey:@"notifications.enable"]) {
if(@available(macOS 10.14, *)) {
if(didGainUN) {
UNUserNotificationCenter *center =
[UNUserNotificationCenter currentNotificationCenter];
UNMutableNotificationContent *content =
[[UNMutableNotificationContent alloc] init];
content.title = @"Now Playing";
NSString *subtitle;
NSString *artist = (pe.artist && [pe.artist length]) ? pe.artist : nil;
NSString *album = (pe.album && [pe.album length]) ? pe.album : nil;
if(artist && album) {
subtitle = [NSString stringWithFormat:@"%@ - %@", artist, album];
} else if(artist) {
subtitle = artist;
} else if(album) {
subtitle = album;
} else {
subtitle = @"";
}
NSString *body = [NSString stringWithFormat:@"%@\n%@", [pe title], subtitle];
content.body = body;
content.sound = nil;
content.categoryIdentifier = @"play";
if([defaults boolForKey:@"notifications.show-album-art"] &&
[pe albumArt]) {
NSError *error = nil;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *tmpSubFolderURL = [[NSURL fileURLWithPath:NSTemporaryDirectory()]
URLByAppendingPathComponent:@"cog-artworks-cache"
isDirectory:true];
if([fileManager createDirectoryAtPath:[tmpSubFolderURL path]
withIntermediateDirectories:true
attributes:nil
error:&error]) {
NSString *tmpFileName =
[[NSProcessInfo.processInfo globallyUniqueString]
stringByAppendingString:@".jpg"];
NSURL *fileURL =
[tmpSubFolderURL URLByAppendingPathComponent:tmpFileName];
NSImage *image = [pe albumArt];
CGImageRef cgRef = [image CGImageForProposedRect:NULL
context:nil
hints:nil];
if(cgRef) {
NSBitmapImageRep *newRep =
[[NSBitmapImageRep alloc] initWithCGImage:cgRef];
NSData *jpgData = [newRep
representationUsingType:NSBitmapImageFileTypeJPEG
properties:@{ NSImageCompressionFactor: @0.5f }];
[jpgData writeToURL:fileURL atomically:YES];
UNNotificationAttachment *icon =
[UNNotificationAttachment attachmentWithIdentifier:@"art"
URL:fileURL
options:nil
error:&error];
if(error) {
// We have size limit of 10MB per image attachment.
NSLog(@"%@", error.localizedDescription);
} else {
content.attachments = @[icon];
}
}
}
}
UNNotificationRequest *request =
[UNNotificationRequest requestWithIdentifier:@"PlayTrack"
content:content
trigger:nil];
[center addNotificationRequest:request
withCompletionHandler:^(NSError *_Nullable error) {
NSLog(@"%@", error.localizedDescription);
}];
}
} else {
NSUserNotification *notif = [[NSUserNotification alloc] init];
notif.title = [pe title];
NSString *subtitle;
NSString *artist = (pe.artist && [pe.artist length]) ? pe.artist : nil;
NSString *album = (pe.album && [pe.album length]) ? pe.album : nil;
if(artist && album) {
subtitle = [NSString stringWithFormat:@"%@ - %@", artist, album];
} else if(artist) {
subtitle = artist;
} else if(album) {
subtitle = album;
} else {
subtitle = @"";
}
if([defaults boolForKey:@"notifications.itunes-style"]) {
notif.subtitle = subtitle;
[notif setValue:@YES forKey:@"_showsButtons"];
} else {
notif.informativeText = subtitle;
}
if([notif respondsToSelector:@selector(setContentImage:)]) {
if([defaults boolForKey:@"notifications.show-album-art"] &&
[pe albumArtInternal]) {
NSImage *image = [pe albumArt];
if([defaults boolForKey:@"notifications.itunes-style"]) {
[notif setValue:image forKey:@"_identityImage"];
} else {
notif.contentImage = image;
}
}
}
notif.actionButtonTitle = NSLocalizedString(@"SkipAction", @"");
[[NSUserNotificationCenter defaultUserNotificationCenter]
scheduleNotification:notif];
}
}
}
}
- (void)performPlaybackDidPauseActions {
#if 0
[[NSDistributedNotificationCenter defaultCenter]
postNotificationName:TrackNotification
object:nil
userInfo:[self fillNotificationDictionary:entry status:TrackPaused]
deliverImmediately:YES];
#endif
}
- (void)performPlaybackDidResumeActions {
#if 0
[[NSDistributedNotificationCenter defaultCenter]
postNotificationName:TrackNotification
object:nil
userInfo:[self fillNotificationDictionary:entry status:TrackPlaying]
deliverImmediately:YES];
#endif
}
- (void)performPlaybackDidStopActions {
#if 0
[[NSDistributedNotificationCenter defaultCenter]
postNotificationName:TrackNotification
object:nil
userInfo:[self fillNotificationDictionary:entry status:TrackStopped]
deliverImmediately:YES];
#endif
entry = nil;
}
- (void)awakeFromNib {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(playbackDidBegin:)
name:CogPlaybackDidBeginNotificiation
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(playbackDidPause:)
name:CogPlaybackDidPauseNotificiation
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(playbackDidResume:)
name:CogPlaybackDidResumeNotificiation
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(playbackDidStop:)
name:CogPlaybackDidStopNotificiation
object:nil];
}
- (void)playbackDidBegin:(NSNotification *)notification {
NSOperation *op = [NSBlockOperation blockOperationWithBlock:^{
[self performPlaybackDidBeginActions:(PlaylistEntry *)[notification object]];
}];
[queue addOperation:op];
}
- (void)playbackDidPause:(NSNotification *)notification {
NSOperation *op = [NSBlockOperation blockOperationWithBlock:^{
[self performPlaybackDidPauseActions];
}];
[queue addOperation:op];
}
- (void)playbackDidResume:(NSNotification *)notification {
NSOperation *op = [NSBlockOperation blockOperationWithBlock:^{
[self performPlaybackDidResumeActions];
}];
[queue addOperation:op];
}
- (void)playbackDidStop:(NSNotification *)notification {
NSOperation *op = [NSBlockOperation blockOperationWithBlock:^{
[self performPlaybackDidStopActions];
}];
[queue addOperation:op];
}
- (void)userNotificationCenter:(NSUserNotificationCenter *)center
didActivateNotification:(NSUserNotification *)notification {
switch(notification.activationType) {
case NSUserNotificationActivationTypeActionButtonClicked:
[playbackController next:self];
break;
case NSUserNotificationActivationTypeContentsClicked: {
NSWindow *window = [[NSUserDefaults standardUserDefaults] boolForKey:@"miniMode"] ? miniWindow : mainWindow;
[NSApp activateIgnoringOtherApps:YES];
[window makeKeyAndOrderFront:self];
}; break;
default:
break;
}
}
@end

View file

@ -0,0 +1,19 @@
//
// ScriptAdditions.h
// Cog
//
// Created by Christopher Snowhill on 2/21/22.
//
#ifndef ScriptAdditions_h
#define ScriptAdditions_h
@interface NSApplication (APLApplicationExtensions)
- (id)playbackStart:(NSScriptCommand *)command;
- (id)playbackPause:(NSScriptCommand *)command;
- (id)playbackStop:(NSScriptCommand *)command;
- (id)playbackPrevious:(NSScriptCommand *)command;
- (id)playbackNext:(NSScriptCommand *)command;
@end
#endif /* ScriptAdditions_h */

View file

@ -0,0 +1,33 @@
//
// ScriptAdditions.m
// Cog
//
// Created by Christopher Snowhill on 2/21/22.
//
#import <Cocoa/Cocoa.h>
#import "AppController.h"
@implementation NSApplication (APLApplicationExtensions)
- (id)playbackStart:(NSScriptCommand *)command {
[(AppController *)[NSApp delegate] clickPlay];
return @(YES);
}
- (id)playbackPause:(NSScriptCommand *)command {
[(AppController *)[NSApp delegate] clickPause];
return @(YES);
}
- (id)playbackStop:(NSScriptCommand *)command {
[(AppController *)[NSApp delegate] clickStop];
return @(YES);
}
- (id)playbackPrevious:(NSScriptCommand *)command {
[(AppController *)[NSApp delegate] clickPrev];
return @(YES);
}
- (id)playbackNext:(NSScriptCommand *)command {
[(AppController *)[NSApp delegate] clickNext];
return @(YES);
}
@end

18
Audio/AudioContainer.h Normal file
View file

@ -0,0 +1,18 @@
//
// AudioContainer.h
// CogAudio
//
// Created by Zaphod Beeblebrox on 10/8/07.
// Copyright 2007 __MyCompanyName__. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import <CogAudio/Plugin.h>
@interface AudioContainer : NSObject {
}
+ (NSArray *)urlsForContainerURL:(NSURL *)url;
+ (NSArray *)dependencyUrlsForContainerURL:(NSURL *)url;
@end

27
Audio/AudioContainer.m Normal file
View file

@ -0,0 +1,27 @@
//
// AudioContainer.m
// CogAudio
//
// Created by Zaphod Beeblebrox on 10/8/07.
// Copyright 2007 __MyCompanyName__. All rights reserved.
//
#import "AudioContainer.h"
#import "PluginController.h"
@implementation AudioContainer
+ (NSArray *)urlsForContainerURL:(NSURL *)url {
@autoreleasepool {
return [[PluginController sharedPluginController] urlsForContainerURL:url];
}
}
+ (NSArray *)dependencyUrlsForContainerURL:(NSURL *)url {
@autoreleasepool {
return [[PluginController sharedPluginController] dependencyUrlsForContainerURL:url];
}
}
@end

View file

@ -8,11 +8,12 @@
#import <Cocoa/Cocoa.h>
#import "Plugin.h"
#import <CogAudio/Plugin.h>
@interface AudioDecoder : NSObject {
}
+ (id<CogDecoder>)audioDecoderForURL:(NSURL *)url;
+ (id<CogDecoder>)audioDecoderForSource:(id<CogSource>)source;
+ (id<CogDecoder>)audioDecoderForSource:(id<CogSource>)source skipCue:(BOOL)skip;
@end

View file

@ -12,15 +12,12 @@
@implementation AudioDecoder
+ (id<CogDecoder>) audioDecoderForURL:(NSURL *)url
{
NSString *ext = [[url path] pathExtension];
+ (id<CogDecoder>)audioDecoderForSource:(id<CogSource>)source {
return [[PluginController sharedPluginController] audioDecoderForSource:source skipCue:NO];
}
NSDictionary *decoders = [[PluginController sharedPluginController] decoders];
Class decoder = NSClassFromString([decoders objectForKey:[ext lowercaseString]]);
return [[[decoder alloc] init] autorelease];
+ (id<CogDecoder>)audioDecoderForSource:(id<CogSource>)source skipCue:(BOOL)skip {
return [[PluginController sharedPluginController] audioDecoderForSource:source skipCue:skip];
}
@end

View file

@ -8,11 +8,10 @@
#import <Cocoa/Cocoa.h>
@interface AudioMetadataReader : NSObject {
}
+ (NSDictionary *)metadataForURL:(NSURL *)url;
+ (NSDictionary *)metadataForURL:(NSURL *)url skipCue:(BOOL)skip;
@end

View file

@ -11,16 +11,16 @@
@implementation AudioMetadataReader
+ (NSDictionary *)metadataForURL:(NSURL *)url
{
NSString *ext = [[url path] pathExtension];
NSDictionary *metadataReaders = [[PluginController sharedPluginController] metadataReaders];
Class metadataReader = NSClassFromString([metadataReaders objectForKey:[ext lowercaseString]]);
return [[[[metadataReader alloc] init] autorelease] metadataForURL:url];
+ (NSDictionary *)metadataForURL:(NSURL *)url {
@autoreleasepool {
return [[PluginController sharedPluginController] metadataForURL:url skipCue:NO];
}
}
+ (NSDictionary *)metadataForURL:(NSURL *)url skipCue:(BOOL)skip {
@autoreleasepool {
return [[PluginController sharedPluginController] metadataForURL:url skipCue:skip];
}
}
@end

View file

@ -0,0 +1,16 @@
//
// AudioMetadataWriter.h
// CogAudio
//
// Created by Safari on 08/11/18.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface AudioMetadataWriter : NSObject {
}
+ (int)putMetadataInURL:(NSURL *)url;
@end

View file

@ -0,0 +1,16 @@
//
// AudioMetadataWriter.m
// CogAudio
//
// Created by Safari on 08/11/18.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "AudioMetadataWriter.h"
#import "PluginController.h"
@implementation AudioMetadataWriter
+ (int)putMetadataInURL:(NSURL *)url {
return [[PluginController sharedPluginController] putMetadataInURL:url];
}
@end

View file

@ -8,22 +8,50 @@
#import <Cocoa/Cocoa.h>
#import <CogAudio/CogSemaphore.h>
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AudioUnit/AudioUnit.h>
#import <CoreAudio/CoreAudio.h>
#import <CoreAudio/CoreAudioTypes.h>
#import <stdatomic.h>
@class BufferChain;
@class OutputNode;
@interface AudioPlayer : NSObject
{
@interface AudioPlayer : NSObject {
BufferChain *bufferChain;
OutputNode *output;
double volume;
double pitch;
double tempo;
NSMutableArray *chainQueue;
NSURL *nextStream;
id nextStreamUserInfo;
NSDictionary *nextStreamRGInfo;
id previousUserInfo; // Track currently last heard track for play counts
id delegate;
BOOL outputLaunched;
BOOL endOfInputReached;
BOOL startedPaused;
BOOL initialBufferFilled;
Semaphore *semaphore;
atomic_bool resettingNow;
atomic_int refCount;
int currentPlaybackStatus;
BOOL shouldContinue;
}
- (id)init;
@ -32,49 +60,84 @@
- (id)delegate;
- (void)play:(NSURL *)url;
- (void)play:(NSURL *)url withUserInfo:(id)userInfo;
- (void)play:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)rgi;
- (void)play:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)rgi startPaused:(BOOL)paused;
- (void)play:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)rgi startPaused:(BOOL)paused andSeekTo:(double)time;
- (void)playBG:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)rgi startPaused:(NSNumber *)paused andSeekTo:(NSNumber *)time;
- (void)stop;
- (void)pause;
- (void)resume;
- (void)seekToTime:(double)time;
- (void)seekToTimeBG:(NSNumber *)time;
- (void)setVolume:(double)v;
- (double)volume;
- (double)volumeUp:(double)amount;
- (double)volumeDown:(double)amount;
- (double)amountPlayed;
- (double)amountPlayedInterval;
- (void)setNextStream:(NSURL *)url;
- (void)setNextStream:(NSURL *)url withUserInfo:(id)userInfo;
- (void)setNextStream:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)rgi;
- (void)resetNextStreams;
- (void)restartPlaybackAtCurrentPosition;
- (void)pushInfo:(NSDictionary *)info toTrack:(id)userInfo;
+ (NSArray *)fileTypes;
+ (NSArray *)schemes;
+ (NSArray *)containerTypes;
@end
@interface AudioPlayer (Private) //Dont use this stuff!
@interface AudioPlayer (Private) // Dont use this stuff!
- (OutputNode *) output;
- (BufferChain *) bufferChain;
- (OutputNode *)output;
- (BufferChain *)bufferChain;
- (id)initWithDelegate:(id)d;
- (void)setPlaybackStatus:(int)status waitUntilDone:(BOOL)wait;
- (void)setPlaybackStatus:(int)s;
- (void)requestNextStream:(id)userInfo;
- (void)requestNextStreamMainThread:(id)userInfo;
- (void)notifyStreamChanged:(id)userInfo;
- (void)notifyStreamChangedMainThread:(id)userInfo;
- (void)endOfInputReached:(BufferChain *)sender;
- (void)beginEqualizer:(AudioUnit)eq;
- (void)refreshEqualizer:(AudioUnit)eq;
- (void)endEqualizer:(AudioUnit)eq;
- (BOOL)endOfInputReached:(BufferChain *)sender;
- (void)setShouldContinue:(BOOL)s;
- (BufferChain *)bufferChain;
//- (BufferChain *)bufferChain;
- (void)launchOutputThread;
- (BOOL)selectNextBuffer;
- (void)endOfInputPlayed;
- (void)reportPlayCount;
- (void)sendDelegateMethod:(SEL)selector withVoid:(void *)obj waitUntilDone:(BOOL)wait;
- (void)sendDelegateMethod:(SEL)selector withObject:(id)obj waitUntilDone:(BOOL)wait;
- (void)sendDelegateMethod:(SEL)selector withObject:(id)obj withObject:(id)obj2 waitUntilDone:(BOOL)wait;
- (BOOL)chainQueueHasTracks;
@end
@protocol AudioPlayerDelegate
- (void)audioPlayer:(AudioPlayer *)player requestNextStream:(id)userInfo; //You must use setNextStream in this method
- (void)audioPlayer:(AudioPlayer *)player streamChanged:(id)userInfo;
- (void)audioPlayer:(AudioPlayer *)player changedStatus:(id)status;
- (void)audioPlayer:(AudioPlayer *)player willEndStream:(id)userInfo; // You must use setNextStream in this method
- (void)audioPlayer:(AudioPlayer *)player didBeginStream:(id)userInfo;
- (void)audioPlayer:(AudioPlayer *)player didChangeStatus:(id)status userInfo:(id)userInfo;
- (void)audioPlayer:(AudioPlayer *)player didStopNaturally:(id)userInfo;
- (void)audioPlayer:(AudioPlayer *)player displayEqualizer:(AudioUnit)eq;
- (void)audioPlayer:(AudioPlayer *)player refreshEqualizer:(AudioUnit)eq;
- (void)audioPlayer:(AudioPlayer *)player removeEqualizer:(AudioUnit)eq;
- (void)audioPlayer:(AudioPlayer *)player sustainHDCD:(id)userInfo;
- (void)audioPlayer:(AudioPlayer *)player restartPlaybackAtCurrentPosition:(id)userInfo;
- (void)audioPlayer:(AudioPlayer *)player pushInfo:(NSDictionary *)info toTrack:(id)userInfo;
- (void)audioPlayer:(AudioPlayer *)player reportPlayCountForTrack:(id)userInfo;
- (void)audioPlayer:(AudioPlayer *)player updatePosition:(id)userInfo;
- (void)audioPlayer:(AudioPlayer *)player setError:(NSNumber *)status toTrack:(id)userInfo;
@end

View file

@ -1,4 +1,4 @@
//
// AudioController.m
// Cog
//
@ -8,30 +8,39 @@
#import "AudioPlayer.h"
#import "BufferChain.h"
#import "Helper.h"
#import "OutputNode.h"
#import "Status.h"
#import "PluginController.h"
#import "Status.h"
#import "Logging.h"
@implementation AudioPlayer
- (id)init
{
- (id)init {
self = [super init];
if (self)
{
if(self) {
output = NULL;
bufferChain = NULL;
bufferChain = nil;
outputLaunched = NO;
endOfInputReached = NO;
// Safety
pitch = 1.0;
tempo = 1.0;
chainQueue = [[NSMutableArray alloc] init];
semaphore = [[Semaphore alloc] init];
atomic_init(&resettingNow, false);
atomic_init(&refCount, 0);
}
return self;
}
- (void)setDelegate:(id)d
{
- (void)setDelegate:(id)d {
delegate = d;
}
@ -39,247 +48,598 @@
return delegate;
}
- (void)play:(NSURL *)url
{
[self play:url withUserInfo:nil];
- (void)play:(NSURL *)url {
[self play:url withUserInfo:nil withRGInfo:nil startPaused:NO andSeekTo:0.0];
}
- (void)play:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)rgi {
[self play:url withUserInfo:userInfo withRGInfo:rgi startPaused:NO andSeekTo:0.0];
}
- (void)play:(NSURL *)url withUserInfo:(id)userInfo
{
if (output)
{
[output release];
- (void)play:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)rgi startPaused:(BOOL)paused {
[self play:url withUserInfo:userInfo withRGInfo:rgi startPaused:paused andSeekTo:0.0];
}
- (void)playBG:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)rgi startPaused:(NSNumber *)paused andSeekTo:(NSNumber *)time {
@synchronized (self) {
[self play:url withUserInfo:userInfo withRGInfo:rgi startPaused:[paused boolValue] andSeekTo:[time doubleValue]];
}
output = [[OutputNode alloc] initWithController:self previous:nil];
[output setup];
}
NSEnumerator *enumerator = [chainQueue objectEnumerator];
id anObject;
while (anObject = [enumerator nextObject])
{
[anObject setShouldContinue:NO];
- (void)play:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)rgi startPaused:(BOOL)paused andSeekTo:(double)time {
[self play:url withUserInfo:userInfo withRGInfo:rgi startPaused:paused andSeekTo:time andResumeInterval:NO];
}
- (void)play:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)rgi startPaused:(BOOL)paused andSeekTo:(double)time andResumeInterval:(BOOL)resumeInterval {
ALog(@"Opening file for playback: %@ at seek offset %f%@", url, time, (paused) ? @", starting paused" : @"");
[self waitUntilCallbacksExit];
if(output) {
[output fadeOutBackground];
}
[chainQueue removeAllObjects];
if (bufferChain)
{
[bufferChain setShouldContinue:NO];
[bufferChain release];
if(!output) {
output = [[OutputNode alloc] initWithController:self previous:nil];
[output setupWithInterval:resumeInterval];
}
[output setVolume:volume];
@synchronized(chainQueue) {
for(id anObject in chainQueue) {
[anObject setShouldContinue:NO];
}
[chainQueue removeAllObjects];
endOfInputReached = NO;
if(bufferChain) {
[bufferChain setShouldContinue:NO];
bufferChain = nil;
}
}
bufferChain = [[BufferChain alloc] initWithController:self];
if(!resumeInterval) {
[self notifyStreamChanged:userInfo];
}
while (![bufferChain open:url withOutputFormat:[output format]])
{
[bufferChain release];
while(![bufferChain open:url withOutputFormat:[output format] withUserInfo:userInfo withRGInfo:rgi]) {
bufferChain = nil;
[self requestNextStream: userInfo];
[self requestNextStream:userInfo];
if([nextStream isEqualTo:url]) {
return;
}
url = nextStream;
if (url == nil)
{
if(url == nil) {
return;
}
userInfo = nextStreamUserInfo;
rgi = nextStreamRGInfo;
[self notifyStreamChanged:userInfo];
bufferChain = [[BufferChain alloc] initWithController:self];
}
[bufferChain setUserInfo:userInfo];
if(time > 0.0) {
[output seek:time];
[bufferChain seek:time];
}
[self setShouldContinue:YES];
outputLaunched = NO;
if(!resumeInterval) {
outputLaunched = NO;
}
startedPaused = paused;
initialBufferFilled = NO;
previousUserInfo = userInfo;
[bufferChain launchThreads];
if(paused) {
[self setPlaybackStatus:CogStatusPaused waitUntilDone:YES];
if(time > 0.0) {
[self updatePosition:userInfo];
}
} else if(resumeInterval) {
[output fadeIn];
}
}
- (void)stop
{
//Set shouldoContinue to NO on allll things
- (void)stop {
// Set shouldoContinue to NO on all things
[self setShouldContinue:NO];
[self setPlaybackStatus:kCogStatusStopped];
[self setPlaybackStatus:CogStatusStopped waitUntilDone:YES];
@synchronized(chainQueue) {
for(id anObject in chainQueue) {
[anObject setShouldContinue:NO];
}
[chainQueue removeAllObjects];
endOfInputReached = NO;
if(bufferChain) {
bufferChain = nil;
}
}
if(output) {
[output setShouldContinue:NO];
[output close];
}
output = nil;
}
- (void)pause
{
[output pause];
- (void)pause {
[output fadeOut];
[self setPlaybackStatus:kCogStatusPaused];
[self setPlaybackStatus:CogStatusPaused waitUntilDone:YES];
}
- (void)resume
{
- (void)resume {
if(startedPaused) {
startedPaused = NO;
if(initialBufferFilled)
[self launchOutputThread];
}
[output fadeIn];
[output resume];
[self setPlaybackStatus:kCogStatusPlaying];
[self setPlaybackStatus:CogStatusPlaying waitUntilDone:YES];
}
- (void)seekToTime:(double)time
{
//Need to reset everything's buffers, and then seek?
/*HACK TO TEST HOW WELL THIS WOULD WORK*/
[output seek:time];
[bufferChain seek:time];
/*END HACK*/
- (void)seekToTimeBG:(NSNumber *)time {
[self seekToTime:[time doubleValue]];
}
- (void)setVolume:(double)v
{
- (void)seekToTime:(double)time {
CogStatus status = (CogStatus)currentPlaybackStatus;
NSURL *url;
id userInfo;
NSDictionary *rgi;
@synchronized(chainQueue) {
url = [bufferChain streamURL];
userInfo = [bufferChain userInfo];
rgi = [bufferChain rgInfo];
}
[self play:url withUserInfo:userInfo withRGInfo:rgi startPaused:(status == CogStatusPaused) andSeekTo:time andResumeInterval:YES];
}
- (void)setVolume:(double)v {
volume = v;
[output setVolume:v];
}
- (void)setNextStream:(NSURL *)url
{
[self setNextStream:url withUserInfo:nil];
- (double)volume {
return volume;
}
- (void)setNextStream:(NSURL *)url withUserInfo:(id)userInfo
{
[url retain];
[nextStream release];
// This is called by the delegate DURING a requestNextStream request.
- (void)setNextStream:(NSURL *)url {
[self setNextStream:url withUserInfo:nil withRGInfo:nil];
}
- (void)setNextStream:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)rgi {
nextStream = url;
[userInfo retain];
[nextStreamUserInfo release];
nextStreamUserInfo = userInfo;
nextStreamRGInfo = rgi;
}
// Called when the playlist changed before we actually started playing a requested stream. We will re-request.
- (void)resetNextStreams {
[self waitUntilCallbacksExit];
- (void)setShouldContinue:(BOOL)s
{
[bufferChain setShouldContinue:s];
[output setShouldContinue:s];
@synchronized(chainQueue) {
for(id anObject in chainQueue) {
[anObject setShouldContinue:NO];
}
[chainQueue removeAllObjects];
if(endOfInputReached) {
[self endOfInputReached:bufferChain];
}
}
}
- (double)amountPlayed
{
- (void)restartPlaybackAtCurrentPosition {
[self sendDelegateMethod:@selector(audioPlayer:restartPlaybackAtCurrentPosition:) withObject:previousUserInfo waitUntilDone:NO];
}
- (void)updatePosition:(id)userInfo {
[self sendDelegateMethod:@selector(audioPlayer:updatePosition:) withObject:userInfo waitUntilDone:NO];
}
- (void)pushInfo:(NSDictionary *)info toTrack:(id)userInfo {
[self sendDelegateMethod:@selector(audioPlayer:pushInfo:toTrack:) withObject:info withObject:userInfo waitUntilDone:NO];
}
- (void)reportPlayCountForTrack:(id)userInfo {
[self sendDelegateMethod:@selector(audioPlayer:reportPlayCountForTrack:) withObject:userInfo waitUntilDone:NO];
}
- (void)setShouldContinue:(BOOL)s {
shouldContinue = s;
if(bufferChain)
[bufferChain setShouldContinue:s];
if(output)
[output setShouldContinue:s];
}
- (double)amountPlayed {
return [output amountPlayed];
}
- (void)launchOutputThread
{
[self setPlaybackStatus:kCogStatusPlaying];
if (outputLaunched == NO) {
- (double)amountPlayedInterval {
return [output amountPlayedInterval];
}
- (void)launchOutputThread {
initialBufferFilled = YES;
if(outputLaunched == NO && startedPaused == NO) {
[self setPlaybackStatus:CogStatusPlaying];
[output launchThread];
outputLaunched = YES;
}
else {
[self setShouldContinue:YES];
[output resume];
}
}
- (void)requestNextStream:(id)userInfo
{
[self sendDelegateMethod:@selector(audioPlayer:requestNextStream:) withObject:userInfo waitUntilDone:YES];
- (void)requestNextStream:(id)userInfo {
[self sendDelegateMethod:@selector(audioPlayer:willEndStream:) withObject:userInfo waitUntilDone:YES];
}
- (void)notifyStreamChanged:(id)userInfo
{
[self sendDelegateMethod:@selector(audioPlayer:streamChanged:) withObject:userInfo waitUntilDone:NO];
- (void)notifyStreamChanged:(id)userInfo {
[self sendDelegateMethod:@selector(audioPlayer:didBeginStream:) withObject:userInfo waitUntilDone:YES];
}
- (void)notifyPlaybackStopped:(id)userInfo {
[self sendDelegateMethod:@selector(audioPlayer:didStopNaturally:) withObject:userInfo waitUntilDone:NO];
}
- (void)beginEqualizer:(AudioUnit)eq {
[self sendDelegateMethod:@selector(audioPlayer:displayEqualizer:) withVoid:eq waitUntilDone:YES];
}
- (void)endOfInputReached:(BufferChain *)sender //Sender is a BufferChain
{
BufferChain *newChain = nil;
- (void)refreshEqualizer:(AudioUnit)eq {
[self sendDelegateMethod:@selector(audioPlayer:refreshEqualizer:) withVoid:eq waitUntilDone:YES];
}
nextStreamUserInfo = [sender userInfo];
[nextStreamUserInfo retain]; //Retained because when setNextStream is called, it will be released!!!
do {
[newChain release];
[self requestNextStream: nextStreamUserInfo];
if (nextStream == nil)
{
return;
}
newChain = [[BufferChain alloc] initWithController:self];
} while (![newChain open:nextStream withOutputFormat:[output format]]);
[newChain setUserInfo: nextStreamUserInfo];
- (void)endEqualizer:(AudioUnit)eq {
[self sendDelegateMethod:@selector(audioPlayer:removeEqualizer:) withVoid:eq waitUntilDone:YES];
}
- (void)addChainToQueue:(BufferChain *)newChain {
[newChain setShouldContinue:YES];
[newChain launchThreads];
[chainQueue insertObject:newChain atIndex:[chainQueue count]];
[newChain release];
}
- (void)endOfInputPlayed
- (BOOL)endOfInputReached:(BufferChain *)sender // Sender is a BufferChain
{
if ([chainQueue count] <= 0)
{
//End of playlist
[self stop];
previousUserInfo = [sender userInfo];
return;
BufferChain *newChain = nil;
if(atomic_load_explicit(&resettingNow, memory_order_relaxed))
return YES;
atomic_fetch_add(&refCount, 1);
@synchronized(chainQueue) {
// No point in constructing new chain for the next playlist entry
// if there's already one at the head of chainQueue... r-r-right?
for(BufferChain *chain in chainQueue) {
if([chain isRunning]) {
if(output)
[output setShouldPlayOutBuffer:YES];
atomic_fetch_sub(&refCount, 1);
return YES;
}
}
// We don't want to do this, it may happen with a lot of short files
// if ([chainQueue count] >= 5)
//{
// return YES;
//}
}
[bufferChain release];
bufferChain = [chainQueue objectAtIndex:0];
[bufferChain retain];
double duration = 0.0;
[chainQueue removeObjectAtIndex:0];
@synchronized(chainQueue) {
for(BufferChain *chain in chainQueue) {
duration += [chain secondsBuffered];
}
}
while(duration >= 30.0 && shouldContinue) {
[semaphore wait];
if(atomic_load_explicit(&resettingNow, memory_order_relaxed)) {
if(output)
[output setShouldPlayOutBuffer:YES];
atomic_fetch_sub(&refCount, 1);
return YES;
}
@synchronized(chainQueue) {
duration = 0.0;
for(BufferChain *chain in chainQueue) {
duration += [chain secondsBuffered];
}
}
}
nextStreamUserInfo = [sender userInfo];
nextStreamRGInfo = [sender rgInfo];
// This call can sometimes lead to invoking a chainQueue block on another thread
[self requestNextStream:nextStreamUserInfo];
if(!nextStream) {
if(output)
[output setShouldPlayOutBuffer:YES];
atomic_fetch_sub(&refCount, 1);
return YES;
}
BufferChain *lastChain;
@synchronized(chainQueue) {
newChain = [[BufferChain alloc] initWithController:self];
endOfInputReached = YES;
lastChain = [chainQueue lastObject];
if(lastChain == nil) {
lastChain = bufferChain;
}
}
BOOL pathsEqual = NO;
if([nextStream isFileURL] && [[lastChain streamURL] isFileURL]) {
NSString *unixPathNext = [nextStream path];
NSString *unixPathPrev = [[lastChain streamURL] path];
if([unixPathNext isEqualToString:unixPathPrev])
pathsEqual = YES;
} else if(![nextStream isFileURL] && ![[lastChain streamURL] isFileURL]) {
@try {
NSURL *lastURL = [lastChain streamURL];
NSString *nextScheme = [nextStream scheme];
NSString *lastScheme = [lastURL scheme];
NSString *nextHost = [nextStream host];
NSString *lastHost = [lastURL host];
NSString *nextPath = [nextStream path];
NSString *lastPath = [lastURL path];
if(nextScheme && lastScheme && [nextScheme isEqualToString:lastScheme]) {
if((!nextHost && !lastHost) ||
(nextHost && lastHost && [nextHost isEqualToString:lastHost])) {
if(nextPath && lastPath && [nextPath isEqualToString:lastPath]) {
pathsEqual = YES;
}
}
}
}
@catch(NSException *e) {
DLog(@"Exception thrown checking file match: %@", e);
}
}
if(pathsEqual) {
if([lastChain setTrack:nextStream] && [newChain openWithInput:[lastChain inputNode] withOutputFormat:[output format] withUserInfo:nextStreamUserInfo withRGInfo:nextStreamRGInfo]) {
[newChain setStreamURL:nextStream];
@synchronized(chainQueue) {
[self addChainToQueue:newChain];
}
DLog(@"TRACK SET!!! %@", newChain);
// Keep on-playin
newChain = nil;
atomic_fetch_sub(&refCount, 1);
return NO;
}
}
lastChain = nil;
NSURL *url = nextStream;
while(shouldContinue && ![newChain open:url withOutputFormat:[output format] withUserInfo:nextStreamUserInfo withRGInfo:nextStreamRGInfo]) {
if(nextStream == nil) {
newChain = nil;
if(output)
[output setShouldPlayOutBuffer:YES];
atomic_fetch_sub(&refCount, 1);
return YES;
}
newChain = nil;
[self requestNextStream:nextStreamUserInfo];
if([nextStream isEqualTo:url]) {
newChain = nil;
if(output)
[output setShouldPlayOutBuffer:YES];
atomic_fetch_sub(&refCount, 1);
return YES;
}
url = nextStream;
newChain = [[BufferChain alloc] initWithController:self];
}
@synchronized(chainQueue) {
[self addChainToQueue:newChain];
}
newChain = nil;
// I'm stupid and can't hold too much stuff in my head all at once, so writing it here.
//
// Once we get here:
// - buffer chain for previous stream finished reading
// - there are (probably) some bytes of the previous stream in the output buffer which haven't been played
// (by output node) yet
// - self.bufferChain == previous playlist entry's buffer chain
// - self.nextStream == next playlist entry's URL
// - self.nextStreamUserInfo == next playlist entry
// - head of chainQueue is the buffer chain for the next entry (which has launched its threads already)
if(output)
[output setShouldPlayOutBuffer:YES];
atomic_fetch_sub(&refCount, 1);
return YES;
}
- (void)reportPlayCount {
[self reportPlayCountForTrack:previousUserInfo];
}
- (BOOL)selectNextBuffer {
BOOL signalStopped = NO;
do {
@synchronized(chainQueue) {
endOfInputReached = NO;
if([chainQueue count] <= 0) {
// End of playlist
signalStopped = YES;
break;
}
[bufferChain setShouldContinue:NO];
bufferChain = nil;
bufferChain = [chainQueue objectAtIndex:0];
[chainQueue removeObjectAtIndex:0];
DLog(@"New!!! %@ %@", bufferChain, [[bufferChain inputNode] decoder]);
[semaphore signal];
}
} while(0);
if(signalStopped) {
double latency = 0;
if(output) latency = [output latency];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, latency * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self stop];
self->bufferChain = nil;
[self notifyPlaybackStopped:nil];
});
return YES;
}
[self notifyStreamChanged:[bufferChain userInfo]];
[output setEndOfStream:NO];
return NO;
}
- (void)sendDelegateMethod:(SEL)selector withObject:(id)obj waitUntilDone:(BOOL)wait
{
- (void)endOfInputPlayed {
// Once we get here:
// - the buffer chain for the next playlist entry (started in endOfInputReached) have been working for some time
// already, so that there is some decoded and converted data to play
// - the buffer chain for the next entry is the first item in chainQueue
previousUserInfo = [bufferChain userInfo];
[self notifyStreamChanged:previousUserInfo];
}
- (BOOL)chainQueueHasTracks {
@synchronized(chainQueue) {
return [chainQueue count] > 0;
}
return NO;
}
- (void)sendDelegateMethod:(SEL)selector withVoid:(void *)obj waitUntilDone:(BOOL)wait {
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[delegate methodSignatureForSelector:selector]];
[invocation setTarget:delegate];
[invocation setSelector:selector];
[invocation setArgument:&self atIndex:2]; //Indexes start at 2, the first being self, the second being command.
[invocation setArgument:&obj atIndex:3];
[invocation setArgument:(void *)&self atIndex:2];
[invocation setArgument:&obj atIndex:3];
[invocation retainArguments];
[self performSelectorOnMainThread:@selector(sendDelegateMethodMainThread:) withObject:invocation waitUntilDone:wait];
[invocation performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:wait];
}
- (void)sendDelegateMethod:(SEL)selector withObject:(id)obj waitUntilDone:(BOOL)wait {
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[delegate methodSignatureForSelector:selector]];
[invocation setTarget:delegate];
[invocation setSelector:selector];
[invocation setArgument:(void *)&self atIndex:2];
[invocation setArgument:&obj atIndex:3];
[invocation retainArguments];
- (void)sendDelegateMethodMainThread:(id)invocation
{
[invocation invokeWithTarget:delegate];
[invocation performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:wait];
}
- (void)setPlaybackStatus:(int)status
{
[self sendDelegateMethod:@selector(audioPlayer:statusChanged:) withObject:[NSNumber numberWithInt:status] waitUntilDone:NO];
- (void)sendDelegateMethod:(SEL)selector withObject:(id)obj withObject:(id)obj2 waitUntilDone:(BOOL)wait {
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[delegate methodSignatureForSelector:selector]];
[invocation setTarget:delegate];
[invocation setSelector:selector];
[invocation setArgument:(void *)&self atIndex:2];
[invocation setArgument:&obj atIndex:3];
[invocation setArgument:&obj2 atIndex:4];
[invocation retainArguments];
[invocation performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:wait];
}
- (BufferChain *)bufferChain
{
- (void)setPlaybackStatus:(int)status waitUntilDone:(BOOL)wait {
currentPlaybackStatus = status;
[self sendDelegateMethod:@selector(audioPlayer:didChangeStatus:userInfo:) withObject:@(status) withObject:[bufferChain userInfo] waitUntilDone:wait];
}
- (void)sustainHDCD {
[self sendDelegateMethod:@selector(audioPlayer:sustainHDCD:) withObject:[bufferChain userInfo] waitUntilDone:NO];
}
- (void)setError:(BOOL)status {
[self sendDelegateMethod:@selector(audioPlayer:setError:toTrack:) withObject:@(status) withObject:[bufferChain userInfo] waitUntilDone:NO];
}
- (void)setPlaybackStatus:(int)status {
[self setPlaybackStatus:status waitUntilDone:NO];
}
- (BufferChain *)bufferChain {
return bufferChain;
}
- (OutputNode *) output
{
- (OutputNode *)output {
return output;
}
+ (NSArray *)fileTypes
{
+ (NSArray *)containerTypes {
return [[[PluginController sharedPluginController] containers] allKeys];
}
+ (NSArray *)fileTypes {
PluginController *pluginController = [PluginController sharedPluginController];
NSArray *decoderTypes = [[pluginController decoders] allKeys];
NSArray *containerTypes = [[pluginController containers] allKeys];
NSArray *decoderTypes = [[pluginController decodersByExtension] allKeys];
NSArray *metdataReaderTypes = [[pluginController metadataReaders] allKeys];
NSArray *propertiesReaderTypes = [[pluginController propertiesReaders] allKeys];
NSArray *propertiesReaderTypes = [[pluginController propertiesReadersByExtension] allKeys];
NSMutableSet *types = [NSMutableSet set];
[types addObjectsFromArray:containerTypes];
[types addObjectsFromArray:decoderTypes];
[types addObjectsFromArray:metdataReaderTypes];
[types addObjectsFromArray:propertiesReaderTypes];
@ -287,12 +647,57 @@
return [types allObjects];
}
+ (NSArray *)schemes
{
+ (NSArray *)schemes {
PluginController *pluginController = [PluginController sharedPluginController];
return [[pluginController sources] allKeys];
}
- (double)volumeUp:(double)amount {
BOOL volumeLimit = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] boolForKey:@"volumeLimit"];
const double MAX_VOLUME = (volumeLimit) ? 100.0 : 800.0;
double newVolume = linearToLogarithmic(logarithmicToLinear(volume + amount, MAX_VOLUME), MAX_VOLUME);
if(newVolume > MAX_VOLUME)
newVolume = MAX_VOLUME;
[self setVolume:newVolume];
// the playbackController needs to know the new volume, so it can update the
// volumeSlider accordingly.
return newVolume;
}
- (double)volumeDown:(double)amount {
BOOL volumeLimit = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] boolForKey:@"volumeLimit"];
const double MAX_VOLUME = (volumeLimit) ? 100.0 : 800.0;
double newVolume;
if(amount > volume)
newVolume = 0.0;
else
newVolume = linearToLogarithmic(logarithmicToLinear(volume - amount, MAX_VOLUME), MAX_VOLUME);
[self setVolume:newVolume];
return newVolume;
}
- (void)waitUntilCallbacksExit {
// This sucks! And since the thread that's inside the function can be calling
// event dispatches, we have to pump the message queue if we're on the main
// thread. Damn.
if(atomic_load_explicit(&refCount, memory_order_relaxed) != 0) {
BOOL mainThread = (dispatch_queue_get_label(dispatch_get_main_queue()) == dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
atomic_store(&resettingNow, true);
while(atomic_load_explicit(&refCount, memory_order_relaxed) != 0) {
[semaphore signal]; // Gotta poke this periodically
if(mainThread)
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.001]];
else
usleep(500);
}
atomic_store(&resettingNow, false);
}
}
@end

View file

@ -8,11 +8,10 @@
#import <Cocoa/Cocoa.h>
@interface AudioPropertiesReader : NSObject {
}
+ (NSDictionary *)propertiesForURL:(NSURL *)url;
+ (NSDictionary *)propertiesForURL:(NSURL *)url skipCue:(BOOL)skip;
@end

View file

@ -13,24 +13,16 @@
@implementation AudioPropertiesReader
+ (NSDictionary *)propertiesForURL:(NSURL *)url
{
NSString *ext = [[url path] pathExtension];
id<CogSource> source = [AudioSource audioSourceForURL:url];
if (![source open:url])
return nil;
NSDictionary *propertiesReaders = [[PluginController sharedPluginController] propertiesReaders];
Class propertiesReader = NSClassFromString([propertiesReaders objectForKey:[ext lowercaseString]]);
NSDictionary *properties = [propertiesReader propertiesForSource:source];
[source close];
return properties;
+ (NSDictionary *)propertiesForURL:(NSURL *)url {
@autoreleasepool {
return [[PluginController sharedPluginController] propertiesForURL:url skipCue:NO];
}
}
+ (NSDictionary *)propertiesForURL:(NSURL *)url skipCue:(BOOL)skip {
@autoreleasepool {
return [[PluginController sharedPluginController] propertiesForURL:url skipCue:skip];
}
}
@end

View file

@ -13,6 +13,6 @@
@interface AudioSource : NSObject {
}
+ audioSourceForURL:(NSURL *)url;
+ (id<CogSource>)audioSourceForURL:(NSURL *)url;
@end

View file

@ -8,18 +8,10 @@
#import "AudioSource.h"
@implementation AudioSource
+ audioSourceForURL:(NSURL *)url
{
NSString *scheme = [url scheme];
NSDictionary *sources = [[PluginController sharedPluginController] sources];
Class source = NSClassFromString([sources objectForKey:scheme]);
return [[[source alloc] init] autorelease];
+ (id<CogSource>)audioSourceForURL:(NSURL *)url {
return [[PluginController sharedPluginController] audioSourceForURL:url];
}
@end

112
Audio/Chain/AudioChunk.h Normal file
View file

@ -0,0 +1,112 @@
//
// AudioChunk.h
// CogAudio Framework
//
// Created by Christopher Snowhill on 2/5/22.
//
#ifndef AudioChunk_h
#define AudioChunk_h
#import <CoreAudio/CoreAudio.h>
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
enum {
AudioChannelFrontLeft = 1 << 0,
AudioChannelFrontRight = 1 << 1,
AudioChannelFrontCenter = 1 << 2,
AudioChannelLFE = 1 << 3,
AudioChannelBackLeft = 1 << 4,
AudioChannelBackRight = 1 << 5,
AudioChannelFrontCenterLeft = 1 << 6,
AudioChannelFrontCenterRight = 1 << 7,
AudioChannelBackCenter = 1 << 8,
AudioChannelSideLeft = 1 << 9,
AudioChannelSideRight = 1 << 10,
AudioChannelTopCenter = 1 << 11,
AudioChannelTopFrontLeft = 1 << 12,
AudioChannelTopFrontCenter = 1 << 13,
AudioChannelTopFrontRight = 1 << 14,
AudioChannelTopBackLeft = 1 << 15,
AudioChannelTopBackCenter = 1 << 16,
AudioChannelTopBackRight = 1 << 17,
AudioConfigMono = AudioChannelFrontCenter,
AudioConfigStereo = AudioChannelFrontLeft | AudioChannelFrontRight,
AudioConfig3Point0 = AudioChannelFrontLeft | AudioChannelFrontRight |
AudioChannelFrontCenter,
AudioConfig4Point0 = AudioChannelFrontLeft | AudioChannelFrontRight |
AudioChannelBackLeft | AudioChannelBackRight,
AudioConfig5Point0 = AudioChannelFrontLeft | AudioChannelFrontRight |
AudioChannelFrontCenter | AudioChannelBackLeft |
AudioChannelBackRight,
AudioConfig5Point1 = AudioChannelFrontLeft | AudioChannelFrontRight |
AudioChannelFrontCenter | AudioChannelLFE |
AudioChannelBackLeft | AudioChannelBackRight,
AudioConfig5Point1Side = AudioChannelFrontLeft | AudioChannelFrontRight |
AudioChannelFrontCenter | AudioChannelLFE |
AudioChannelSideLeft | AudioChannelSideRight,
AudioConfig6Point1 = AudioChannelFrontLeft | AudioChannelFrontRight |
AudioChannelFrontCenter | AudioChannelLFE |
AudioChannelBackCenter | AudioChannelSideLeft |
AudioChannelSideRight,
AudioConfig7Point1 = AudioChannelFrontLeft | AudioChannelFrontRight |
AudioChannelFrontCenter | AudioChannelLFE |
AudioChannelBackLeft | AudioChannelBackRight |
AudioChannelSideLeft | AudioChannelSideRight,
AudioChannelsBackLeftRight = AudioChannelBackLeft | AudioChannelBackRight,
AudioChannelsSideLeftRight = AudioChannelSideLeft | AudioChannelSideRight,
};
@interface AudioChunk : NSObject {
AudioStreamBasicDescription format;
NSMutableData *chunkData;
uint32_t channelConfig;
double streamTimestamp;
double streamTimeRatio;
BOOL formatAssigned;
BOOL lossless;
BOOL hdcd;
}
@property AudioStreamBasicDescription format;
@property uint32_t channelConfig;
@property double streamTimestamp;
@property double streamTimeRatio;
@property BOOL lossless;
+ (uint32_t)guessChannelConfig:(uint32_t)channelCount;
+ (uint32_t)channelIndexFromConfig:(uint32_t)channelConfig forFlag:(uint32_t)flag;
+ (uint32_t)extractChannelFlag:(uint32_t)index fromConfig:(uint32_t)channelConfig;
+ (uint32_t)countChannels:(uint32_t)channelConfig;
+ (uint32_t)findChannelIndex:(uint32_t)flag;
- (id)init;
- (id)initWithProperties:(NSDictionary *)properties;
- (void)assignSamples:(const void *_Nonnull)data frameCount:(size_t)count;
- (void)assignData:(NSData *)data;
- (NSData *)removeSamples:(size_t)frameCount;
- (BOOL)isEmpty;
- (size_t)frameCount;
- (void)setFrameCount:(size_t)count; // For truncation only
- (double)duration;
- (double)durationRatioed;
- (BOOL)isHDCD;
- (void)setHDCD;
- (AudioChunk *)copy;
@end
NS_ASSUME_NONNULL_END
#endif /* AudioChunk_h */

233
Audio/Chain/AudioChunk.m Normal file
View file

@ -0,0 +1,233 @@
//
// AudioChunk.m
// CogAudio Framework
//
// Created by Christopher Snowhill on 2/5/22.
//
#import "AudioChunk.h"
#import "CoreAudioUtils.h"
@implementation AudioChunk
- (id)init {
self = [super init];
if(self) {
chunkData = [[NSMutableData alloc] init];
formatAssigned = NO;
lossless = NO;
hdcd = NO;
streamTimestamp = 0.0;
streamTimeRatio = 1.0;
}
return self;
}
- (id)initWithProperties:(NSDictionary *)properties {
self = [super init];
if(self) {
chunkData = [[NSMutableData alloc] init];
[self setFormat:propertiesToASBD(properties)];
lossless = [[properties objectForKey:@"encoding"] isEqualToString:@"lossless"];
hdcd = NO;
streamTimestamp = 0.0;
streamTimeRatio = 1.0;
}
return self;
}
- (AudioChunk *)copy {
AudioChunk *outputChunk = [[AudioChunk alloc] init];
[outputChunk setFormat:format];
[outputChunk setChannelConfig:channelConfig];
if(hdcd) [outputChunk setHDCD];
[outputChunk setStreamTimestamp:streamTimestamp];
[outputChunk setStreamTimeRatio:streamTimeRatio];
[outputChunk assignData:chunkData];
return outputChunk;
}
static const uint32_t AudioChannelConfigTable[] = {
0,
AudioConfigMono,
AudioConfigStereo,
AudioConfig3Point0,
AudioConfig4Point0,
AudioConfig5Point0,
AudioConfig5Point1,
AudioConfig6Point1,
AudioConfig7Point1,
0,
AudioConfig7Point1 | AudioChannelFrontCenterLeft | AudioChannelFrontCenterRight
};
+ (uint32_t)guessChannelConfig:(uint32_t)channelCount {
if(channelCount == 0) return 0;
if(channelCount > 32) return 0;
int ret = 0;
if(channelCount < (sizeof(AudioChannelConfigTable) / sizeof(AudioChannelConfigTable[0])))
ret = AudioChannelConfigTable[channelCount];
if(!ret) {
ret = (1 << channelCount) - 1;
}
assert([AudioChunk countChannels:ret] == channelCount);
return ret;
}
+ (uint32_t)channelIndexFromConfig:(uint32_t)channelConfig forFlag:(uint32_t)flag {
uint32_t index = 0;
for(uint32_t walk = 0; walk < 32; ++walk) {
uint32_t query = 1 << walk;
if(flag & query) return index;
if(channelConfig & query) ++index;
}
return ~0;
}
+ (uint32_t)extractChannelFlag:(uint32_t)index fromConfig:(uint32_t)channelConfig {
uint32_t toskip = index;
uint32_t flag = 1;
while(flag) {
if(channelConfig & flag) {
if(toskip == 0) break;
toskip--;
}
flag <<= 1;
}
return flag;
}
+ (uint32_t)countChannels:(uint32_t)channelConfig {
return __builtin_popcount(channelConfig);
}
+ (uint32_t)findChannelIndex:(uint32_t)flag {
uint32_t rv = 0;
if((flag & 0xFFFF) == 0) {
rv += 16;
flag >>= 16;
}
if((flag & 0xFF) == 0) {
rv += 8;
flag >>= 8;
}
if((flag & 0xF) == 0) {
rv += 4;
flag >>= 4;
}
if((flag & 0x3) == 0) {
rv += 2;
flag >>= 2;
}
if((flag & 0x1) == 0) {
rv += 1;
flag >>= 1;
}
assert(flag & 1);
return rv;
}
@synthesize lossless;
@synthesize streamTimestamp;
@synthesize streamTimeRatio;
- (AudioStreamBasicDescription)format {
return format;
}
- (void)setFormat:(AudioStreamBasicDescription)informat {
formatAssigned = YES;
format = informat;
channelConfig = [AudioChunk guessChannelConfig:format.mChannelsPerFrame];
}
- (uint32_t)channelConfig {
return channelConfig;
}
- (void)setChannelConfig:(uint32_t)config {
if(formatAssigned) {
if(config == 0) {
config = [AudioChunk guessChannelConfig:format.mChannelsPerFrame];
}
}
channelConfig = config;
}
- (void)assignSamples:(const void *_Nonnull)data frameCount:(size_t)count {
if(formatAssigned) {
const size_t bytesPerPacket = format.mBytesPerPacket;
[chunkData appendBytes:data length:bytesPerPacket * count];
}
}
- (void)assignData:(NSData *)data {
[chunkData appendData:data];
}
- (NSData *)removeSamples:(size_t)frameCount {
if(formatAssigned) {
@autoreleasepool {
const double secondsDuration = (double)(frameCount) / format.mSampleRate;
const double DSDrate = (format.mBitsPerChannel == 1) ? 8.0 : 1.0;
const size_t bytesPerPacket = format.mBytesPerPacket;
const size_t byteCount = bytesPerPacket * frameCount;
NSData *ret = [chunkData subdataWithRange:NSMakeRange(0, byteCount)];
[chunkData replaceBytesInRange:NSMakeRange(0, byteCount) withBytes:NULL length:0];
streamTimestamp += secondsDuration * streamTimeRatio * DSDrate;
return ret;
}
}
return [NSData data];
}
- (BOOL)isEmpty {
return [chunkData length] == 0;
}
- (size_t)frameCount {
if(formatAssigned) {
const size_t bytesPerPacket = format.mBytesPerPacket;
return [chunkData length] / bytesPerPacket;
}
return 0;
}
- (void)setFrameCount:(size_t)count {
if(formatAssigned) {
count *= format.mBytesPerPacket;
size_t currentLength = [chunkData length];
if(count < currentLength) {
[chunkData replaceBytesInRange:NSMakeRange(count, currentLength - count) withBytes:NULL length:0];
}
}
}
- (double)duration {
if(formatAssigned && [chunkData length]) {
const size_t bytesPerPacket = format.mBytesPerPacket;
const double sampleRate = format.mSampleRate;
const double DSDrate = (format.mBitsPerChannel == 1) ? 8.0 : 1.0;
return ((double)([chunkData length] / bytesPerPacket) / sampleRate) * DSDrate;
}
return 0.0;
}
- (double)durationRatioed {
return [self duration] * streamTimeRatio;
}
- (BOOL)isHDCD {
return hdcd;
}
- (void)setHDCD {
hdcd = YES;
}
@end

View file

@ -8,41 +8,77 @@
#import <Cocoa/Cocoa.h>
#import "InputNode.h"
#import "AudioPlayer.h"
#import <CogAudio/AudioPlayer.h>
#import <CogAudio/ConverterNode.h>
#import <CogAudio/InputNode.h>
@interface BufferChain : NSObject {
InputNode *inputNode;
ConverterNode *converterNode;
NSURL *streamURL;
id userInfo;
NSDictionary *rgInfo;
id finalNode; //Final buffer in the chain.
id finalNode; // Final buffer in the chain.
id controller;
}
- (id)initWithController:(id)c;
- (void)buildChain;
- (BOOL)open:(NSURL *)url withOutputFormat:(AudioStreamBasicDescription)outputFormat;
- (BOOL)buildChain;
- (BOOL)open:(NSURL *)url withOutputFormat:(AudioStreamBasicDescription)outputFormat withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)rgi;
// Used when changing tracks to reuse the same decoder
- (BOOL)openWithInput:(InputNode *)i withOutputFormat:(AudioStreamBasicDescription)outputFormat withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)rgi;
// Used when resetting the decoder on seek
- (BOOL)openWithDecoder:(id<CogDecoder>)decoder
withOutputFormat:(AudioStreamBasicDescription)outputFormat
withUserInfo:(id)userInfo
withRGInfo:(NSDictionary *)rgi;
- (void)seek:(double)time;
- (void)launchThreads;
- (InputNode *)inputNode;
- (id)finalNode;
- (id)userInfo;
- (void)setUserInfo:(id)i;
- (NSDictionary *)rgInfo;
- (void)setRGInfo:(NSDictionary *)rgi;
- (NSURL *)streamURL;
- (void)setStreamURL:(NSURL *)url;
- (void)setShouldContinue:(BOOL)s;
- (void)initialBufferFilled;
- (void)initialBufferFilled:(id)sender;
- (void)endOfInputReached;
- (BOOL)endOfInputReached;
- (BOOL)setTrack:(NSURL *)track;
- (BOOL)isRunning;
- (id)controller;
- (ConverterNode *)converter;
- (AudioStreamBasicDescription)inputFormat;
- (uint32_t)inputConfig;
- (double)secondsBuffered;
- (void)sustainHDCD;
- (void)restartPlaybackAtCurrentPosition;
- (void)pushInfo:(NSDictionary *)info;
- (void)setError:(BOOL)status;
@end

View file

@ -7,119 +7,278 @@
//
#import "BufferChain.h"
#import "OutputNode.h"
#import "AudioSource.h"
#import "CoreAudioUtils.h"
#import "DSPDownmixNode.h"
#import "OutputNode.h"
#import "AudioPlayer.h"
#import "Logging.h"
@implementation BufferChain
- (id)initWithController:(id)c
{
- (id)initWithController:(id)c {
self = [super init];
if (self)
{
if(self) {
controller = c;
streamURL = nil;
userInfo = nil;
rgInfo = nil;
inputNode = nil;
converterNode = nil;
}
return self;
}
- (void)buildChain
{
[inputNode release];
- (BOOL)buildChain {
// Cut off output source
finalNode = nil;
// Tear them down in reverse
converterNode = nil;
inputNode = nil;
inputNode = [[InputNode alloc] initWithController:self previous:nil];
if(!inputNode) return NO;
converterNode = [[ConverterNode alloc] initWithController:self previous:inputNode];
if(!converterNode) return NO;
finalNode = inputNode;
finalNode = converterNode;
return YES;
}
- (BOOL)open:(NSURL *)url withOutputFormat:(AudioStreamBasicDescription)outputFormat
{
- (BOOL)open:(NSURL *)url withOutputFormat:(AudioStreamBasicDescription)outputFormat withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)rgi {
[self setStreamURL:url];
[self setUserInfo:userInfo];
[self buildChain];
id<CogSource> source = [AudioSource audioSourceForURL:url];
if (![source open:url])
{
NSLog(@"Couldn't open source...");
if (![self buildChain]) {
DLog(@"Couldn't build processing chain...");
return NO;
}
id<CogSource> source = [AudioSource audioSourceForURL:url];
DLog(@"Opening: %@", url);
if(!source || ![source open:url]) {
DLog(@"Couldn't open source...");
url = [NSURL URLWithString:@"silence://10"];
source = [AudioSource audioSourceForURL:url];
if(![source open:url])
return NO;
}
if (![inputNode openURL:url withSource:source outputFormat:outputFormat])
if(![inputNode openWithSource:source])
return NO;
if(![self initConverter:outputFormat])
return NO;
[self initDownmixer];
[self setRGInfo:rgi];
// return NO;
return YES;
}
- (BOOL)openWithInput:(InputNode *)i withOutputFormat:(AudioStreamBasicDescription)outputFormat withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)rgi {
DLog(@"New buffer chain!");
[self setUserInfo:userInfo];
if(![self buildChain]) {
DLog(@"Couldn't build processing chain...");
return NO;
}
if(![inputNode openWithDecoder:[i decoder]])
return NO;
if(![self initConverter:outputFormat])
return NO;
[self initDownmixer];
[self setRGInfo:rgi];
return YES;
}
- (BOOL)openWithDecoder:(id<CogDecoder>)decoder
withOutputFormat:(AudioStreamBasicDescription)outputFormat
withUserInfo:(id)userInfo
withRGInfo:(NSDictionary *)rgi;
{
DLog(@"New buffer chain!");
[self setUserInfo:userInfo];
if(![self buildChain]) {
DLog(@"Couldn't build processing chain...");
return NO;
}
if(![inputNode openWithDecoder:decoder])
return NO;
if(![self initConverter:outputFormat])
return NO;
[self initDownmixer];
[self setRGInfo:rgi];
return YES;
}
- (BOOL)initConverter:(AudioStreamBasicDescription)outputFormat {
NSDictionary *properties = [inputNode properties];
DLog(@"Input Properties: %@", properties);
AudioStreamBasicDescription inputFormat = [inputNode nodeFormat];
uint32_t inputChannelConfig = 0;
if([properties valueForKey:@"channelConfig"])
inputChannelConfig = [[properties valueForKey:@"channelConfig"] unsignedIntValue];
outputFormat.mChannelsPerFrame = inputFormat.mChannelsPerFrame;
outputFormat.mBytesPerFrame = ((outputFormat.mBitsPerChannel + 7) / 8) * outputFormat.mChannelsPerFrame;
outputFormat.mBytesPerPacket = outputFormat.mBytesPerFrame * outputFormat.mFramesPerPacket;
if(![converterNode setupWithInputFormat:inputFormat withInputConfig:inputChannelConfig outputFormat:outputFormat isLossless:[[properties valueForKey:@"encoding"] isEqualToString:@"lossless"]])
return NO;
return YES;
}
- (void)launchThreads
{
[inputNode launchThread];
- (void)initDownmixer {
AudioPlayer * audioPlayer = controller;
OutputNode *outputNode = [audioPlayer output];
DSPDownmixNode *downmixNode = [outputNode downmix];
[downmixNode setOutputFormat:[outputNode deviceFormat] withChannelConfig:[outputNode deviceChannelConfig]];
}
- (void)setUserInfo:(id)i
{
[i retain];
[userInfo release];
- (void)launchThreads {
DLog(@"Properties: %@", [inputNode properties]);
[inputNode launchThread];
[converterNode launchThread];
}
- (void)setUserInfo:(id)i {
userInfo = i;
}
- (id)userInfo
{
- (id)userInfo {
return userInfo;
}
- (void)dealloc
{
[userInfo release];
[inputNode release];
[super dealloc];
- (void)setRGInfo:(NSDictionary *)rgi {
rgInfo = rgi;
[converterNode setRGInfo:rgi];
}
- (void)seek:(double)time
{
[inputNode seek:time];
- (NSDictionary *)rgInfo {
return rgInfo;
}
- (void)endOfInputReached
{
[controller endOfInputReached:self];
- (void)dealloc {
[inputNode setShouldContinue:NO];
[[inputNode exitAtTheEndOfTheStream] signal];
[[inputNode writeSemaphore] signal];
if(![inputNode threadExited])
[[inputNode exitAtTheEndOfTheStream] wait]; // wait for decoder to be closed (see InputNode's -(void)process )
DLog(@"Bufferchain dealloc");
}
- (void)initialBufferFilled
{
- (void)seek:(double)time {
long frame = (long)round(time * [[[inputNode properties] objectForKey:@"sampleRate"] floatValue]);
[inputNode seek:frame];
}
- (BOOL)endOfInputReached {
return [controller endOfInputReached:self];
}
- (BOOL)setTrack:(NSURL *)track {
return [inputNode setTrack:track];
}
- (void)initialBufferFilled:(id)sender {
DLog(@"INITIAL BUFFER FILLED");
[controller launchOutputThread];
}
- (id)finalNode
{
- (InputNode *)inputNode {
return inputNode;
}
- (id)finalNode {
return finalNode;
}
- (NSURL *)streamURL
{
- (NSURL *)streamURL {
return streamURL;
}
- (void)setStreamURL:(NSURL *)url
{
[url retain];
[streamURL release];
- (void)setStreamURL:(NSURL *)url {
streamURL = url;
}
- (void)setShouldContinue:(BOOL)s
{
- (void)setShouldContinue:(BOOL)s {
[inputNode setShouldContinue:s];
[converterNode setShouldContinue:s];
}
- (BOOL)isRunning {
InputNode *node = [self inputNode];
if(nil != node && [node shouldContinue] && ![node endOfStream]) {
return YES;
}
return NO;
}
- (id)controller {
return controller;
}
- (ConverterNode *)converter {
return converterNode;
}
- (AudioStreamBasicDescription)inputFormat {
return [inputNode nodeFormat];
}
- (uint32_t)inputConfig {
return [inputNode nodeChannelConfig];
}
- (double)secondsBuffered {
double duration = 0.0;
Node *node = [self finalNode];
while(node) {
duration += [node secondsBuffered];
node = [node previousNode];
}
return duration;
}
- (void)sustainHDCD {
OutputNode *outputNode = (OutputNode *)[controller output];
[outputNode sustainHDCD];
[controller sustainHDCD];
}
- (void)restartPlaybackAtCurrentPosition {
[controller restartPlaybackAtCurrentPosition];
}
- (void)pushInfo:(NSDictionary *)info {
[controller pushInfo:info toTrack:userInfo];
}
- (void)setError:(BOOL)status {
[controller setError:status];
}
@end

86
Audio/Chain/ChunkList.h Normal file
View file

@ -0,0 +1,86 @@
//
// ChunkList.h
// CogAudio Framework
//
// Created by Christopher Snowhill on 2/5/22.
//
#import <CoreAudio/CoreAudio.h>
#import <Foundation/Foundation.h>
#import <CogAudio/AudioChunk.h>
#import <CogAudio/CogSemaphore.h>
NS_ASSUME_NONNULL_BEGIN
#define DSD_DECIMATE 1
@interface ChunkList : NSObject {
NSMutableArray<AudioChunk *> *chunkList;
double listDuration;
double listDurationRatioed;
double maxDuration;
BOOL inAdder;
BOOL inRemover;
BOOL inPeeker;
BOOL inMerger;
BOOL inConverter;
BOOL stopping;
// For format converter
void *inputBuffer;
size_t inputBufferSize;
#if DSD_DECIMATE
void **dsd2pcm;
size_t dsd2pcmCount;
int dsd2pcmLatency;
#endif
BOOL observersRegistered;
BOOL halveDSDVolume;
BOOL enableHDCD;
void *hdcd_decoder;
BOOL formatRead;
AudioStreamBasicDescription inputFormat;
AudioStreamBasicDescription floatFormat;
uint32_t inputChannelConfig;
BOOL inputLossless;
uint8_t *tempData;
size_t tempDataSize;
}
@property(readonly) double listDuration;
@property(readonly) double listDurationRatioed;
@property(readonly) double maxDuration;
- (id)initWithMaximumDuration:(double)duration;
- (void)reset;
- (BOOL)isEmpty;
- (BOOL)isFull;
- (void)addChunk:(AudioChunk *)chunk;
- (AudioChunk *)removeSamples:(size_t)maxFrameCount;
- (AudioChunk *)removeSamplesAsFloat32:(size_t)maxFrameCount;
- (BOOL)peekFormat:(nonnull AudioStreamBasicDescription *)format channelConfig:(nonnull uint32_t *)config;
- (BOOL)peekTimestamp:(nonnull double *)timestamp timeRatio:(nonnull double *)timeRatio;
// Helpers
- (AudioChunk *)removeAndMergeSamples:(size_t)maxFrameCount callBlock:(BOOL(NS_NOESCAPE ^ _Nonnull)(void))block;
- (AudioChunk *)removeAndMergeSamplesAsFloat32:(size_t)maxFrameCount callBlock:(BOOL(NS_NOESCAPE ^ _Nonnull)(void))block;
@end
NS_ASSUME_NONNULL_END

977
Audio/Chain/ChunkList.m Normal file
View file

@ -0,0 +1,977 @@
//
// ChunkList.m
// CogAudio Framework
//
// Created by Christopher Snowhill on 2/5/22.
//
#import <Accelerate/Accelerate.h>
#import "ChunkList.h"
#import "hdcd_decode2.h"
#if !DSD_DECIMATE
#import "dsd2float.h"
#endif
#ifdef _DEBUG
#import "BadSampleCleaner.h"
#endif
static void *kChunkListContext = &kChunkListContext;
#if DSD_DECIMATE
/**
* DSD 2 PCM: Stage 1:
* Decimate by factor 8
* (one byte (8 samples) -> one float sample)
* The bits are processed from least signicifant to most signicicant.
* @author Sebastian Gesemann
*/
/**
* This is the 2nd half of an even order symmetric FIR
* lowpass filter (to be used on a signal sampled at 44100*64 Hz)
* Passband is 0-24 kHz (ripples +/- 0.025 dB)
* Stopband starts at 176.4 kHz (rejection: 170 dB)
* The overall gain is 2.0
*/
#define dsd2pcm_FILTER_COEFFS_COUNT 64
static const float dsd2pcm_FILTER_COEFFS[64] = {
0.09712411121659f, 0.09613438994044f, 0.09417884216316f, 0.09130441727307f,
0.08757947648990f, 0.08309142055179f, 0.07794369263673f, 0.07225228745463f,
0.06614191680338f, 0.05974199351302f, 0.05318259916599f, 0.04659059631228f,
0.04008603356890f, 0.03377897290478f, 0.02776684382775f, 0.02213240062966f,
0.01694232798846f, 0.01224650881275f, 0.00807793792573f, 0.00445323755944f,
0.00137370697215f, -0.00117318019994f, -0.00321193033831f, -0.00477694265140f,
-0.00591028841335f, -0.00665946056286f, -0.00707518873201f, -0.00720940203988f,
-0.00711340642819f, -0.00683632603227f, -0.00642384017266f, -0.00591723006715f,
-0.00535273320457f, -0.00476118922548f, -0.00416794965654f, -0.00359301524813f,
-0.00305135909510f, -0.00255339111833f, -0.00210551956895f, -0.00171076760278f,
-0.00136940723130f, -0.00107957856005f, -0.00083786862365f, -0.00063983084245f,
-0.00048043272086f, -0.00035442550015f, -0.00025663481039f, -0.00018217573430f,
-0.00012659899635f, -0.00008597726991f, -0.00005694188820f, -0.00003668060332f,
-0.00002290670286f, -0.00001380895679f, -0.00000799057558f, -0.00000440385083f,
-0.00000228567089f, -0.00000109760778f, -0.00000047286430f, -0.00000017129652f,
-0.00000004282776f, 0.00000000119422f, 0.00000000949179f, 0.00000000747450f
};
struct dsd2pcm_state {
/*
* This is the 2nd half of an even order symmetric FIR
* lowpass filter (to be used on a signal sampled at 44100*64 Hz)
* Passband is 0-24 kHz (ripples +/- 0.025 dB)
* Stopband starts at 176.4 kHz (rejection: 170 dB)
* The overall gain is 2.0
*/
/* These remain constant for the duration */
int FILT_LOOKUP_PARTS;
float *FILT_LOOKUP_TABLE;
uint8_t *REVERSE_BITS;
int FIFO_LENGTH;
int FIFO_OFS_MASK;
/* These are altered */
int *fifo;
int fpos;
};
static void dsd2pcm_free(void *);
static void dsd2pcm_reset(void *);
static void *dsd2pcm_alloc(void) {
struct dsd2pcm_state *state = (struct dsd2pcm_state *)calloc(1, sizeof(struct dsd2pcm_state));
float *FILT_LOOKUP_TABLE;
double *temp;
uint8_t *REVERSE_BITS;
if(!state)
return NULL;
state->FILT_LOOKUP_PARTS = (dsd2pcm_FILTER_COEFFS_COUNT + 7) / 8;
const int FILT_LOOKUP_PARTS = state->FILT_LOOKUP_PARTS;
// The current 128 tap FIR leads to an 8 KB lookup table
state->FILT_LOOKUP_TABLE = (float *)calloc(sizeof(float), FILT_LOOKUP_PARTS << 8);
if(!state->FILT_LOOKUP_TABLE)
goto fail;
FILT_LOOKUP_TABLE = state->FILT_LOOKUP_TABLE;
temp = (double *)calloc(sizeof(double), 0x100);
if(!temp)
goto fail;
for(int part = 0, sofs = 0, dofs = 0; part < FILT_LOOKUP_PARTS;) {
memset(temp, 0, 0x100 * sizeof(double));
for(int bit = 0, bitmask = 0x80; bit < 8 && sofs + bit < dsd2pcm_FILTER_COEFFS_COUNT;) {
double coeff = dsd2pcm_FILTER_COEFFS[sofs + bit];
for(int bite = 0; bite < 0x100; bite++) {
if((bite & bitmask) == 0) {
temp[bite] -= coeff;
} else {
temp[bite] += coeff;
}
}
bit++;
bitmask >>= 1;
}
for(int s = 0; s < 0x100;) {
FILT_LOOKUP_TABLE[dofs++] = (float)temp[s++];
}
part++;
sofs += 8;
}
free(temp);
{ // calculate FIFO stuff
int k = 1;
while(k < FILT_LOOKUP_PARTS * 2) k <<= 1;
state->FIFO_LENGTH = k;
state->FIFO_OFS_MASK = k - 1;
}
state->REVERSE_BITS = (uint8_t *)calloc(1, 0x100);
if(!state->REVERSE_BITS)
goto fail;
REVERSE_BITS = state->REVERSE_BITS;
for(int i = 0, j = 0; i < 0x100; i++) {
REVERSE_BITS[i] = (uint8_t)j;
// "reverse-increment" of j
for(int bitmask = 0x80;;) {
if(((j ^= bitmask) & bitmask) != 0) break;
if(bitmask == 1) break;
bitmask >>= 1;
}
}
state->fifo = (int *)calloc(sizeof(int), state->FIFO_LENGTH);
if(!state->fifo)
goto fail;
dsd2pcm_reset(state);
return (void *)state;
fail:
dsd2pcm_free(state);
return NULL;
}
static void *dsd2pcm_dup(void *_state) {
struct dsd2pcm_state *state = (struct dsd2pcm_state *)_state;
if(state) {
struct dsd2pcm_state *newstate = (struct dsd2pcm_state *)calloc(1, sizeof(struct dsd2pcm_state));
if(newstate) {
newstate->FILT_LOOKUP_PARTS = state->FILT_LOOKUP_PARTS;
newstate->FIFO_LENGTH = state->FIFO_LENGTH;
newstate->FIFO_OFS_MASK = state->FIFO_OFS_MASK;
newstate->fpos = state->fpos;
newstate->FILT_LOOKUP_TABLE = (float *)calloc(sizeof(float), state->FILT_LOOKUP_PARTS << 8);
if(!newstate->FILT_LOOKUP_TABLE)
goto fail;
memcpy(newstate->FILT_LOOKUP_TABLE, state->FILT_LOOKUP_TABLE, sizeof(float) * (state->FILT_LOOKUP_PARTS << 8));
newstate->REVERSE_BITS = (uint8_t *)calloc(1, 0x100);
if(!newstate->REVERSE_BITS)
goto fail;
memcpy(newstate->REVERSE_BITS, state->REVERSE_BITS, 0x100);
newstate->fifo = (int *)calloc(sizeof(int), state->FIFO_LENGTH);
if(!newstate->fifo)
goto fail;
memcpy(newstate->fifo, state->fifo, sizeof(int) * state->FIFO_LENGTH);
return (void *)newstate;
}
fail:
dsd2pcm_free(newstate);
return NULL;
}
return NULL;
}
static void dsd2pcm_free(void *_state) {
struct dsd2pcm_state *state = (struct dsd2pcm_state *)_state;
if(state) {
free(state->fifo);
free(state->REVERSE_BITS);
free(state->FILT_LOOKUP_TABLE);
free(state);
}
}
static void dsd2pcm_reset(void *_state) {
struct dsd2pcm_state *state = (struct dsd2pcm_state *)_state;
const int FILT_LOOKUP_PARTS = state->FILT_LOOKUP_PARTS;
int *fifo = state->fifo;
for(int i = 0; i < FILT_LOOKUP_PARTS; i++) {
fifo[i] = 0x55;
fifo[i + FILT_LOOKUP_PARTS] = 0xAA;
}
state->fpos = FILT_LOOKUP_PARTS;
}
static int dsd2pcm_latency(void *_state) {
struct dsd2pcm_state *state = (struct dsd2pcm_state *)_state;
if(state)
return state->FILT_LOOKUP_PARTS * 8;
else
return 0;
}
static void dsd2pcm_process(void *_state, const uint8_t *src, size_t sofs, size_t sinc, float *dest, size_t dofs, size_t dinc, size_t len) {
struct dsd2pcm_state *state = (struct dsd2pcm_state *)_state;
int bite1, bite2, temp;
float sample;
int *fifo = state->fifo;
const uint8_t *REVERSE_BITS = state->REVERSE_BITS;
const float *FILT_LOOKUP_TABLE = state->FILT_LOOKUP_TABLE;
const int FILT_LOOKUP_PARTS = state->FILT_LOOKUP_PARTS;
const int FIFO_OFS_MASK = state->FIFO_OFS_MASK;
int fpos = state->fpos;
while(len > 0) {
fifo[fpos] = REVERSE_BITS[fifo[fpos]] & 0xFF;
fifo[(fpos + FILT_LOOKUP_PARTS) & FIFO_OFS_MASK] = src[sofs] & 0xFF;
sofs += sinc;
temp = (fpos + 1) & FIFO_OFS_MASK;
sample = 0;
for(int k = 0, lofs = 0; k < FILT_LOOKUP_PARTS;) {
bite1 = fifo[(fpos - k) & FIFO_OFS_MASK];
bite2 = fifo[(temp + k) & FIFO_OFS_MASK];
sample += FILT_LOOKUP_TABLE[lofs + bite1] + FILT_LOOKUP_TABLE[lofs + bite2];
k++;
lofs += 0x100;
}
fpos = temp;
dest[dofs] = sample;
dofs += dinc;
len--;
}
state->fpos = fpos;
}
static void convert_dsd_to_f32(float *output, const uint8_t *input, size_t count, size_t channels, void **dsd2pcm) {
for(size_t channel = 0; channel < channels; ++channel) {
dsd2pcm_process(dsd2pcm[channel], input, channel, channels, output, channel, channels, count);
}
}
#else
static void convert_dsd_to_f32(float *output, const uint8_t *input, size_t count, size_t channels) {
const uint8_t *iptr = input;
float *optr = output;
for(size_t index = 0; index < count; ++index) {
for(size_t channel = 0; channel < channels; ++channel) {
uint8_t sample = *iptr++;
cblas_scopy(8, &dsd2float[sample][0], 1, optr++, (int)channels);
}
optr += channels * 7;
}
}
#endif
static void convert_u8_to_s16(int16_t *output, const uint8_t *input, size_t count) {
for(size_t i = 0; i < count; ++i) {
uint16_t sample = (input[i] << 8) | input[i];
sample ^= 0x8080;
output[i] = (int16_t)(sample);
}
}
static void convert_s8_to_s16(int16_t *output, const uint8_t *input, size_t count) {
for(size_t i = 0; i < count; ++i) {
uint16_t sample = (input[i] << 8) | input[i];
output[i] = (int16_t)(sample);
}
}
static void convert_u16_to_s16(int16_t *buffer, size_t count) {
for(size_t i = 0; i < count; ++i) {
buffer[i] ^= 0x8000;
}
}
static void convert_s16_to_hdcd_input(int32_t *output, const int16_t *input, size_t count) {
for(size_t i = 0; i < count; ++i) {
output[i] = input[i];
}
}
static void convert_s24_to_s32(int32_t *output, const uint8_t *input, size_t count) {
for(size_t i = 0; i < count; ++i) {
int32_t sample = (input[i * 3] << 8) | (input[i * 3 + 1] << 16) | (input[i * 3 + 2] << 24);
output[i] = sample;
}
}
static void convert_u24_to_s32(int32_t *output, const uint8_t *input, size_t count) {
for(size_t i = 0; i < count; ++i) {
int32_t sample = (input[i * 3] << 8) | (input[i * 3 + 1] << 16) | (input[i * 3 + 2] << 24);
output[i] = sample ^ 0x80000000;
}
}
static void convert_u32_to_s32(int32_t *buffer, size_t count) {
for(size_t i = 0; i < count; ++i) {
buffer[i] ^= 0x80000000;
}
}
static void convert_f64_to_f32(float *output, const double *input, size_t count) {
vDSP_vdpsp(input, 1, output, 1, count);
}
static void convert_be_to_le(uint8_t *buffer, size_t bitsPerSample, size_t bytes) {
size_t i;
bitsPerSample = (bitsPerSample + 7) / 8;
switch(bitsPerSample) {
case 2:
for(i = 0; i < bytes; i += 2) {
*(int16_t *)buffer = __builtin_bswap16(*(int16_t *)buffer);
buffer += 2;
}
break;
case 3: {
union {
vDSP_int24 int24;
uint32_t int32;
} intval;
intval.int32 = 0;
for(i = 0; i < bytes; i += 3) {
intval.int24 = *(vDSP_int24 *)buffer;
intval.int32 = __builtin_bswap32(intval.int32 << 8);
*(vDSP_int24 *)buffer = intval.int24;
buffer += 3;
}
} break;
case 4:
for(i = 0; i < bytes; i += 4) {
*(uint32_t *)buffer = __builtin_bswap32(*(uint32_t *)buffer);
buffer += 4;
}
break;
case 8:
for(i = 0; i < bytes; i += 8) {
*(uint64_t *)buffer = __builtin_bswap64(*(uint64_t *)buffer);
buffer += 8;
}
break;
}
}
@implementation ChunkList
@synthesize listDuration;
@synthesize listDurationRatioed;
@synthesize maxDuration;
- (id)initWithMaximumDuration:(double)duration {
self = [super init];
if(self) {
chunkList = [[NSMutableArray alloc] init];
listDuration = 0.0;
listDurationRatioed = 0.0;
maxDuration = duration;
inAdder = NO;
inRemover = NO;
inPeeker = NO;
inMerger = NO;
inConverter = NO;
stopping = NO;
formatRead = NO;
inputBuffer = NULL;
inputBufferSize = 0;
#if DSD_DECIMATE
dsd2pcm = NULL;
dsd2pcmCount = 0;
dsd2pcmLatency = 0;
#endif
observersRegistered = NO;
}
return self;
}
- (void)addObservers {
if(!observersRegistered) {
halveDSDVolume = NO;
enableHDCD = NO;
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.halveDSDVolume" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kChunkListContext];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.enableHDCD" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kChunkListContext];
observersRegistered = YES;
}
}
- (void)removeObservers {
if(observersRegistered) {
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.halveDSDVolume" context:kChunkListContext];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.enableHDCD" context:kChunkListContext];
observersRegistered = NO;
}
}
- (void)dealloc {
stopping = YES;
while(inAdder || inRemover || inPeeker || inMerger || inConverter) {
usleep(500);
}
[self removeObservers];
if(hdcd_decoder) {
free(hdcd_decoder);
hdcd_decoder = NULL;
}
#if DSD_DECIMATE
if(dsd2pcm && dsd2pcmCount) {
for(size_t i = 0; i < dsd2pcmCount; ++i) {
dsd2pcm_free(dsd2pcm[i]);
dsd2pcm[i] = NULL;
}
free(dsd2pcm);
dsd2pcm = NULL;
}
#endif
if(tempData) {
free(tempData);
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if(context != kChunkListContext) {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
return;
}
if([keyPath isEqualToString:@"values.halveDSDVolume"]) {
halveDSDVolume = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] boolForKey:@"halveDSDVolume"];
} else if([keyPath isEqualToString:@"values.enableHDCD"]) {
enableHDCD = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] boolForKey:@"enableHDCD"];
}
}
- (void)reset {
@synchronized(chunkList) {
[chunkList removeAllObjects];
listDuration = 0.0;
listDurationRatioed = 0.0;
}
}
- (BOOL)isEmpty {
@synchronized(chunkList) {
return [chunkList count] == 0;
}
}
- (BOOL)isFull {
@synchronized (chunkList) {
return (maxDuration - listDuration) < 0.001;
}
}
- (void)addChunk:(AudioChunk *)chunk {
if(stopping) return;
inAdder = YES;
const double chunkDuration = [chunk duration];
const double chunkDurationRatioed = [chunk durationRatioed];
@synchronized(chunkList) {
[chunkList addObject:chunk];
listDuration += chunkDuration;
listDurationRatioed += chunkDurationRatioed;
}
inAdder = NO;
}
- (AudioChunk *)removeSamples:(size_t)maxFrameCount {
if(stopping) {
return [[AudioChunk alloc] init];
}
@synchronized(chunkList) {
inRemover = YES;
if(![chunkList count]) {
inRemover = NO;
return [[AudioChunk alloc] init];
}
AudioChunk *chunk = [chunkList objectAtIndex:0];
if([chunk frameCount] <= maxFrameCount) {
[chunkList removeObjectAtIndex:0];
listDuration -= [chunk duration];
listDurationRatioed -= [chunk durationRatioed];
inRemover = NO;
return chunk;
}
double streamTimestamp = [chunk streamTimestamp];
NSData *removedData = [chunk removeSamples:maxFrameCount];
AudioChunk *ret = [[AudioChunk alloc] init];
[ret setFormat:[chunk format]];
[ret setChannelConfig:[chunk channelConfig]];
[ret setLossless:[chunk lossless]];
[ret setStreamTimestamp:streamTimestamp];
[ret setStreamTimeRatio:[chunk streamTimeRatio]];
[ret assignData:removedData];
listDuration -= [ret duration];
listDurationRatioed -= [ret durationRatioed];
inRemover = NO;
return ret;
}
}
- (AudioChunk *)removeSamplesAsFloat32:(size_t)maxFrameCount {
if(stopping) {
return [[AudioChunk alloc] init];
}
@synchronized (chunkList) {
inRemover = YES;
if(![chunkList count]) {
inRemover = NO;
return [[AudioChunk alloc] init];
}
AudioChunk *chunk = [chunkList objectAtIndex:0];
#if !DSD_DECIMATE
AudioStreamBasicDescription asbd = [chunk format];
if(asbd.mBitsPerChannel == 1) {
maxFrameCount /= 8;
}
#endif
if([chunk frameCount] <= maxFrameCount) {
[chunkList removeObjectAtIndex:0];
listDuration -= [chunk duration];
listDurationRatioed -= [chunk durationRatioed];
inRemover = NO;
return [self convertChunk:chunk];
}
double streamTimestamp = [chunk streamTimestamp];
NSData *removedData = [chunk removeSamples:maxFrameCount];
AudioChunk *ret = [[AudioChunk alloc] init];
[ret setFormat:[chunk format]];
[ret setChannelConfig:[chunk channelConfig]];
[ret setLossless:[chunk lossless]];
[ret setStreamTimestamp:streamTimestamp];
[ret setStreamTimeRatio:[chunk streamTimeRatio]];
[ret assignData:removedData];
listDuration -= [ret duration];
listDurationRatioed -= [ret durationRatioed];
inRemover = NO;
return [self convertChunk:ret];
}
}
- (AudioChunk *)removeAndMergeSamples:(size_t)maxFrameCount callBlock:(BOOL(NS_NOESCAPE ^ _Nonnull)(void))block {
if(stopping) {
return [[AudioChunk alloc] init];
}
inMerger = YES;
BOOL formatSet = NO;
AudioStreamBasicDescription currentFormat;
uint32_t currentChannelConfig = 0;
double streamTimestamp = 0.0;
double streamTimeRatio = 1.0;
BOOL blocked = NO;
while(![self peekTimestamp:&streamTimestamp timeRatio:&streamTimeRatio]) {
if((blocked = block())) {
break;
}
}
if(blocked) {
inMerger = NO;
return [[AudioChunk alloc] init];
}
AudioChunk *chunk;
size_t totalFrameCount = 0;
AudioChunk *outputChunk = [[AudioChunk alloc] init];
[outputChunk setStreamTimestamp:streamTimestamp];
[outputChunk setStreamTimeRatio:streamTimeRatio];
while(!stopping && totalFrameCount < maxFrameCount) {
AudioStreamBasicDescription newFormat;
uint32_t newChannelConfig;
if(![self peekFormat:&newFormat channelConfig:&newChannelConfig]) {
if(block()) {
break;
}
continue;
}
if(formatSet &&
(memcmp(&newFormat, &currentFormat, sizeof(newFormat)) != 0 ||
newChannelConfig != currentChannelConfig)) {
break;
} else if(!formatSet) {
[outputChunk setFormat:newFormat];
[outputChunk setChannelConfig:newChannelConfig];
currentFormat = newFormat;
currentChannelConfig = newChannelConfig;
formatSet = YES;
}
chunk = [self removeSamples:maxFrameCount - totalFrameCount];
if(!chunk || ![chunk frameCount]) {
if(block()) {
break;
}
continue;
}
if([chunk isHDCD]) {
[outputChunk setHDCD];
}
size_t frameCount = [chunk frameCount];
NSData *sampleData = [chunk removeSamples:frameCount];
[outputChunk assignData:sampleData];
totalFrameCount += frameCount;
}
if(!totalFrameCount) {
inMerger = NO;
return [[AudioChunk alloc] init];
}
inMerger = NO;
return outputChunk;
}
- (AudioChunk *)removeAndMergeSamplesAsFloat32:(size_t)maxFrameCount callBlock:(BOOL(NS_NOESCAPE ^ _Nonnull)(void))block {
AudioChunk *ret = [self removeAndMergeSamples:maxFrameCount callBlock:block];
return [self convertChunk:ret];
}
- (AudioChunk *)convertChunk:(AudioChunk *)inChunk {
if(stopping) return [[AudioChunk alloc] init];
inConverter = YES;
AudioStreamBasicDescription chunkFormat = [inChunk format];
if(![inChunk frameCount] ||
(chunkFormat.mFormatFlags == kAudioFormatFlagsNativeFloatPacked &&
chunkFormat.mBitsPerChannel == 32)) {
inConverter = NO;
return inChunk;
}
uint32_t chunkConfig = [inChunk channelConfig];
BOOL chunkLossless = [inChunk lossless];
if(!formatRead || memcmp(&chunkFormat, &inputFormat, sizeof(chunkFormat)) != 0 ||
chunkConfig != inputChannelConfig || chunkLossless != inputLossless) {
formatRead = YES;
inputFormat = chunkFormat;
inputChannelConfig = chunkConfig;
inputLossless = chunkLossless;
BOOL isFloat = !!(inputFormat.mFormatFlags & kAudioFormatFlagIsFloat);
if((!isFloat && !(inputFormat.mBitsPerChannel >= 1 && inputFormat.mBitsPerChannel <= 32)) || (isFloat && !(inputFormat.mBitsPerChannel == 32 || inputFormat.mBitsPerChannel == 64))) {
inConverter = NO;
return [[AudioChunk alloc] init];
}
// These are really placeholders, as we're doing everything internally now
if(inputLossless &&
inputFormat.mBitsPerChannel == 16 &&
inputFormat.mChannelsPerFrame == 2 &&
inputFormat.mSampleRate == 44100) {
// possibly HDCD, run through decoder
[self addObservers];
if(hdcd_decoder) {
free(hdcd_decoder);
hdcd_decoder = NULL;
}
hdcd_decoder = calloc(1, sizeof(hdcd_state_stereo_t));
hdcd_reset_stereo((hdcd_state_stereo_t *)hdcd_decoder, 44100);
}
floatFormat = inputFormat;
floatFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
floatFormat.mBitsPerChannel = 32;
floatFormat.mBytesPerFrame = (32 / 8) * floatFormat.mChannelsPerFrame;
floatFormat.mBytesPerPacket = floatFormat.mBytesPerFrame * floatFormat.mFramesPerPacket;
#if DSD_DECIMATE
if(inputFormat.mBitsPerChannel == 1) {
// Decimate this for speed
floatFormat.mSampleRate *= 1.0 / 8.0;
if(dsd2pcm && dsd2pcmCount) {
for(size_t i = 0; i < dsd2pcmCount; ++i) {
dsd2pcm_free(dsd2pcm[i]);
dsd2pcm[i] = NULL;
}
free(dsd2pcm);
dsd2pcm = NULL;
}
dsd2pcmCount = floatFormat.mChannelsPerFrame;
dsd2pcm = (void **)calloc(dsd2pcmCount, sizeof(void *));
dsd2pcm[0] = dsd2pcm_alloc();
dsd2pcmLatency = dsd2pcm_latency(dsd2pcm[0]);
for(size_t i = 1; i < dsd2pcmCount; ++i) {
dsd2pcm[i] = dsd2pcm_dup(dsd2pcm[0]);
}
}
#endif
}
NSUInteger samplesRead = [inChunk frameCount];
if(!samplesRead) {
inConverter = NO;
return [[AudioChunk alloc] init];
}
BOOL isFloat = !!(inputFormat.mFormatFlags & kAudioFormatFlagIsFloat);
BOOL isUnsigned = !isFloat && !(inputFormat.mFormatFlags & kAudioFormatFlagIsSignedInteger);
size_t bitsPerSample = inputFormat.mBitsPerChannel;
BOOL isBigEndian = !!(inputFormat.mFormatFlags & kAudioFormatFlagIsBigEndian);
double streamTimestamp = [inChunk streamTimestamp];
NSData *inputData = [inChunk removeSamples:samplesRead];
#if DSD_DECIMATE
const size_t sizeFactor = 3;
#else
const size_t sizeFactor = (bitsPerSample == 1) ? 9 : 3;
#endif
size_t newSize = samplesRead * floatFormat.mBytesPerPacket * sizeFactor + 64;
if(!tempData || tempDataSize < newSize)
tempData = realloc(tempData, tempDataSize = newSize); // Either two buffers plus padding, and/or double precision in case of endian flip
// double buffer system, with alignment
const size_t buffer_adder_base = (samplesRead * floatFormat.mBytesPerPacket + 31) & ~31;
NSUInteger bytesReadFromInput = samplesRead * inputFormat.mBytesPerPacket;
uint8_t *inputBuffer = (uint8_t *)[inputData bytes];
BOOL inputChanged = NO;
BOOL hdcdSustained = NO;
if(bytesReadFromInput && isBigEndian) {
// Time for endian swap!
memcpy(&tempData[0], [inputData bytes], bytesReadFromInput);
convert_be_to_le((uint8_t *)(&tempData[0]), inputFormat.mBitsPerChannel, bytesReadFromInput);
inputBuffer = &tempData[0];
inputChanged = YES;
}
if(bytesReadFromInput && isFloat && bitsPerSample == 64) {
// Time for precision loss from weird inputs
const size_t buffer_adder = (inputBuffer == &tempData[0]) ? buffer_adder_base * 2 : 0;
samplesRead = bytesReadFromInput / sizeof(double);
convert_f64_to_f32((float *)(&tempData[buffer_adder]), (const double *)inputBuffer, samplesRead);
bytesReadFromInput = samplesRead * sizeof(float);
inputBuffer = &tempData[buffer_adder];
inputChanged = YES;
bitsPerSample = 32;
}
if(bytesReadFromInput && !isFloat) {
float gain = 1.0;
if(bitsPerSample == 1) {
const size_t buffer_adder = (inputBuffer == &tempData[0]) ? buffer_adder_base : 0;
samplesRead = bytesReadFromInput / inputFormat.mBytesPerPacket;
convert_dsd_to_f32((float *)(&tempData[buffer_adder]), (const uint8_t *)inputBuffer, samplesRead, inputFormat.mChannelsPerFrame
#if DSD_DECIMATE
,
dsd2pcm
#endif
);
#if !DSD_DECIMATE
samplesRead *= 8;
#endif
bitsPerSample = 32;
bytesReadFromInput = samplesRead * floatFormat.mBytesPerPacket;
isFloat = YES;
inputBuffer = &tempData[buffer_adder];
inputChanged = YES;
[self addObservers];
#if DSD_DECIMATE
if(halveDSDVolume) {
float scaleFactor = 2.0f;
vDSP_vsdiv((float *)inputBuffer, 1, &scaleFactor, (float *)inputBuffer, 1, bytesReadFromInput / sizeof(float));
}
#else
if(!halveDSDVolume) {
float scaleFactor = 2.0f;
vDSP_vsmul((float *)inputBuffer, 1, &scaleFactor, (float *)inputBuffer, 1, bytesReadFromInput / sizeof(float));
}
#endif
} else if(bitsPerSample <= 8) {
samplesRead = bytesReadFromInput;
const size_t buffer_adder = (inputBuffer == &tempData[0]) ? buffer_adder_base : 0;
if(!isUnsigned)
convert_s8_to_s16((int16_t *)(&tempData[buffer_adder]), (const uint8_t *)inputBuffer, samplesRead);
else
convert_u8_to_s16((int16_t *)(&tempData[buffer_adder]), (const uint8_t *)inputBuffer, samplesRead);
bitsPerSample = 16;
bytesReadFromInput = samplesRead * 2;
isUnsigned = NO;
inputBuffer = &tempData[buffer_adder];
inputChanged = YES;
}
if(hdcd_decoder) { // implied bits per sample is 16, produces 32 bit int scale
samplesRead = bytesReadFromInput / 2;
const size_t buffer_adder = (inputBuffer == &tempData[0]) ? buffer_adder_base : 0;
if(isUnsigned) {
if(!inputChanged) {
memcpy(&tempData[buffer_adder], inputBuffer, samplesRead * 2);
inputBuffer = &tempData[buffer_adder];
inputChanged = YES;
}
convert_u16_to_s16((int16_t *)inputBuffer, samplesRead);
isUnsigned = NO;
}
const size_t buffer_adder2 = (inputBuffer == &tempData[0]) ? buffer_adder_base : 0;
convert_s16_to_hdcd_input((int32_t *)(&tempData[buffer_adder2]), (int16_t *)inputBuffer, samplesRead);
hdcd_process_stereo((hdcd_state_stereo_t *)hdcd_decoder, (int32_t *)(&tempData[buffer_adder2]), (int)(samplesRead / 2));
if(((hdcd_state_stereo_t *)hdcd_decoder)->channel[0].sustain &&
((hdcd_state_stereo_t *)hdcd_decoder)->channel[1].sustain) {
hdcdSustained = YES;
}
if(enableHDCD) {
gain = 2.0;
bitsPerSample = 32;
bytesReadFromInput = samplesRead * 4;
isUnsigned = NO;
inputBuffer = &tempData[buffer_adder2];
inputChanged = YES;
} else {
// Discard the output of the decoder and process again
goto process16bit;
}
} else if(bitsPerSample <= 16) {
process16bit:
samplesRead = bytesReadFromInput / 2;
const size_t buffer_adder = (inputBuffer == &tempData[0]) ? buffer_adder_base : 0;
if(isUnsigned) {
if(!inputChanged) {
memcpy(&tempData[buffer_adder], inputBuffer, samplesRead * 2);
inputBuffer = &tempData[buffer_adder];
inputChanged = YES;
}
convert_u16_to_s16((int16_t *)inputBuffer, samplesRead);
}
const size_t buffer_adder2 = (inputBuffer == &tempData[0]) ? buffer_adder_base : 0;
vDSP_vflt16((const short *)inputBuffer, 1, (float *)(&tempData[buffer_adder2]), 1, samplesRead);
float scale = 1ULL << 15;
vDSP_vsdiv((const float *)(&tempData[buffer_adder2]), 1, &scale, (float *)(&tempData[buffer_adder2]), 1, samplesRead);
bitsPerSample = 32;
bytesReadFromInput = samplesRead * sizeof(float);
isUnsigned = NO;
isFloat = YES;
inputBuffer = &tempData[buffer_adder2];
inputChanged = YES;
} else if(bitsPerSample <= 24) {
const size_t buffer_adder = (inputBuffer == &tempData[0]) ? buffer_adder_base : 0;
samplesRead = bytesReadFromInput / 3;
if(isUnsigned)
convert_u24_to_s32((int32_t *)(&tempData[buffer_adder]), (uint8_t *)inputBuffer, samplesRead);
else
convert_s24_to_s32((int32_t *)(&tempData[buffer_adder]), (uint8_t *)inputBuffer, samplesRead);
bitsPerSample = 32;
bytesReadFromInput = samplesRead * 4;
isUnsigned = NO;
inputBuffer = &tempData[buffer_adder];
inputChanged = YES;
}
if(!isFloat && bitsPerSample <= 32) {
samplesRead = bytesReadFromInput / 4;
if(isUnsigned) {
if(!inputChanged) {
memcpy(&tempData[0], inputBuffer, bytesReadFromInput);
inputBuffer = &tempData[0];
}
convert_u32_to_s32((int32_t *)inputBuffer, samplesRead);
}
const size_t buffer_adder = (inputBuffer == &tempData[0]) ? buffer_adder_base : 0; // vDSP functions expect aligned to four elements
vDSP_vflt32((const int *)inputBuffer, 1, (float *)(&tempData[buffer_adder]), 1, samplesRead);
float scale = (1ULL << 31) / gain;
vDSP_vsdiv((const float *)(&tempData[buffer_adder]), 1, &scale, (float *)(&tempData[buffer_adder]), 1, samplesRead);
bitsPerSample = 32;
bytesReadFromInput = samplesRead * sizeof(float);
isUnsigned = NO;
isFloat = YES;
inputBuffer = &tempData[buffer_adder];
}
#ifdef _DEBUG
[BadSampleCleaner cleanSamples:(float *)inputBuffer
amount:bytesReadFromInput / sizeof(float)
location:@"post int to float conversion"];
#endif
}
AudioChunk *outChunk = [[AudioChunk alloc] init];
[outChunk setFormat:floatFormat];
[outChunk setChannelConfig:inputChannelConfig];
[outChunk setLossless:inputLossless];
[outChunk setStreamTimestamp:streamTimestamp];
[outChunk setStreamTimeRatio:[inChunk streamTimeRatio]];
if(hdcdSustained) [outChunk setHDCD];
[outChunk assignSamples:inputBuffer frameCount:bytesReadFromInput / floatFormat.mBytesPerPacket];
inConverter = NO;
return outChunk;
}
- (BOOL)peekFormat:(AudioStreamBasicDescription *)format channelConfig:(uint32_t *)config {
if(stopping) return NO;
inPeeker = YES;
@synchronized(chunkList) {
if([chunkList count]) {
AudioChunk *chunk = [chunkList objectAtIndex:0];
*format = [chunk format];
*config = [chunk channelConfig];
inPeeker = NO;
return YES;
}
}
inPeeker = NO;
return NO;
}
- (BOOL)peekTimestamp:(double *)timestamp timeRatio:(double *)timeRatio {
if(stopping) return NO;
inPeeker = YES;
@synchronized (chunkList) {
if([chunkList count]) {
AudioChunk *chunk = [chunkList objectAtIndex:0];
*timestamp = [chunk streamTimestamp];
*timeRatio = [chunk streamTimeRatio];
inPeeker = NO;
return YES;
}
}
*timestamp = 0.0;
*timeRatio = 1.0;
inPeeker = NO;
return NO;
}
@end

View file

@ -1,44 +0,0 @@
//
// ConverterNode.h
// Cog
//
// Created by Vincent Spader on 8/2/05.
// Copyright 2005 Vincent Spader. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import <CoreAudio/AudioHardware.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AudioUnit/AudioUnit.h>
@interface Converter : NSObject
{
AudioConverterRef converter;
void *outputBuffer;
int outputBufferSize;
//Temporary for callback use
void *inputBuffer;
int inputBufferSize;
BOOL needsReset;
//end
int outputSize;
AudioStreamBasicDescription inputFormat;
AudioStreamBasicDescription outputFormat;
}
- (void *)outputBuffer;
- (int)outputBufferSize;
- (void)setupWithInputFormat:(AudioStreamBasicDescription)inputFormat outputFormat:(AudioStreamBasicDescription)outputFormat;
- (void)cleanUp;
- (void)reset;
//Returns the amount actually read from input
- (int)convert:(void *)input amount:(int)inputSize;
@end

View file

@ -1,167 +0,0 @@
//
// ConverterNode.m
// Cog
//
// Created by Vincent Spader on 8/2/05.
// Copyright 2005 Vincent Spader. All rights reserved.
//
#import "Converter.h"
#import "Node.h"
void PrintStreamDesc (AudioStreamBasicDescription *inDesc)
{
if (!inDesc) {
printf ("Can't print a NULL desc!\n");
return;
}
printf ("- - - - - - - - - - - - - - - - - - - -\n");
printf (" Sample Rate:%f\n", inDesc->mSampleRate);
printf (" Format ID:%s\n", (char*)&inDesc->mFormatID);
printf (" Format Flags:%lX\n", inDesc->mFormatFlags);
printf (" Bytes per Packet:%ld\n", inDesc->mBytesPerPacket);
printf (" Frames per Packet:%ld\n", inDesc->mFramesPerPacket);
printf (" Bytes per Frame:%ld\n", inDesc->mBytesPerFrame);
printf (" Channels per Frame:%ld\n", inDesc->mChannelsPerFrame);
printf (" Bits per Channel:%ld\n", inDesc->mBitsPerChannel);
printf ("- - - - - - - - - - - - - - - - - - - -\n");
}
@implementation Converter
//called from the complexfill when the audio is converted...good clean fun
static OSStatus ACInputProc(AudioConverterRef inAudioConverter, UInt32* ioNumberDataPackets, AudioBufferList* ioData, AudioStreamPacketDescription** outDataPacketDescription, void* inUserData)
{
Converter *converter = (Converter *)inUserData;
OSStatus err = noErr;
if (converter->inputBufferSize > 0) {
int amountConverted = *ioNumberDataPackets * converter->inputFormat.mBytesPerPacket;
if (amountConverted > converter->inputBufferSize) {
amountConverted = converter->inputBufferSize;
}
ioData->mBuffers[0].mData = converter->inputBuffer;
ioData->mBuffers[0].mDataByteSize = amountConverted;
ioData->mBuffers[0].mNumberChannels = (converter->inputFormat.mChannelsPerFrame);
ioData->mNumberBuffers = 1;
*ioNumberDataPackets = amountConverted / converter->inputFormat.mBytesPerPacket;
converter->inputBufferSize -= amountConverted;
converter->inputBuffer = ((char *)converter->inputBuffer) + amountConverted;
}
else {
ioData->mBuffers[0].mData = NULL;
ioData->mBuffers[0].mDataByteSize = 0;
ioData->mNumberBuffers = 1;
*ioNumberDataPackets = 0;
//Reset the converter's internal bufferrs.
converter->needsReset = YES;
}
return err;
}
- (void)reset
{
AudioConverterReset(converter);
}
- (int)convert:(void *)input amount:(int)inputSize
{
AudioBufferList ioData;
UInt32 ioNumberFrames;
if (inputSize <= 0) {
outputBufferSize = inputSize;
return inputSize;
}
OSStatus err;
needsReset = NO;
ioNumberFrames = inputSize/inputFormat.mBytesPerFrame;
ioData.mBuffers[0].mData = outputBuffer;
ioData.mBuffers[0].mDataByteSize = outputSize;
ioData.mBuffers[0].mNumberChannels = outputFormat.mChannelsPerFrame;
ioData.mNumberBuffers = 1;
inputBuffer = input;
inputBufferSize = inputSize;
err = AudioConverterFillComplexBuffer(converter, ACInputProc, self, &ioNumberFrames, &ioData, NULL);
if (err != noErr || needsReset) //It returns insz at EOS at times...so run it again to make sure all data is converted
{
[self reset];
}
outputBufferSize = ioData.mBuffers[0].mDataByteSize;
return inputSize - inputBufferSize;
}
- (void)setupWithInputFormat:(AudioStreamBasicDescription)inf outputFormat:(AudioStreamBasicDescription)outf
{
//Make the converter
OSStatus stat = noErr;
inputFormat = inf;
outputFormat = outf;
stat = AudioConverterNew ( &inputFormat, &outputFormat, &converter);
if (stat != noErr)
{
NSLog(@"Error creating converter %i", stat);
}
if (inputFormat.mChannelsPerFrame == 1)
{
SInt32 channelMap[2] = { 0, 0 };
stat = AudioConverterSetProperty(converter,kAudioConverterChannelMap,sizeof(channelMap),channelMap);
if (stat != noErr)
{
NSLog(@"Error mapping channels %i", stat);
}
}
outputSize = CHUNK_SIZE;
UInt32 dataSize = sizeof(outputSize);
AudioConverterGetProperty(converter,
kAudioConverterPropertyCalculateOutputBufferSize,
&dataSize,
(void*)&outputSize);
if (outputBuffer)
{
free(outputBuffer);
}
outputBuffer = malloc(outputSize);
//PrintStreamDesc(&inf);
//PrintStreamDesc(&outf);
}
- (void *)outputBuffer
{
return outputBuffer;
}
- (int)outputBufferSize
{
return outputBufferSize;
}
- (void)cleanUp
{
if (outputBuffer) {
free(outputBuffer);
outputBuffer = NULL;
}
AudioConverterDispose(converter);
}
@end

View file

@ -0,0 +1,91 @@
//
// ConverterNode.h
// Cog
//
// Created by Zaphod Beeblebrox on 8/2/05.
// Copyright 2005 __MyCompanyName__. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AudioUnit/AudioUnit.h>
#import <CoreAudio/AudioHardware.h>
#import <CogAudio/soxr.h>
#import <CogAudio/Node.h>
@interface ConverterNode : Node {
NSDictionary *rgInfo;
soxr_t soxr;
void *inputBuffer;
size_t inputBufferSize;
size_t inpSize, inpOffset;
double streamTimestamp, streamTimeRatio;
BOOL stopping;
BOOL convertEntered;
BOOL paused;
BOOL skipResampler;
unsigned int PRIME_LEN_;
unsigned int N_samples_to_add_;
unsigned int N_samples_to_drop_;
BOOL is_preextrapolated_;
int is_postextrapolated_;
int latencyEaten;
int latencyEatenPost;
double sampleRatio;
BOOL observersAdded;
float volumeScale;
void *floatBuffer;
size_t floatBufferSize;
void *extrapolateBuffer;
size_t extrapolateBufferSize;
BOOL rememberedLossless;
AudioStreamBasicDescription inputFormat;
AudioStreamBasicDescription floatFormat;
AudioStreamBasicDescription outputFormat;
uint32_t inputChannelConfig;
BOOL streamFormatChanged;
AudioStreamBasicDescription newInputFormat;
uint32_t newInputChannelConfig;
}
@property AudioStreamBasicDescription inputFormat;
- (id)initWithController:(id)c previous:(id)p;
- (BOOL)setupWithInputFormat:(AudioStreamBasicDescription)inputFormat withInputConfig:(uint32_t)inputConfig outputFormat:(AudioStreamBasicDescription)outputFormat isLossless:(BOOL)lossless;
- (void)cleanUp;
- (BOOL)paused;
- (void)process;
- (AudioChunk *)convert;
- (void)setRGInfo:(NSDictionary *)rgi;
- (void)setOutputFormat:(AudioStreamBasicDescription)outputFormat;
- (void)inputFormatDidChange:(AudioStreamBasicDescription)format inputConfig:(uint32_t)inputConfig;
- (void)refreshVolumeScaling;
@end

564
Audio/Chain/ConverterNode.m Normal file
View file

@ -0,0 +1,564 @@
//
// ConverterNode.m
// Cog
//
// Created by Zaphod Beeblebrox on 8/2/05.
// Copyright 2005 __MyCompanyName__. All rights reserved.
//
#import <Accelerate/Accelerate.h>
#import <Foundation/Foundation.h>
#import "ConverterNode.h"
#import "BufferChain.h"
#import "OutputNode.h"
#import "Logging.h"
#import "lpc.h"
#import "util.h"
#ifdef _DEBUG
#import "BadSampleCleaner.h"
#endif
void PrintStreamDesc(AudioStreamBasicDescription *inDesc) {
if(!inDesc) {
DLog(@"Can't print a NULL desc!\n");
return;
}
DLog(@"- - - - - - - - - - - - - - - - - - - -\n");
DLog(@" Sample Rate:%f\n", inDesc->mSampleRate);
DLog(@" Format ID:%s\n", (char *)&inDesc->mFormatID);
DLog(@" Format Flags:%X\n", inDesc->mFormatFlags);
DLog(@" Bytes per Packet:%d\n", inDesc->mBytesPerPacket);
DLog(@" Frames per Packet:%d\n", inDesc->mFramesPerPacket);
DLog(@" Bytes per Frame:%d\n", inDesc->mBytesPerFrame);
DLog(@" Channels per Frame:%d\n", inDesc->mChannelsPerFrame);
DLog(@" Bits per Channel:%d\n", inDesc->mBitsPerChannel);
DLog(@"- - - - - - - - - - - - - - - - - - - -\n");
}
@implementation ConverterNode
static void *kConverterNodeContext = &kConverterNodeContext;
@synthesize inputFormat;
- (id)initWithController:(id)c previous:(id)p {
self = [super initWithController:c previous:p];
if(self) {
rgInfo = nil;
soxr = 0;
inputBuffer = NULL;
inputBufferSize = 0;
floatBuffer = NULL;
floatBufferSize = 0;
stopping = NO;
convertEntered = NO;
paused = NO;
skipResampler = YES;
extrapolateBuffer = NULL;
extrapolateBufferSize = 0;
#ifdef LOG_CHAINS
[self initLogFiles];
#endif
}
return self;
}
- (void)addObservers {
if(!observersAdded) {
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.volumeScaling" options:(NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew) context:kConverterNodeContext];
observersAdded = YES;
}
}
- (void)removeObservers {
if(observersAdded) {
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.volumeScaling" context:kConverterNodeContext];
observersAdded = NO;
}
}
void scale_by_volume(float *buffer, size_t count, float volume) {
if(volume != 1.0) {
size_t unaligned = (uintptr_t)buffer & 15;
if(unaligned) {
size_t count_unaligned = (16 - unaligned) / sizeof(float);
while(count > 0 && count_unaligned > 0) {
*buffer++ *= volume;
count_unaligned--;
count--;
}
}
if(count) {
vDSP_vsmul(buffer, 1, &volume, buffer, 1, count);
}
}
}
- (BOOL)paused {
return paused;
}
- (void)process {
// Removed endOfStream check from here, since we want to be able to flush the converter
// when the end of stream is reached. Convert function instead processes what it can,
// and returns 0 samples when it has nothing more to process at the end of stream.
while([self shouldContinue] == YES) {
while(paused) {
usleep(500);
}
@autoreleasepool {
AudioChunk *chunk = nil;
chunk = [self convert];
if(!chunk || ![chunk frameCount]) {
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
endOfStream = YES;
break;
}
if(paused || !streamFormatChanged) {
continue;
}
usleep(500);
} else {
[self writeChunk:chunk];
chunk = nil;
}
if(streamFormatChanged) {
[self cleanUp];
[self setupWithInputFormat:newInputFormat withInputConfig:newInputChannelConfig outputFormat:self->outputFormat isLossless:rememberedLossless];
}
}
}
endOfStream = YES;
}
- (AudioChunk *)convert {
UInt32 ioNumberPackets;
if(stopping)
return 0;
convertEntered = YES;
if(stopping || [self shouldContinue] == NO) {
convertEntered = NO;
return nil;
}
if(inpOffset == inpSize) {
streamTimestamp = 0.0;
streamTimeRatio = 1.0;
if(![self peekTimestamp:&streamTimestamp timeRatio:&streamTimeRatio]) {
convertEntered = NO;
return nil;
}
}
while(inpOffset == inpSize) {
// Approximately the most we want on input
ioNumberPackets = 4096;
size_t newSize = ioNumberPackets * floatFormat.mBytesPerPacket;
if(!inputBuffer || inputBufferSize < newSize)
inputBuffer = realloc(inputBuffer, inputBufferSize = newSize);
ssize_t amountToWrite = ioNumberPackets * floatFormat.mBytesPerPacket;
ssize_t bytesReadFromInput = 0;
while(bytesReadFromInput < amountToWrite && !stopping && !paused && !streamFormatChanged && [self shouldContinue] == YES && !([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES)) {
AudioStreamBasicDescription inf;
uint32_t config;
if([self peekFormat:&inf channelConfig:&config]) {
if(config != inputChannelConfig || memcmp(&inf, &inputFormat, sizeof(inf)) != 0) {
if(inputChannelConfig == 0 && memcmp(&inf, &inputFormat, sizeof(inf)) == 0) {
inputChannelConfig = config;
continue;
} else {
newInputFormat = inf;
newInputChannelConfig = config;
streamFormatChanged = YES;
break;
}
}
}
AudioChunk *chunk = [self readChunkAsFloat32:((amountToWrite - bytesReadFromInput) / floatFormat.mBytesPerPacket)];
inf = [chunk format];
size_t frameCount = [chunk frameCount];
config = [chunk channelConfig];
size_t bytesRead = frameCount * inf.mBytesPerPacket;
if(frameCount) {
NSData *samples = [chunk removeSamples:frameCount];
memcpy(((uint8_t *)inputBuffer) + bytesReadFromInput, [samples bytes], bytesRead);
if([chunk isHDCD]) {
[controller sustainHDCD];
}
}
bytesReadFromInput += bytesRead;
if(!frameCount) {
usleep(500);
}
}
if(!bytesReadFromInput) {
convertEntered = NO;
return nil;
}
if(stopping || paused || streamFormatChanged || [self shouldContinue] == NO || ([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES)) {
if(!skipResampler) {
if(!is_postextrapolated_) {
is_postextrapolated_ = 1;
}
} else {
is_postextrapolated_ = 3;
}
}
// Extrapolate start
if(!skipResampler && !is_preextrapolated_) {
size_t inputSamples = bytesReadFromInput / floatFormat.mBytesPerPacket;
size_t prime = MIN(inputSamples, PRIME_LEN_);
size_t _N_samples_to_add_ = N_samples_to_add_;
size_t newSize = _N_samples_to_add_ * floatFormat.mBytesPerPacket;
newSize += bytesReadFromInput;
if(newSize > inputBufferSize) {
inputBuffer = realloc(inputBuffer, inputBufferSize = newSize * 3);
}
memmove(inputBuffer + _N_samples_to_add_ * floatFormat.mBytesPerPacket, inputBuffer, bytesReadFromInput);
lpc_extrapolate_bkwd(inputBuffer + _N_samples_to_add_ * floatFormat.mBytesPerPacket, inputSamples, prime, floatFormat.mChannelsPerFrame, LPC_ORDER, _N_samples_to_add_, &extrapolateBuffer, &extrapolateBufferSize);
bytesReadFromInput += _N_samples_to_add_ * floatFormat.mBytesPerPacket;
latencyEaten = N_samples_to_drop_;
is_preextrapolated_ = YES;
}
if(is_postextrapolated_ == 1) {
size_t inputSamples = bytesReadFromInput / floatFormat.mBytesPerPacket;
size_t prime = MIN(inputSamples, PRIME_LEN_);
size_t _N_samples_to_add_ = N_samples_to_add_;
size_t newSize = bytesReadFromInput;
newSize += _N_samples_to_add_ * floatFormat.mBytesPerPacket;
if(newSize > inputBufferSize) {
inputBuffer = realloc(inputBuffer, inputBufferSize = newSize * 3);
}
lpc_extrapolate_fwd(inputBuffer, inputSamples, prime, floatFormat.mChannelsPerFrame, LPC_ORDER, _N_samples_to_add_, &extrapolateBuffer, &extrapolateBufferSize);
bytesReadFromInput += _N_samples_to_add_ * floatFormat.mBytesPerPacket;
latencyEatenPost = N_samples_to_drop_;
is_postextrapolated_ = 2;
} else if(is_postextrapolated_ == 3) {
latencyEatenPost = 0;
}
// Input now contains bytesReadFromInput worth of floats, in the input sample rate
inpSize = bytesReadFromInput;
inpOffset = 0;
}
ioNumberPackets = (UInt32)(inpSize - inpOffset);
ioNumberPackets -= ioNumberPackets % floatFormat.mBytesPerPacket;
if(ioNumberPackets) {
size_t inputSamples = ioNumberPackets / floatFormat.mBytesPerPacket;
ioNumberPackets = (UInt32)inputSamples;
ioNumberPackets = (UInt32)ceil((float)ioNumberPackets * sampleRatio);
ioNumberPackets += soxr_delay(soxr);
ioNumberPackets = (ioNumberPackets + 255) & ~255;
size_t newSize = ioNumberPackets * floatFormat.mBytesPerPacket;
if(!floatBuffer || floatBufferSize < newSize) {
floatBuffer = realloc(floatBuffer, floatBufferSize = newSize * 3);
}
if(stopping) {
convertEntered = NO;
return nil;
}
size_t inputDone = 0;
size_t outputDone = 0;
if(!skipResampler) {
soxr_process(soxr, (float *)(((uint8_t *)inputBuffer) + inpOffset), inputSamples, &inputDone, floatBuffer, ioNumberPackets, &outputDone);
if(latencyEatenPost) {
// Post file or format change flush
size_t idone = 0, odone = 0;
do {
soxr_process(soxr, NULL, 0, &idone, floatBuffer + outputDone * floatFormat.mBytesPerPacket, ioNumberPackets - outputDone, &odone);
outputDone += odone;
} while(odone > 0);
}
} else {
memcpy(floatBuffer, (((uint8_t *)inputBuffer) + inpOffset), inputSamples * floatFormat.mBytesPerPacket);
inputDone = inputSamples;
outputDone = inputSamples;
}
inpOffset += inputDone * floatFormat.mBytesPerPacket;
if(latencyEaten) {
if(outputDone > latencyEaten) {
outputDone -= latencyEaten;
memmove(floatBuffer, floatBuffer + latencyEaten * floatFormat.mBytesPerPacket, outputDone * floatFormat.mBytesPerPacket);
latencyEaten = 0;
} else {
latencyEaten -= outputDone;
outputDone = 0;
}
}
if(latencyEatenPost) {
if(outputDone > latencyEatenPost) {
outputDone -= latencyEatenPost;
} else {
outputDone = 0;
}
latencyEatenPost = 0;
}
ioNumberPackets = (UInt32)outputDone * floatFormat.mBytesPerPacket;
}
if(ioNumberPackets) {
AudioChunk *chunk = [[AudioChunk alloc] init];
[chunk setFormat:nodeFormat];
if(nodeChannelConfig) {
[chunk setChannelConfig:nodeChannelConfig];
}
[self addObservers];
scale_by_volume(floatBuffer, ioNumberPackets / sizeof(float), volumeScale);
[chunk setStreamTimestamp:streamTimestamp];
[chunk setStreamTimeRatio:streamTimeRatio];
[chunk assignSamples:floatBuffer frameCount:ioNumberPackets / floatFormat.mBytesPerPacket];
streamTimestamp += [chunk durationRatioed];
convertEntered = NO;
return chunk;
}
convertEntered = NO;
return nil;
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if(context == kConverterNodeContext) {
DLog(@"SOMETHING CHANGED!");
if([keyPath isEqualToString:@"values.volumeScaling"]) {
// User reset the volume scaling option
[self refreshVolumeScaling];
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
static float db_to_scale(float db) {
return pow(10.0, db / 20);
}
- (void)refreshVolumeScaling {
if(rgInfo == nil) {
volumeScale = 1.0;
return;
}
NSString *scaling = [[NSUserDefaults standardUserDefaults] stringForKey:@"volumeScaling"];
BOOL useAlbum = [scaling hasPrefix:@"albumGain"];
BOOL useTrack = useAlbum || [scaling hasPrefix:@"trackGain"];
BOOL useVolume = useAlbum || useTrack || [scaling isEqualToString:@"volumeScale"];
BOOL usePeak = [scaling hasSuffix:@"WithPeak"];
float scale = 1.0;
float peak = 0.0;
if(useVolume) {
id pVolumeScale = [rgInfo objectForKey:@"volume"];
if(pVolumeScale != nil)
scale = [pVolumeScale floatValue];
}
if(useTrack) {
id trackGain = [rgInfo objectForKey:@"replayGainTrackGain"];
id trackPeak = [rgInfo objectForKey:@"replayGainTrackPeak"];
if(trackGain != nil)
scale = db_to_scale([trackGain floatValue]);
if(trackPeak != nil)
peak = [trackPeak floatValue];
}
if(useAlbum) {
id albumGain = [rgInfo objectForKey:@"replayGainAlbumGain"];
id albumPeak = [rgInfo objectForKey:@"replayGainAlbumPeak"];
if(albumGain != nil)
scale = db_to_scale([albumGain floatValue]);
if(albumPeak != nil)
peak = [albumPeak floatValue];
}
if(usePeak) {
if(scale * peak > 1.0)
scale = 1.0 / peak;
}
volumeScale = scale;
}
- (BOOL)setupWithInputFormat:(AudioStreamBasicDescription)inf withInputConfig:(uint32_t)inputConfig outputFormat:(AudioStreamBasicDescription)outf isLossless:(BOOL)lossless {
// Make the converter
inputFormat = inf;
outputFormat = outf;
inputChannelConfig = inputConfig;
rememberedLossless = lossless;
// These are the only sample formats we support translating
BOOL isFloat = !!(inputFormat.mFormatFlags & kAudioFormatFlagIsFloat);
if((!isFloat && !(inputFormat.mBitsPerChannel >= 1 && inputFormat.mBitsPerChannel <= 32)) || (isFloat && !(inputFormat.mBitsPerChannel == 32 || inputFormat.mBitsPerChannel == 64)))
return NO;
floatFormat = inputFormat;
floatFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
floatFormat.mBitsPerChannel = 32;
floatFormat.mBytesPerFrame = (32 / 8) * floatFormat.mChannelsPerFrame;
floatFormat.mBytesPerPacket = floatFormat.mBytesPerFrame * floatFormat.mFramesPerPacket;
#if DSD_DECIMATE
if(inputFormat.mBitsPerChannel == 1) {
// Decimate this for speed
floatFormat.mSampleRate *= 1.0 / 8.0;
}
#endif
inpOffset = 0;
inpSize = 0;
// This is a post resampler format
nodeFormat = floatFormat;
nodeFormat.mSampleRate = outputFormat.mSampleRate;
nodeChannelConfig = inputChannelConfig;
sampleRatio = (double)outputFormat.mSampleRate / (double)floatFormat.mSampleRate;
skipResampler = fabs(sampleRatio - 1.0) < 1e-7;
if(!skipResampler) {
soxr_quality_spec_t q_spec = soxr_quality_spec(SOXR_HQ, 0);
soxr_io_spec_t io_spec = soxr_io_spec(SOXR_FLOAT32_I, SOXR_FLOAT32_I);
soxr_runtime_spec_t runtime_spec = soxr_runtime_spec(0);
soxr_error_t error;
soxr = soxr_create(floatFormat.mSampleRate, outputFormat.mSampleRate, floatFormat.mChannelsPerFrame, &error, &io_spec, &q_spec, &runtime_spec);
if(error)
return NO;
PRIME_LEN_ = MAX(floatFormat.mSampleRate / 20, 1024u);
PRIME_LEN_ = MIN(PRIME_LEN_, 16384u);
PRIME_LEN_ = MAX(PRIME_LEN_, (unsigned int)(2 * LPC_ORDER + 1));
N_samples_to_add_ = floatFormat.mSampleRate;
N_samples_to_drop_ = outputFormat.mSampleRate;
samples_len(&N_samples_to_add_, &N_samples_to_drop_, 20, 8192u);
is_preextrapolated_ = NO;
is_postextrapolated_ = 0;
}
latencyEaten = 0;
latencyEatenPost = 0;
PrintStreamDesc(&inf);
PrintStreamDesc(&nodeFormat);
[self refreshVolumeScaling];
// Move this here so process call isn't running the resampler until it's allocated
stopping = NO;
convertEntered = NO;
streamFormatChanged = NO;
paused = NO;
return YES;
}
- (void)dealloc {
DLog(@"Converter dealloc");
[self removeObservers];
paused = NO;
[self cleanUp];
[super cleanUp];
}
- (void)setOutputFormat:(AudioStreamBasicDescription)format {
DLog(@"SETTING OUTPUT FORMAT!");
outputFormat = format;
}
- (void)inputFormatDidChange:(AudioStreamBasicDescription)format inputConfig:(uint32_t)inputConfig {
DLog(@"FORMAT CHANGED");
paused = YES;
while(convertEntered) {
usleep(500);
}
[self cleanUp];
[self setupWithInputFormat:format withInputConfig:inputConfig outputFormat:self->outputFormat isLossless:rememberedLossless];
}
- (void)setRGInfo:(NSDictionary *)rgi {
DLog(@"Setting ReplayGain info");
rgInfo = rgi;
[self refreshVolumeScaling];
}
- (void)cleanUp {
stopping = YES;
while(convertEntered) {
usleep(500);
}
if(soxr) {
soxr_delete(soxr);
soxr = NULL;
}
if(extrapolateBuffer) {
free(extrapolateBuffer);
extrapolateBuffer = NULL;
extrapolateBufferSize = 0;
}
if(floatBuffer) {
free(floatBuffer);
floatBuffer = NULL;
floatBufferSize = 0;
}
if(inputBuffer) {
free(inputBuffer);
inputBuffer = NULL;
inputBufferSize = 0;
}
inpOffset = 0;
inpSize = 0;
}
- (double)secondsBuffered {
return [buffer listDuration];
}
@end

View file

@ -0,0 +1,34 @@
//
// DSPDownmixNode.h
// CogAudio
//
// Created by Christopher Snowhill on 2/13/25.
//
#ifndef DSPDownmixNode_h
#define DSPDownmixNode_h
#import <AudioToolbox/AudioToolbox.h>
#import <CogAudio/DSPNode.h>
@interface DSPDownmixNode : DSPNode {
}
- (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p latency:(double)latency;
- (BOOL)setup;
- (void)cleanUp;
- (void)resetBuffer;
- (BOOL)paused;
- (void)process;
- (AudioChunk * _Nullable)convert;
- (void)setOutputFormat:(AudioStreamBasicDescription)format withChannelConfig:(uint32_t)config;
@end
#endif /* DSPDownmixNode_h */

View file

@ -0,0 +1,201 @@
//
// DSPDownmixNode.m
// CogAudio Framework
//
// Created by Christopher Snowhill on 2/13/25.
//
#import <Foundation/Foundation.h>
#import "Downmix.h"
#import "Logging.h"
#import "DSPDownmixNode.h"
@implementation DSPDownmixNode {
DownmixProcessor *downmix;
BOOL stopping, paused;
BOOL processEntered;
BOOL formatSet;
AudioStreamBasicDescription lastInputFormat;
AudioStreamBasicDescription inputFormat;
AudioStreamBasicDescription outputFormat;
uint32_t lastInputChannelConfig, inputChannelConfig;
uint32_t outputChannelConfig;
float outBuffer[4096 * 32];
}
- (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p latency:(double)latency {
self = [super initWithController:c previous:p latency:latency];
return self;
}
- (void)dealloc {
DLog(@"Downmix dealloc");
[self setShouldContinue:NO];
[self cleanUp];
[super cleanUp];
}
- (BOOL)fullInit {
if(formatSet) {
downmix = [[DownmixProcessor alloc] initWithInputFormat:inputFormat inputConfig:inputChannelConfig andOutputFormat:outputFormat outputConfig:outputChannelConfig];
if(!downmix) {
return NO;
}
}
return YES;
}
- (void)fullShutdown {
downmix = nil;
}
- (BOOL)setup {
if(stopping)
return NO;
[self fullShutdown];
return [self fullInit];
}
- (void)cleanUp {
stopping = YES;
while(processEntered) {
usleep(500);
}
[self fullShutdown];
formatSet = NO;
}
- (void)resetBuffer {
paused = YES;
while(processEntered) {
usleep(500);
}
[buffer reset];
paused = NO;
}
- (void)setOutputFormat:(AudioStreamBasicDescription)format withChannelConfig:(uint32_t)config {
if(memcmp(&outputFormat, &format, sizeof(outputFormat)) != 0 ||
outputChannelConfig != config) {
paused = YES;
while(processEntered) {
usleep(500);
}
[buffer reset];
[self fullShutdown];
paused = NO;
}
outputFormat = format;
outputChannelConfig = config;
formatSet = YES;
}
- (BOOL)paused {
return paused;
}
- (void)process {
while([self shouldContinue] == YES) {
if(paused || endOfStream) {
usleep(500);
continue;
}
@autoreleasepool {
AudioChunk *chunk = nil;
chunk = [self convert];
if(!chunk || ![chunk frameCount]) {
if([previousNode endOfStream] == YES) {
usleep(500);
endOfStream = YES;
continue;
}
if(paused) {
continue;
}
usleep(500);
} else {
[self writeChunk:chunk];
chunk = nil;
}
}
}
}
- (AudioChunk *)convert {
if(stopping)
return nil;
processEntered = YES;
if(stopping || ([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) || [self shouldContinue] == NO) {
processEntered = NO;
return nil;
}
if(![self peekFormat:&inputFormat channelConfig:&inputChannelConfig]) {
processEntered = NO;
return nil;
}
if(!inputFormat.mSampleRate ||
!inputFormat.mBitsPerChannel ||
!inputFormat.mChannelsPerFrame ||
!inputFormat.mBytesPerFrame ||
!inputFormat.mFramesPerPacket ||
!inputFormat.mBytesPerPacket) {
processEntered = NO;
return nil;
}
if((formatSet && !downmix) ||
memcmp(&inputFormat, &lastInputFormat, sizeof(inputFormat)) != 0 ||
inputChannelConfig != lastInputChannelConfig) {
lastInputFormat = inputFormat;
lastInputChannelConfig = inputChannelConfig;
[self fullShutdown];
if(formatSet && ![self setup]) {
processEntered = NO;
return nil;
}
}
if(!downmix) {
processEntered = NO;
return [self readChunk:4096];
}
AudioChunk *chunk = [self readChunkAsFloat32:4096];
if(!chunk || ![chunk frameCount]) {
processEntered = NO;
return nil;
}
double streamTimestamp = [chunk streamTimestamp];
size_t frameCount = [chunk frameCount];
NSData *sampleData = [chunk removeSamples:frameCount];
[downmix process:[sampleData bytes] frameCount:frameCount output:&outBuffer[0]];
AudioChunk *outputChunk = [[AudioChunk alloc] init];
[outputChunk setFormat:outputFormat];
if(outputChannelConfig) {
[outputChunk setChannelConfig:outputChannelConfig];
}
if([chunk isHDCD]) [outputChunk setHDCD];
[outputChunk setStreamTimestamp:streamTimestamp];
[outputChunk setStreamTimeRatio:[chunk streamTimeRatio]];
[outputChunk assignSamples:&outBuffer[0] frameCount:frameCount];
processEntered = NO;
return outputChunk;
}
@end

View file

@ -0,0 +1,31 @@
//
// DSPEqualizerNode.h
// CogAudio
//
// Created by Christopher Snowhill on 2/11/25.
//
#ifndef DSPEqualizerNode_h
#define DSPEqualizerNode_h
#import <CogAudio/DSPNode.h>
@interface DSPEqualizerNode : DSPNode {
float *samplePtr;
}
- (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p latency:(double)latency;
- (BOOL)setup;
- (void)cleanUp;
- (void)resetBuffer;
- (BOOL)paused;
- (void)process;
- (AudioChunk * _Nullable)convert;
@end
#endif /* DSPEqualizerNode_h */

View file

@ -0,0 +1,401 @@
//
// DSPEqualizerNode.m
// CogAudio Framework
//
// Created by Christopher Snowhill on 2/11/25.
//
#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AudioUnit/AudioUnit.h>
#import <Accelerate/Accelerate.h>
#import "DSPEqualizerNode.h"
#import "OutputNode.h"
#import "Logging.h"
#import "AudioPlayer.h"
extern void scale_by_volume(float *buffer, size_t count, float volume);
static void * kDSPEqualizerNodeContext = &kDSPEqualizerNodeContext;
@implementation DSPEqualizerNode {
BOOL enableEqualizer;
BOOL equalizerInitialized;
double equalizerPreamp;
__weak AudioPlayer *audioPlayer;
AudioUnit _eq;
AudioTimeStamp timeStamp;
BOOL stopping, paused;
BOOL processEntered;
BOOL observersapplied;
AudioStreamBasicDescription lastInputFormat;
AudioStreamBasicDescription inputFormat;
uint32_t lastInputChannelConfig, inputChannelConfig;
uint32_t outputChannelConfig;
float inBuffer[4096 * 32];
float eqBuffer[4096 * 32];
float outBuffer[4096 * 32];
}
static void fillBuffers(AudioBufferList *ioData, const float *inbuffer, size_t count, size_t offset) {
const size_t channels = ioData->mNumberBuffers;
for(int i = 0; i < channels; ++i) {
const size_t maxCount = (ioData->mBuffers[i].mDataByteSize / sizeof(float)) - offset;
float *output = ((float *)ioData->mBuffers[i].mData) + offset;
const float *input = inbuffer + i;
cblas_scopy((int)((count > maxCount) ? maxCount : count), input, (int)channels, output, 1);
ioData->mBuffers[i].mNumberChannels = 1;
}
}
static void clearBuffers(AudioBufferList *ioData, size_t count, size_t offset) {
for(int i = 0; i < ioData->mNumberBuffers; ++i) {
memset((uint8_t *)ioData->mBuffers[i].mData + offset * sizeof(float), 0, count * sizeof(float));
ioData->mBuffers[i].mNumberChannels = 1;
}
}
static OSStatus eqRenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) {
if(inNumberFrames > 4096 || !inRefCon) {
clearBuffers(ioData, inNumberFrames, 0);
return 0;
}
DSPEqualizerNode *_self = (__bridge DSPEqualizerNode *)inRefCon;
fillBuffers(ioData, _self->samplePtr, inNumberFrames, 0);
return 0;
}
- (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p latency:(double)latency {
self = [super initWithController:c previous:p latency:latency];
if(self) {
NSUserDefaults *defaults = [[NSUserDefaultsController sharedUserDefaultsController] defaults];
enableEqualizer = [defaults boolForKey:@"GraphicEQenable"];
float preamp = [defaults floatForKey:@"eqPreamp"];
equalizerPreamp = pow(10.0, preamp / 20.0);
OutputNode *outputNode = c;
audioPlayer = [outputNode controller];
[self addObservers];
}
return self;
}
- (void)dealloc {
DLog(@"Equalizer dealloc");
[self setShouldContinue:NO];
[self cleanUp];
[self removeObservers];
[super cleanUp];
}
- (void)addObservers {
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.GraphicEQenable" options:0 context:kDSPEqualizerNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.eqPreamp" options:0 context:kDSPEqualizerNodeContext];
observersapplied = YES;
}
- (void)removeObservers {
if(observersapplied) {
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.GraphicEQenable" context:kDSPEqualizerNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.eqPreamp" context:kDSPEqualizerNodeContext];
observersapplied = NO;
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if(context != kDSPEqualizerNodeContext) {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
return;
}
if([keyPath isEqualToString:@"values.GraphicEQenable"]) {
NSUserDefaults *defaults = [[NSUserDefaultsController sharedUserDefaultsController] defaults];
enableEqualizer = [defaults boolForKey:@"GraphicEQenable"];
} else if([keyPath isEqualToString:@"values.eqPreamp"]) {
NSUserDefaults *defaults = [[NSUserDefaultsController sharedUserDefaultsController] defaults];
float preamp = [defaults floatForKey:@"eqPreamp"];
equalizerPreamp = pow(10.0, preamp / 20.0);
}
}
- (AudioPlayer *)audioPlayer {
return audioPlayer;
}
- (BOOL)fullInit {
if(enableEqualizer) {
AudioComponentDescription desc;
NSError *err;
desc.componentType = kAudioUnitType_Effect;
desc.componentSubType = kAudioUnitSubType_GraphicEQ;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
AudioComponent comp = NULL;
comp = AudioComponentFindNext(comp, &desc);
if(!comp) {
return NO;
}
OSStatus _err = AudioComponentInstanceNew(comp, &_eq);
if(err) {
return NO;
}
UInt32 value;
UInt32 size = sizeof(value);
value = 4096;
AudioUnitSetProperty(_eq, kAudioUnitProperty_MaximumFramesPerSlice,
kAudioUnitScope_Global, 0, &value, size);
value = 127;
AudioUnitSetProperty(_eq, kAudioUnitProperty_RenderQuality,
kAudioUnitScope_Global, 0, &value, size);
AURenderCallbackStruct callbackStruct;
callbackStruct.inputProcRefCon = (__bridge void *)self;
callbackStruct.inputProc = eqRenderCallback;
AudioUnitSetProperty(_eq, kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input, 0, &callbackStruct, sizeof(callbackStruct));
AudioUnitReset(_eq, kAudioUnitScope_Input, 0);
AudioUnitReset(_eq, kAudioUnitScope_Output, 0);
AudioUnitReset(_eq, kAudioUnitScope_Global, 0);
AudioStreamBasicDescription asbd = inputFormat;
// Of course, non-interleaved has only one sample per frame/packet, per buffer
asbd.mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
asbd.mBytesPerFrame = sizeof(float);
asbd.mBytesPerPacket = sizeof(float);
asbd.mFramesPerPacket = 1;
UInt32 maximumFrames = 4096;
AudioUnitSetProperty(_eq, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maximumFrames, sizeof(maximumFrames));
AudioUnitSetProperty(_eq, kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input, 0, &asbd, sizeof(asbd));
AudioUnitSetProperty(_eq, kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output, 0, &asbd, sizeof(asbd));
AudioUnitReset(_eq, kAudioUnitScope_Input, 0);
AudioUnitReset(_eq, kAudioUnitScope_Output, 0);
AudioUnitReset(_eq, kAudioUnitScope_Global, 0);
_err = AudioUnitInitialize(_eq);
if(_err != noErr) {
return NO;
}
bzero(&timeStamp, sizeof(timeStamp));
timeStamp.mFlags = kAudioTimeStampSampleTimeValid;
equalizerInitialized = YES;
[[self audioPlayer] beginEqualizer:_eq];
}
return YES;
}
- (void)fullShutdown {
if(_eq) {
if(equalizerInitialized) {
[[self audioPlayer] endEqualizer:_eq];
AudioUnitUninitialize(_eq);
equalizerInitialized = NO;
}
AudioComponentInstanceDispose(_eq);
_eq = NULL;
}
}
- (BOOL)setup {
if(stopping)
return NO;
[self fullShutdown];
return [self fullInit];
}
- (void)cleanUp {
stopping = YES;
while(processEntered) {
usleep(500);
}
[self fullShutdown];
}
- (void)resetBuffer {
paused = YES;
while(processEntered) {
usleep(500);
}
[buffer reset];
[self fullShutdown];
paused = NO;
}
- (BOOL)paused {
return paused;
}
- (void)process {
while([self shouldContinue] == YES) {
if(paused || endOfStream) {
usleep(500);
continue;
}
@autoreleasepool {
AudioChunk *chunk = nil;
chunk = [self convert];
if(!chunk || ![chunk frameCount]) {
if([previousNode endOfStream] == YES) {
usleep(500);
endOfStream = YES;
continue;
}
if(paused) {
continue;
}
usleep(500);
} else {
[self writeChunk:chunk];
chunk = nil;
}
if(!enableEqualizer && equalizerInitialized) {
[self fullShutdown];
}
}
}
}
- (AudioChunk *)convert {
if(stopping)
return nil;
processEntered = YES;
if(stopping || ([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) || [self shouldContinue] == NO) {
processEntered = NO;
return nil;
}
if(![self peekFormat:&inputFormat channelConfig:&inputChannelConfig]) {
processEntered = NO;
return nil;
}
if(!inputFormat.mSampleRate ||
!inputFormat.mBitsPerChannel ||
!inputFormat.mChannelsPerFrame ||
!inputFormat.mBytesPerFrame ||
!inputFormat.mFramesPerPacket ||
!inputFormat.mBytesPerPacket) {
processEntered = NO;
return nil;
}
if((enableEqualizer && !equalizerInitialized) ||
memcmp(&inputFormat, &lastInputFormat, sizeof(inputFormat)) != 0 ||
inputChannelConfig != lastInputChannelConfig) {
lastInputFormat = inputFormat;
lastInputChannelConfig = inputChannelConfig;
[self fullShutdown];
if(enableEqualizer && ![self setup]) {
processEntered = NO;
return nil;
}
}
if(!equalizerInitialized) {
processEntered = NO;
return [self readChunk:4096];
}
AudioChunk *chunk = [self readChunkAsFloat32:4096];
if(!chunk || ![chunk frameCount]) {
processEntered = NO;
return nil;
}
double streamTimestamp = [chunk streamTimestamp];
samplePtr = &inBuffer[0];
size_t channels = inputFormat.mChannelsPerFrame;
size_t frameCount = [chunk frameCount];
NSData *sampleData = [chunk removeSamples:frameCount];
cblas_scopy((int)(frameCount * channels), [sampleData bytes], 1, &inBuffer[0], 1);
const size_t channelsminusone = channels - 1;
uint8_t tempBuffer[sizeof(AudioBufferList) + sizeof(AudioBuffer) * channelsminusone];
AudioBufferList *ioData = (AudioBufferList *)&tempBuffer[0];
ioData->mNumberBuffers = (UInt32)channels;
for(size_t i = 0; i < channels; ++i) {
ioData->mBuffers[i].mData = &eqBuffer[4096 * i];
ioData->mBuffers[i].mDataByteSize = (UInt32)(frameCount * sizeof(float));
ioData->mBuffers[i].mNumberChannels = 1;
}
OSStatus status = AudioUnitRender(_eq, NULL, &timeStamp, 0, (UInt32)frameCount, ioData);
if(status != noErr) {
processEntered = NO;
return nil;
}
timeStamp.mSampleTime += ((double)frameCount) / inputFormat.mSampleRate;
for(int i = 0; i < channels; ++i) {
cblas_scopy((int)frameCount, &eqBuffer[4096 * i], 1, &outBuffer[i], (int)channels);
}
AudioChunk *outputChunk = nil;
if(frameCount) {
scale_by_volume(&outBuffer[0], frameCount * channels, equalizerPreamp);
outputChunk = [[AudioChunk alloc] init];
[outputChunk setFormat:inputFormat];
if(outputChannelConfig) {
[outputChunk setChannelConfig:inputChannelConfig];
}
if([chunk isHDCD]) [outputChunk setHDCD];
[outputChunk setStreamTimestamp:streamTimestamp];
[outputChunk setStreamTimeRatio:[chunk streamTimeRatio]];
[outputChunk assignSamples:&outBuffer[0] frameCount:frameCount];
}
processEntered = NO;
return outputChunk;
}
@end

View file

@ -0,0 +1,30 @@
//
// DSPFSurroundNode.h
// CogAudio
//
// Created by Christopher Snowhill on 2/11/25.
//
#ifndef DSPFSurroundNode_h
#define DSPFSurroundNode_h
#import <CogAudio/DSPNode.h>
@interface DSPFSurroundNode : DSPNode {
}
- (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p latency:(double)latency;
- (BOOL)setup;
- (void)cleanUp;
- (void)resetBuffer;
- (BOOL)paused;
- (void)process;
- (AudioChunk * _Nullable)convert;
@end
#endif /* DSPFSurroundNode_h */

View file

@ -0,0 +1,275 @@
//
// DSPFSurroundNode.m
// CogAudio Framework
//
// Created by Christopher Snowhill on 2/11/25.
//
#import <Foundation/Foundation.h>
#import <Accelerate/Accelerate.h>
#import "DSPFSurroundNode.h"
#import "Logging.h"
#import "FSurroundFilter.h"
#define OCTAVES 5
static void * kDSPFSurroundNodeContext = &kDSPFSurroundNodeContext;
@implementation DSPFSurroundNode {
BOOL enableFSurround;
BOOL FSurroundDelayRemoved;
FSurroundFilter *fsurround;
BOOL stopping, paused;
BOOL processEntered;
BOOL observersapplied;
AudioStreamBasicDescription lastInputFormat;
AudioStreamBasicDescription inputFormat;
AudioStreamBasicDescription outputFormat;
uint32_t lastInputChannelConfig, inputChannelConfig;
uint32_t outputChannelConfig;
float inBuffer[4096 * 2];
float outBuffer[8192 * 6];
}
- (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p latency:(double)latency {
self = [super initWithController:c previous:p latency:latency];
if(self) {
NSUserDefaults *defaults = [[NSUserDefaultsController sharedUserDefaultsController] defaults];
enableFSurround = [defaults boolForKey:@"enableFSurround"];
[self addObservers];
}
return self;
}
- (void)dealloc {
DLog(@"FreeSurround dealloc");
[self setShouldContinue:NO];
[self cleanUp];
[self removeObservers];
[super cleanUp];
}
- (void)addObservers {
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.enableFSurround" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kDSPFSurroundNodeContext];
observersapplied = YES;
}
- (void)removeObservers {
if(observersapplied) {
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.enableFSurround" context:kDSPFSurroundNodeContext];
observersapplied = NO;
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if(context != kDSPFSurroundNodeContext) {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
return;
}
if([keyPath isEqualToString:@"values.enableFSurround"]) {
NSUserDefaults *defaults = [[NSUserDefaultsController sharedUserDefaultsController] defaults];
enableFSurround = [defaults boolForKey:@"enableFSurround"];
}
}
- (BOOL)fullInit {
if(enableFSurround && inputFormat.mChannelsPerFrame == 2) {
fsurround = [[FSurroundFilter alloc] initWithSampleRate:inputFormat.mSampleRate];
if(!fsurround) {
return NO;
}
outputFormat = inputFormat;
outputFormat.mChannelsPerFrame = [fsurround channelCount];
outputFormat.mBytesPerFrame = sizeof(float) * outputFormat.mChannelsPerFrame;
outputFormat.mBytesPerPacket = outputFormat.mBytesPerFrame * outputFormat.mFramesPerPacket;
outputChannelConfig = [fsurround channelConfig];
FSurroundDelayRemoved = NO;
} else {
fsurround = nil;
}
return YES;
}
- (void)fullShutdown {
fsurround = nil;
}
- (BOOL)setup {
if(stopping)
return NO;
[self fullShutdown];
return [self fullInit];
}
- (void)cleanUp {
stopping = YES;
while(processEntered) {
usleep(500);
}
[self fullShutdown];
}
- (void)resetBuffer {
paused = YES;
while(processEntered) {
usleep(500);
}
[buffer reset];
[self fullShutdown];
paused = NO;
}
- (BOOL)paused {
return paused;
}
- (void)process {
while([self shouldContinue] == YES) {
if(paused || endOfStream) {
usleep(500);
continue;
}
@autoreleasepool {
AudioChunk *chunk = nil;
chunk = [self convert];
if(!chunk || ![chunk frameCount]) {
if([previousNode endOfStream] == YES) {
usleep(500);
endOfStream = YES;
continue;
}
if(paused) {
continue;
}
usleep(500);
} else {
[self writeChunk:chunk];
chunk = nil;
}
if(!enableFSurround && fsurround) {
[self fullShutdown];
}
}
}
}
- (AudioChunk *)convert {
if(stopping)
return nil;
processEntered = YES;
if(stopping || ([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) || [self shouldContinue] == NO) {
processEntered = NO;
return nil;
}
if(![self peekFormat:&inputFormat channelConfig:&inputChannelConfig]) {
processEntered = NO;
return nil;
}
if(!inputFormat.mSampleRate ||
!inputFormat.mBitsPerChannel ||
!inputFormat.mChannelsPerFrame ||
!inputFormat.mBytesPerFrame ||
!inputFormat.mFramesPerPacket ||
!inputFormat.mBytesPerPacket) {
processEntered = NO;
return nil;
}
if((enableFSurround && !fsurround) ||
memcmp(&inputFormat, &lastInputFormat, sizeof(inputFormat)) != 0 ||
inputChannelConfig != lastInputChannelConfig) {
lastInputFormat = inputFormat;
lastInputChannelConfig = inputChannelConfig;
[self fullShutdown];
if(enableFSurround && ![self setup]) {
processEntered = NO;
return nil;
}
}
if(!fsurround) {
processEntered = NO;
return [self readChunk:4096];
}
size_t totalRequestedSamples = 4096;
size_t totalFrameCount = 0;
AudioChunk *chunk = [self readAndMergeChunksAsFloat32:totalRequestedSamples];
if(!chunk || ![chunk frameCount]) {
processEntered = NO;
return nil;
}
double streamTimestamp = [chunk streamTimestamp];
float *samplePtr = &inBuffer[0];
size_t frameCount = [chunk frameCount];
NSData *sampleData = [chunk removeSamples:frameCount];
cblas_scopy((int)frameCount * 2, [sampleData bytes], 1, &samplePtr[0], 1);
totalFrameCount = frameCount;
size_t countToProcess = totalFrameCount;
size_t samplesRendered;
if(countToProcess < 4096) {
bzero(&inBuffer[countToProcess * 2], (4096 - countToProcess) * 2 * sizeof(float));
countToProcess = 4096;
}
[fsurround process:&inBuffer[0] output:&outBuffer[0] count:(int)countToProcess];
samplePtr = &outBuffer[0];
samplesRendered = totalFrameCount;
if(totalFrameCount < 4096) {
bzero(&outBuffer[4096 * 6], 4096 * 2 * sizeof(float));
[fsurround process:&outBuffer[4096 * 6] output:&outBuffer[4096 * 6] count:4096];
samplesRendered += 2048;
}
if(!FSurroundDelayRemoved) {
FSurroundDelayRemoved = YES;
if(samplesRendered > 2048) {
samplePtr += 2048 * 6;
samplesRendered -= 2048;
}
}
AudioChunk *outputChunk = nil;
if(samplesRendered) {
outputChunk = [[AudioChunk alloc] init];
[outputChunk setFormat:outputFormat];
if(outputChannelConfig) {
[outputChunk setChannelConfig:outputChannelConfig];
}
if([chunk isHDCD]) [outputChunk setHDCD];
[outputChunk setStreamTimestamp:streamTimestamp];
[outputChunk setStreamTimeRatio:[chunk streamTimeRatio]];
[outputChunk assignSamples:samplePtr frameCount:samplesRendered];
}
processEntered = NO;
return outputChunk;
}
@end

View file

@ -0,0 +1,35 @@
//
// DSPHRTFNode.h
// CogAudio
//
// Created by Christopher Snowhill on 2/11/25.
//
#ifndef DSPHRTFNode_h
#define DSPHRTFNode_h
#import <simd/types.h>
#import <CogAudio/DSPNode.h>
@interface DSPHRTFNode : DSPNode {
}
- (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p latency:(double)latency;
- (BOOL)setup;
- (void)cleanUp;
- (void)resetBuffer;
- (BOOL)paused;
- (void)process;
- (AudioChunk * _Nullable)convert;
- (void)reportMotion:(simd_float4x4)matrix;
- (void)resetReferencePosition:(NSNotification *_Nullable)notification;
@end
#endif /* DSPHRTFNode_h */

View file

@ -0,0 +1,434 @@
//
// DSPHRTFNode.m
// CogAudio Framework
//
// Created by Christopher Snowhill on 2/11/25.
//
#import <Foundation/Foundation.h>
#import <CoreMotion/CoreMotion.h>
#import "Logging.h"
#import "DSPHRTFNode.h"
#import "lpc.h"
#import "HeadphoneFilter.h"
#include <AvailabilityMacros.h>
#if defined(MAC_OS_X_VERSION_14_0) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_14_0
#define MOTION_MANAGER 1
#endif
static void * kDSPHRTFNodeContext = &kDSPHRTFNodeContext;
static NSString *CogPlaybackDidResetHeadTracking = @"CogPlaybackDigResetHeadTracking";
static simd_float4x4 convertMatrix(CMRotationMatrix r) {
simd_float4x4 matrix = {
simd_make_float4(r.m33, -r.m31, r.m32, 0.0f),
simd_make_float4(r.m13, -r.m11, r.m12, 0.0f),
simd_make_float4(r.m23, -r.m21, r.m22, 0.0f),
simd_make_float4(0.0f, 0.0f, 0.0f, 1.0f)
};
return matrix;
}
#ifdef MOTION_MANAGER
static NSLock *motionManagerLock = nil;
API_AVAILABLE(macos(14.0)) static CMHeadphoneMotionManager *motionManager = nil;
static DSPHRTFNode *registeredMotionListener = nil;
#endif
static void registerMotionListener(DSPHRTFNode *listener) {
#ifdef MOTION_MANAGER
if(@available(macOS 14, *)) {
[motionManagerLock lock];
if([motionManager isDeviceMotionActive]) {
[motionManager stopDeviceMotionUpdates];
}
if([motionManager isDeviceMotionAvailable]) {
registeredMotionListener = listener;
[motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) {
if(motion) {
[motionManagerLock lock];
[registeredMotionListener reportMotion:convertMatrix(motion.attitude.rotationMatrix)];
[motionManagerLock unlock];
}
}];
}
[motionManagerLock unlock];
}
#endif
}
static void unregisterMotionListener(void) {
#ifdef MOTION_MANAGER
if(@available(macOS 14, *)) {
[motionManagerLock lock];
if([motionManager isDeviceMotionActive]) {
[motionManager stopDeviceMotionUpdates];
}
registeredMotionListener = nil;
[motionManagerLock unlock];
}
#endif
}
@implementation DSPHRTFNode {
BOOL enableHrtf;
BOOL enableHeadTracking;
BOOL lastEnableHeadTracking;
HeadphoneFilter *hrtf;
BOOL stopping, paused;
BOOL processEntered;
BOOL resetFilter;
size_t needPrefill;
BOOL observersapplied;
AudioStreamBasicDescription lastInputFormat;
AudioStreamBasicDescription inputFormat;
AudioStreamBasicDescription outputFormat;
uint32_t lastInputChannelConfig, inputChannelConfig;
uint32_t outputChannelConfig;
BOOL referenceMatrixSet;
BOOL rotationMatrixUpdated;
simd_float4x4 rotationMatrix;
simd_float4x4 referenceMatrix;
float prefillBuffer[4096 * 32];
float outBuffer[4096 * 2];
void *extrapolate_buffer;
size_t extrapolate_buffer_size;
}
+ (void)initialize {
#ifdef MOTION_MANAGER
motionManagerLock = [[NSLock alloc] init];
if(@available(macOS 14, *)) {
CMAuthorizationStatus status = [CMHeadphoneMotionManager authorizationStatus];
if(status == CMAuthorizationStatusDenied) {
ALog(@"Headphone motion not authorized");
return;
} else if(status == CMAuthorizationStatusAuthorized) {
ALog(@"Headphone motion authorized");
} else if(status == CMAuthorizationStatusRestricted) {
ALog(@"Headphone motion restricted");
} else if(status == CMAuthorizationStatusNotDetermined) {
ALog(@"Headphone motion status not determined; will prompt for access");
}
motionManager = [[CMHeadphoneMotionManager alloc] init];
}
#endif
}
- (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p latency:(double)latency {
self = [super initWithController:c previous:p latency:latency];
if(self) {
NSUserDefaults *defaults = [[NSUserDefaultsController sharedUserDefaultsController] defaults];
enableHrtf = [defaults boolForKey:@"enableHrtf"];
enableHeadTracking = [defaults boolForKey:@"enableHeadTracking"];
rotationMatrix = matrix_identity_float4x4;
[self addObservers];
}
return self;
}
- (void)dealloc {
DLog(@"HRTF dealloc");
[self setShouldContinue:NO];
[self cleanUp];
[self removeObservers];
[super cleanUp];
if(extrapolate_buffer) {
free(extrapolate_buffer);
extrapolate_buffer = NULL;
extrapolate_buffer_size = 0;
}
}
- (void)addObservers {
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.enableHrtf" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kDSPHRTFNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.enableHeadTracking" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kDSPHRTFNodeContext];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resetReferencePosition:) name:CogPlaybackDidResetHeadTracking object:nil];
observersapplied = YES;
}
- (void)removeObservers {
if(observersapplied) {
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.enableHrtf" context:kDSPHRTFNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.enableHeadTracking" context:kDSPHRTFNodeContext];
[[NSNotificationCenter defaultCenter] removeObserver:self name:CogPlaybackDidResetHeadTracking object:nil];
observersapplied = NO;
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if(context != kDSPHRTFNodeContext) {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
return;
}
if([keyPath isEqualToString:@"values.enableHrtf"] ||
[keyPath isEqualToString:@"values.enableHeadTracking"]) {
NSUserDefaults *defaults = [[NSUserDefaultsController sharedUserDefaultsController] defaults];
enableHrtf = [defaults boolForKey:@"enableHrtf"];
enableHeadTracking = [defaults boolForKey:@"enableHeadTracking"];
resetFilter = YES;
}
}
- (BOOL)fullInit {
if(enableHrtf) {
NSURL *presetUrl = [[NSBundle mainBundle] URLForResource:@"SADIE_D02-96000" withExtension:@"mhr"];
rotationMatrixUpdated = NO;
simd_float4x4 matrix;
if(!referenceMatrixSet || !enableHeadTracking) {
referenceMatrixSet = NO;
matrix = matrix_identity_float4x4;
self->referenceMatrix = matrix;
if(enableHeadTracking) {
lastEnableHeadTracking = YES;
registerMotionListener(self);
} else if(lastEnableHeadTracking) {
lastEnableHeadTracking = NO;
unregisterMotionListener();
}
} else {
simd_float4x4 mirrorTransform = {
simd_make_float4(-1.0, 0.0, 0.0, 0.0),
simd_make_float4(0.0, 1.0, 0.0, 0.0),
simd_make_float4(0.0, 0.0, 1.0, 0.0),
simd_make_float4(0.0, 0.0, 0.0, 1.0)
};
matrix = simd_mul(mirrorTransform, rotationMatrix);
matrix = simd_mul(matrix, referenceMatrix);
}
hrtf = [[HeadphoneFilter alloc] initWithImpulseFile:presetUrl forSampleRate:inputFormat.mSampleRate withInputChannels:inputFormat.mChannelsPerFrame withConfig:inputChannelConfig withMatrix:matrix];
if(!hrtf) {
return NO;
}
outputFormat = inputFormat;
outputFormat.mChannelsPerFrame = 2;
outputFormat.mBytesPerFrame = sizeof(float) * outputFormat.mChannelsPerFrame;
outputFormat.mBytesPerPacket = outputFormat.mBytesPerFrame * outputFormat.mFramesPerPacket;
outputChannelConfig = AudioChannelSideLeft | AudioChannelSideRight;
resetFilter = NO;
needPrefill = [hrtf needPrefill];
} else {
if(lastEnableHeadTracking) {
lastEnableHeadTracking = NO;
unregisterMotionListener();
}
referenceMatrixSet = NO;
hrtf = nil;
}
return YES;
}
- (void)fullShutdown {
hrtf = nil;
if(lastEnableHeadTracking) {
lastEnableHeadTracking = NO;
unregisterMotionListener();
}
resetFilter = NO;
}
- (BOOL)setup {
if(stopping)
return NO;
[self fullShutdown];
return [self fullInit];
}
- (void)cleanUp {
stopping = YES;
while(processEntered) {
usleep(500);
}
[self fullShutdown];
}
- (void)resetBuffer {
paused = YES;
while(processEntered) {
usleep(500);
}
[buffer reset];
[self fullShutdown];
paused = NO;
}
- (BOOL)paused {
return paused;
}
- (void)process {
while([self shouldContinue] == YES) {
if(paused || endOfStream) {
usleep(500);
continue;
}
@autoreleasepool {
AudioChunk *chunk = nil;
chunk = [self convert];
if(!chunk || ![chunk frameCount]) {
if([previousNode endOfStream] == YES) {
usleep(500);
endOfStream = YES;
continue;
}
if(paused) {
continue;
}
usleep(500);
} else {
[self writeChunk:chunk];
chunk = nil;
}
if(resetFilter || (!enableHrtf && hrtf)) {
[self fullShutdown];
}
}
}
}
- (AudioChunk *)convert {
if(stopping)
return nil;
processEntered = YES;
if(stopping || ([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) || [self shouldContinue] == NO) {
processEntered = NO;
return nil;
}
if(![self peekFormat:&inputFormat channelConfig:&inputChannelConfig]) {
processEntered = NO;
return nil;
}
if(!inputFormat.mSampleRate ||
!inputFormat.mBitsPerChannel ||
!inputFormat.mChannelsPerFrame ||
!inputFormat.mBytesPerFrame ||
!inputFormat.mFramesPerPacket ||
!inputFormat.mBytesPerPacket) {
processEntered = NO;
return nil;
}
if((enableHrtf && !hrtf) ||
memcmp(&inputFormat, &lastInputFormat, sizeof(inputFormat)) != 0 ||
inputChannelConfig != lastInputChannelConfig) {
lastInputFormat = inputFormat;
lastInputChannelConfig = inputChannelConfig;
[self fullShutdown];
if(enableHrtf && ![self setup]) {
processEntered = NO;
return nil;
}
}
if(!hrtf) {
processEntered = NO;
return [self readChunk:4096];
}
AudioChunk *chunk = [self readChunkAsFloat32:4096];
if(!chunk || ![chunk frameCount]) {
processEntered = NO;
return nil;
}
if(rotationMatrixUpdated) {
rotationMatrixUpdated = NO;
simd_float4x4 mirrorTransform = {
simd_make_float4(-1.0, 0.0, 0.0, 0.0),
simd_make_float4(0.0, 1.0, 0.0, 0.0),
simd_make_float4(0.0, 0.0, 1.0, 0.0),
simd_make_float4(0.0, 0.0, 0.0, 1.0)
};
simd_float4x4 matrix = simd_mul(mirrorTransform, rotationMatrix);
matrix = simd_mul(matrix, referenceMatrix);
[hrtf reloadWithMatrix:matrix];
}
double streamTimestamp = [chunk streamTimestamp];
size_t frameCount = [chunk frameCount];
NSData *sampleData = [chunk removeSamples:frameCount];
if(needPrefill) {
size_t maxToUse = 4096 - needPrefill;
if(maxToUse > frameCount) {
maxToUse = frameCount;
}
size_t channels = inputFormat.mChannelsPerFrame;
memcpy(&prefillBuffer[needPrefill * channels], [sampleData bytes], maxToUse * sizeof(float) * channels);
lpc_extrapolate_bkwd(&prefillBuffer[needPrefill * channels], maxToUse, maxToUse, (int)channels, LPC_ORDER, needPrefill, &extrapolate_buffer, &extrapolate_buffer_size);
[hrtf process:&prefillBuffer[0] sampleCount:(int)needPrefill toBuffer:&outBuffer[0]];
needPrefill = 0;
}
[hrtf process:(const float *)[sampleData bytes] sampleCount:(int)frameCount toBuffer:&outBuffer[0]];
AudioChunk *outputChunk = [[AudioChunk alloc] init];
[outputChunk setFormat:outputFormat];
if(outputChannelConfig) {
[outputChunk setChannelConfig:outputChannelConfig];
}
if([chunk isHDCD]) [outputChunk setHDCD];
[outputChunk setStreamTimestamp:streamTimestamp];
[outputChunk setStreamTimeRatio:[chunk streamTimeRatio]];
[outputChunk assignSamples:&outBuffer[0] frameCount:frameCount];
processEntered = NO;
return outputChunk;
}
- (void)reportMotion:(simd_float4x4)matrix {
rotationMatrix = matrix;
if(!referenceMatrixSet) {
referenceMatrix = simd_inverse(matrix);
referenceMatrixSet = YES;
}
rotationMatrixUpdated = YES;
}
- (void)resetReferencePosition:(NSNotification *)notification {
referenceMatrixSet = NO;
}
@end

View file

@ -0,0 +1,32 @@
//
// DSPRubberbandNode.h
// CogAudio
//
// Created by Christopher Snowhill on 2/10/25.
//
#ifndef DSPRubberbandNode_h
#define DSPRubberbandNode_h
#import <CogAudio/DSPNode.h>
@interface DSPRubberbandNode : DSPNode {
}
- (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p latency:(double)latency;
- (BOOL)setup;
- (void)cleanUp;
- (void)resetBuffer;
- (BOOL)paused;
- (void)process;
- (AudioChunk * _Nullable)convert;
- (double)secondsBuffered;
@end
#endif /* DSPRubberbandNode_h */

View file

@ -0,0 +1,560 @@
//
// DSPRubberbandNode.m
// CogAudio Framework
//
// Created by Christopher Snowhill on 2/10/25.
//
#import <Foundation/Foundation.h>
#import <Accelerate/Accelerate.h>
#import "DSPRubberbandNode.h"
#import "Logging.h"
#import <rubberband/rubberband-c.h>
static void * kDSPRubberbandNodeContext = &kDSPRubberbandNodeContext;
@implementation DSPRubberbandNode {
BOOL enableRubberband;
RubberBandState ts;
RubberBandOptions tslastoptions, tsnewoptions;
size_t tschannels;
ssize_t blockSize, toDrop, samplesBuffered;
BOOL tsapplynewoptions;
BOOL tsrestartengine;
double tempo, pitch;
double lastTempo, lastPitch;
double countIn;
uint64_t countOut;
double streamTimestamp;
double streamTimeRatio;
BOOL isHDCD;
BOOL stopping, paused;
BOOL processEntered;
BOOL flushed;
BOOL observersapplied;
AudioStreamBasicDescription lastInputFormat;
AudioStreamBasicDescription inputFormat;
uint32_t lastInputChannelConfig, inputChannelConfig;
float *rsPtrs[32];
float rsInBuffer[4096 * 32];
float rsOutBuffer[65536 * 32];
}
- (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p latency:(double)latency {
self = [super initWithController:c previous:p latency:latency];
if(self) {
NSUserDefaults *defaults = [[NSUserDefaultsController sharedUserDefaultsController] defaults];
enableRubberband = ![[defaults stringForKey:@"rubberbandEngine"] isEqualToString:@"disabled"];
pitch = [defaults doubleForKey:@"pitch"];
tempo = [defaults doubleForKey:@"tempo"];
lastPitch = pitch;
lastTempo = tempo;
[self addObservers];
}
return self;
}
- (void)dealloc {
DLog(@"Rubber Band dealloc");
[self setShouldContinue:NO];
[self cleanUp];
[self removeObservers];
[super cleanUp];
}
- (void)addObservers {
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.pitch" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kDSPRubberbandNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.tempo" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kDSPRubberbandNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.rubberbandEngine" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kDSPRubberbandNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.rubberbandTransients" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kDSPRubberbandNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.rubberbandDetector" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kDSPRubberbandNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.rubberbandPhase" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kDSPRubberbandNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.rubberbandWindow" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kDSPRubberbandNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.rubberbandSmoothing" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kDSPRubberbandNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.rubberbandFormant" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kDSPRubberbandNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.rubberbandPitch" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kDSPRubberbandNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.rubberbandChannels" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kDSPRubberbandNodeContext];
observersapplied = YES;
}
- (void)removeObservers {
if(observersapplied) {
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.pitch" context:kDSPRubberbandNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.tempo" context:kDSPRubberbandNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.rubberbandEngine" context:kDSPRubberbandNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.rubberbandTransients" context:kDSPRubberbandNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.rubberbandDetector" context:kDSPRubberbandNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.rubberbandPhase" context:kDSPRubberbandNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.rubberbandWindow" context:kDSPRubberbandNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.rubberbandSmoothing" context:kDSPRubberbandNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.rubberbandFormant" context:kDSPRubberbandNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.rubberbandPitch" context:kDSPRubberbandNodeContext];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.rubberbandChannels" context:kDSPRubberbandNodeContext];
observersapplied = NO;
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if(context != kDSPRubberbandNodeContext) {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
return;
}
if([keyPath isEqualToString:@"values.pitch"] ||
[keyPath isEqualToString:@"values.tempo"]) {
NSUserDefaults *defaults = [[NSUserDefaultsController sharedUserDefaultsController] defaults];
pitch = [defaults doubleForKey:@"pitch"];
tempo = [defaults doubleForKey:@"tempo"];
tsapplynewoptions = YES;
} else if([[keyPath substringToIndex:17] isEqualToString:@"values.rubberband"]) {
NSUserDefaults *defaults = [[NSUserDefaultsController sharedUserDefaultsController] defaults];
enableRubberband = ![[defaults stringForKey:@"rubberbandEngine"] isEqualToString:@"disabled"];
if(enableRubberband && ts) {
RubberBandOptions options = [self getRubberbandOptions];
RubberBandOptions changed = options ^ tslastoptions;
if(changed) {
BOOL engineR3 = !!(options & RubberBandOptionEngineFiner);
// Options which require a restart of the engine
const RubberBandOptions mustRestart = RubberBandOptionEngineFaster | RubberBandOptionEngineFiner | RubberBandOptionWindowStandard | RubberBandOptionWindowShort | RubberBandOptionWindowLong | RubberBandOptionSmoothingOff | RubberBandOptionSmoothingOn | (engineR3 ? RubberBandOptionPitchHighSpeed | RubberBandOptionPitchHighQuality | RubberBandOptionPitchHighConsistency : 0) | RubberBandOptionChannelsApart | RubberBandOptionChannelsTogether;
if(changed & mustRestart) {
tsrestartengine = YES;
} else {
tsnewoptions = options;
tsapplynewoptions = YES;
}
}
}
}
}
- (RubberBandOptions)getRubberbandOptions {
RubberBandOptions options = RubberBandOptionProcessRealTime;
NSUserDefaults *defaults = [[NSUserDefaultsController sharedUserDefaultsController] defaults];
NSString *value = [defaults stringForKey:@"rubberbandEngine"];
BOOL engineR3 = NO;
if([value isEqualToString:@"faster"]) {
options |= RubberBandOptionEngineFaster;
} else if([value isEqualToString:@"finer"]) {
options |= RubberBandOptionEngineFiner;
engineR3 = YES;
}
if(!engineR3) {
value = [defaults stringForKey:@"rubberbandTransients"];
if([value isEqualToString:@"crisp"]) {
options |= RubberBandOptionTransientsCrisp;
} else if([value isEqualToString:@"mixed"]) {
options |= RubberBandOptionTransientsMixed;
} else if([value isEqualToString:@"smooth"]) {
options |= RubberBandOptionTransientsSmooth;
}
value = [defaults stringForKey:@"rubberbandDetector"];
if([value isEqualToString:@"compound"]) {
options |= RubberBandOptionDetectorCompound;
} else if([value isEqualToString:@"percussive"]) {
options |= RubberBandOptionDetectorPercussive;
} else if([value isEqualToString:@"soft"]) {
options |= RubberBandOptionDetectorSoft;
}
value = [defaults stringForKey:@"rubberbandPhase"];
if([value isEqualToString:@"laminar"]) {
options |= RubberBandOptionPhaseLaminar;
} else if([value isEqualToString:@"independent"]) {
options |= RubberBandOptionPhaseIndependent;
}
}
value = [defaults stringForKey:@"rubberbandWindow"];
if([value isEqualToString:@"standard"]) {
options |= RubberBandOptionWindowStandard;
} else if([value isEqualToString:@"short"]) {
options |= RubberBandOptionWindowShort;
} else if([value isEqualToString:@"long"]) {
if(engineR3) {
options |= RubberBandOptionWindowStandard;
} else {
options |= RubberBandOptionWindowLong;
}
}
if(!engineR3) {
value = [defaults stringForKey:@"rubberbandSmoothing"];
if([value isEqualToString:@"off"]) {
options |= RubberBandOptionSmoothingOff;
} else if([value isEqualToString:@"on"]) {
options |= RubberBandOptionSmoothingOn;
}
}
value = [defaults stringForKey:@"rubberbandFormant"];
if([value isEqualToString:@"shifted"]) {
options |= RubberBandOptionFormantShifted;
} else if([value isEqualToString:@"preserved"]) {
options |= RubberBandOptionFormantPreserved;
}
value = [defaults stringForKey:@"rubberbandPitch"];
if([value isEqualToString:@"highspeed"]) {
options |= RubberBandOptionPitchHighSpeed;
} else if([value isEqualToString:@"highquality"]) {
options |= RubberBandOptionPitchHighQuality;
} else if([value isEqualToString:@"highconsistency"]) {
options |= RubberBandOptionPitchHighConsistency;
}
value = [defaults stringForKey:@"rubberbandChannels"];
if([value isEqualToString:@"apart"]) {
options |= RubberBandOptionChannelsApart;
} else if([value isEqualToString:@"together"]) {
options |= RubberBandOptionChannelsTogether;
}
return options;
}
- (BOOL)fullInit {
RubberBandOptions options = [self getRubberbandOptions];
tslastoptions = options;
tschannels = inputFormat.mChannelsPerFrame;
ts = rubberband_new(inputFormat.mSampleRate, (int)tschannels, options, 1.0 / tempo, pitch);
if(!ts)
return NO;
blockSize = rubberband_get_process_size_limit(ts);
toDrop = rubberband_get_start_delay(ts);
samplesBuffered = 0;
if(blockSize > 4096)
blockSize = 4096;
rubberband_set_max_process_size(ts, (unsigned int)blockSize);
for(size_t i = 0; i < 32; ++i) {
rsPtrs[i] = &rsInBuffer[4096 * i];
}
ssize_t toPad = rubberband_get_preferred_start_pad(ts);
if(toPad > 0) {
for(size_t i = 0; i < tschannels; ++i) {
memset(rsPtrs[i], 0, 4096 * sizeof(float));
}
while(toPad > 0) {
ssize_t p = toPad;
if(p > blockSize) p = blockSize;
rubberband_process(ts, (const float * const *)rsPtrs, (int)p, false);
toPad -= p;
}
}
tsapplynewoptions = NO;
tsrestartengine = NO;
flushed = NO;
countIn = 0.0;
countOut = 0;
return YES;
}
- (void)partialInit {
if(stopping || paused || !ts) return;
processEntered = YES;
RubberBandOptions changed = tslastoptions ^ tsnewoptions;
if(changed) {
tslastoptions = tsnewoptions;
BOOL engineR3 = !!(tsnewoptions & RubberBandOptionEngineFiner);
const RubberBandOptions transientsmask = RubberBandOptionTransientsCrisp | RubberBandOptionTransientsMixed | RubberBandOptionTransientsSmooth;
const RubberBandOptions detectormask = RubberBandOptionDetectorCompound | RubberBandOptionDetectorPercussive | RubberBandOptionDetectorSoft;
const RubberBandOptions phasemask = RubberBandOptionPhaseLaminar | RubberBandOptionPhaseIndependent;
const RubberBandOptions formantmask = RubberBandOptionFormantShifted | RubberBandOptionFormantPreserved;
const RubberBandOptions pitchmask = RubberBandOptionPitchHighSpeed | RubberBandOptionPitchHighQuality | RubberBandOptionPitchHighConsistency;
if(changed & transientsmask)
rubberband_set_transients_option(ts, tsnewoptions & transientsmask);
if(!engineR3) {
if(changed & detectormask)
rubberband_set_detector_option(ts, tsnewoptions & detectormask);
if(changed & phasemask)
rubberband_set_phase_option(ts, tsnewoptions & phasemask);
}
if(changed & formantmask)
rubberband_set_formant_option(ts, tsnewoptions & formantmask);
if(!engineR3 && (changed & pitchmask))
rubberband_set_pitch_option(ts, tsnewoptions & pitchmask);
}
if(fabs(pitch - lastPitch) > 1e-5 ||
fabs(tempo - lastTempo) > 1e-5) {
lastPitch = pitch;
lastTempo = tempo;
rubberband_set_pitch_scale(ts, pitch);
rubberband_set_time_ratio(ts, 1.0 / tempo);
}
tsapplynewoptions = NO;
processEntered = NO;
}
- (void)fullShutdown {
if(ts) {
rubberband_delete(ts);
ts = NULL;
}
}
- (BOOL)setup {
if(stopping)
return NO;
[self fullShutdown];
return [self fullInit];
}
- (void)cleanUp {
stopping = YES;
while(processEntered) {
usleep(500);
}
[self fullShutdown];
}
- (void)resetBuffer {
paused = YES;
while(processEntered) {
usleep(500);
}
[buffer reset];
[self fullShutdown];
paused = NO;
}
- (BOOL)paused {
return paused;
}
- (void)setPreviousNode:(id)p {
if(previousNode != p) {
paused = YES;
while(processEntered);
previousNode = p;
paused = NO;
}
}
- (void)setEndOfStream:(BOOL)e {
if(endOfStream && !e) {
[self fullShutdown];
}
[super setEndOfStream:e];
flushed = e;
}
- (void)process {
while([self shouldContinue] == YES) {
if(paused || endOfStream) {
usleep(500);
continue;
}
@autoreleasepool {
AudioChunk *chunk = nil;
chunk = [self convert];
if(!chunk || ![chunk frameCount]) {
if(!ts) {
flushed = previousNode && [[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES;
}
if(flushed) {
usleep(500);
endOfStream = YES;
continue;
}
if(paused) {
continue;
}
usleep(500);
} else {
[self writeChunk:chunk];
chunk = nil;
}
if(!enableRubberband && ts) {
[self fullShutdown];
} else if(tsrestartengine) {
[self fullShutdown];
} else if(tsapplynewoptions) {
[self partialInit];
}
}
}
}
- (AudioChunk *)convert {
if(stopping)
return nil;
processEntered = YES;
if(stopping || flushed || !previousNode || ([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) || [self shouldContinue] == NO) {
processEntered = NO;
return nil;
}
if(![self peekFormat:&inputFormat channelConfig:&inputChannelConfig]) {
processEntered = NO;
return nil;
}
if(!inputFormat.mSampleRate ||
!inputFormat.mBitsPerChannel ||
!inputFormat.mChannelsPerFrame ||
!inputFormat.mBytesPerFrame ||
!inputFormat.mFramesPerPacket ||
!inputFormat.mBytesPerPacket) {
processEntered = NO;
return nil;
}
if((enableRubberband && !ts) ||
memcmp(&inputFormat, &lastInputFormat, sizeof(inputFormat)) != 0 ||
inputChannelConfig != lastInputChannelConfig) {
lastInputFormat = inputFormat;
lastInputChannelConfig = inputChannelConfig;
[self fullShutdown];
if(enableRubberband && ![self setup]) {
processEntered = NO;
return nil;
}
}
if(!ts) {
processEntered = NO;
return [self readChunk:4096];
}
ssize_t samplesToProcess = rubberband_get_samples_required(ts);
if(samplesToProcess > blockSize)
samplesToProcess = blockSize;
int channels = (int)(inputFormat.mChannelsPerFrame);
if(samplesToProcess > 0) {
AudioChunk *chunk = [self readAndMergeChunksAsFloat32:samplesToProcess];
if(!chunk || ![chunk frameCount]) {
processEntered = NO;
return nil;
}
streamTimestamp = [chunk streamTimestamp];
streamTimeRatio = [chunk streamTimeRatio];
isHDCD = [chunk isHDCD];
size_t frameCount = [chunk frameCount];
countIn += ((double)frameCount) / tempo;
NSData *sampleData = [chunk removeSamples:frameCount];
for (size_t i = 0; i < channels; ++i) {
cblas_scopy((int)frameCount, ((const float *)[sampleData bytes]) + i, channels, rsPtrs[i], 1);
}
flushed = [[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES;
int len = (int)frameCount;
rubberband_process(ts, (const float * const *)rsPtrs, len, flushed);
}
ssize_t samplesAvailable;
while(!stopping && (samplesAvailable = rubberband_available(ts)) > 0) {
if(toDrop > 0) {
ssize_t blockDrop = toDrop;
if(blockDrop > samplesAvailable) blockDrop = samplesAvailable;
if(blockDrop > blockSize) blockDrop = blockSize;
rubberband_retrieve(ts, (float * const *)rsPtrs, (int)blockDrop);
toDrop -= blockDrop;
continue;
}
ssize_t maxAvailable = 65536 - samplesBuffered;
ssize_t samplesOut = samplesAvailable;
if(samplesOut > maxAvailable) {
samplesOut = maxAvailable;
if(samplesOut <= 0) {
break;
}
}
if(samplesOut > blockSize) samplesOut = blockSize;
rubberband_retrieve(ts, (float * const *)rsPtrs, (int)samplesOut);
for(size_t i = 0; i < channels; ++i) {
cblas_scopy((int)samplesOut, rsPtrs[i], 1, &rsOutBuffer[samplesBuffered * channels + i], channels);
}
samplesBuffered += samplesOut;
}
if(flushed) {
if(samplesBuffered > 0) {
ssize_t ideal = (ssize_t)floor(countIn + 0.5);
if(countOut + samplesBuffered > ideal) {
// Rubber Band does not account for flushing duration in real time mode
samplesBuffered = ideal - countOut;
}
}
}
AudioChunk *outputChunk = nil;
if(samplesBuffered > 0) {
outputChunk = [[AudioChunk alloc] init];
[outputChunk setFormat:inputFormat];
if(inputChannelConfig) {
[outputChunk setChannelConfig:inputChannelConfig];
}
if(isHDCD) [outputChunk setHDCD];
[outputChunk setStreamTimestamp:streamTimestamp];
[outputChunk setStreamTimeRatio:streamTimeRatio * tempo];
[outputChunk assignSamples:&rsOutBuffer[0] frameCount:samplesBuffered];
countOut += samplesBuffered;
samplesBuffered = 0;
double chunkDuration = [outputChunk duration];
streamTimestamp += chunkDuration * [outputChunk streamTimeRatio];
}
processEntered = NO;
return outputChunk;
}
- (double)secondsBuffered {
double rbBuffered = 0.0;
if(ts) {
// We don't use Rubber Band's latency function, because at least in Cog's case,
// by the time we call this function, and also, because it doesn't account for
// how much audio will be lopped off at the end of the process.
//
// Tested once, this tends to be close to zero when actually called.
rbBuffered = countIn - (double)(countOut);
if(rbBuffered < 0) {
rbBuffered = 0.0;
} else {
rbBuffered /= inputFormat.mSampleRate;
}
}
return [buffer listDuration] + rbBuffered;
}
@end

24
Audio/Chain/DSP/Downmix.h Normal file
View file

@ -0,0 +1,24 @@
//
// Downmix.h
// Cog
//
// Created by Christopher Snowhill on 2/05/22.
// Copyright 2022 __LoSnoCo__. All rights reserved.
//
#import <CoreAudio/CoreAudio.h>
#import <Foundation/Foundation.h>
@interface DownmixProcessor : NSObject {
AudioStreamBasicDescription inputFormat;
AudioStreamBasicDescription outputFormat;
uint32_t inConfig;
uint32_t outConfig;
}
- (id)initWithInputFormat:(AudioStreamBasicDescription)inf inputConfig:(uint32_t)iConfig andOutputFormat:(AudioStreamBasicDescription)outf outputConfig:(uint32_t)oConfig;
- (void)process:(const void *)inBuffer frameCount:(size_t)frames output:(void *)outBuffer;
@end

301
Audio/Chain/DSP/Downmix.m Normal file
View file

@ -0,0 +1,301 @@
//
// Downmix.m
// Cog
//
// Created by Christopher Snowhill on 2/05/22.
// Copyright 2022 __LoSnoCo__. All rights reserved.
//
#import "Downmix.h"
#import "Logging.h"
#import "AudioChunk.h"
#import <Accelerate/Accelerate.h>
static void downmix_to_stereo(const float *inBuffer, int channels, uint32_t config, float *outBuffer, size_t count) {
float FrontRatios[2] = { 0.0F, 0.0F };
float FrontCenterRatio = 0.0F;
float LFERatio = 0.0F;
float BackRatios[2] = { 0.0F, 0.0F };
float BackCenterRatio = 0.0F;
float SideRatios[2] = { 0.0F, 0.0F };
if(config & (AudioChannelFrontLeft | AudioChannelFrontRight)) {
FrontRatios[0] = 1.0F;
}
if(config & AudioChannelFrontCenter) {
FrontRatios[0] = 0.5858F;
FrontCenterRatio = 0.4142F;
}
if(config & (AudioChannelBackLeft | AudioChannelBackRight)) {
if(config & AudioChannelFrontCenter) {
FrontRatios[0] = 0.651F;
FrontCenterRatio = 0.46F;
BackRatios[0] = 0.5636F;
BackRatios[1] = 0.3254F;
} else {
FrontRatios[0] = 0.4226F;
BackRatios[0] = 0.366F;
BackRatios[1] = 0.2114F;
}
}
if(config & AudioChannelLFE) {
FrontRatios[0] *= 0.8F;
FrontCenterRatio *= 0.8F;
LFERatio = FrontCenterRatio;
BackRatios[0] *= 0.8F;
BackRatios[1] *= 0.8F;
}
if(config & AudioChannelBackCenter) {
FrontRatios[0] *= 0.86F;
FrontCenterRatio *= 0.86F;
LFERatio *= 0.86F;
BackRatios[0] *= 0.86F;
BackRatios[1] *= 0.86F;
BackCenterRatio = FrontCenterRatio * 0.86F;
}
if(config & (AudioChannelSideLeft | AudioChannelSideRight)) {
float ratio = 0.73F;
if(config & AudioChannelBackCenter) ratio = 0.85F;
FrontRatios[0] *= ratio;
FrontCenterRatio *= ratio;
LFERatio *= ratio;
BackRatios[0] *= ratio;
BackRatios[1] *= ratio;
BackCenterRatio *= ratio;
SideRatios[0] = 0.463882352941176 * ratio;
SideRatios[1] = 0.267882352941176 * ratio;
}
int32_t channelIndexes[channels];
for(int i = 0; i < channels; ++i) {
channelIndexes[i] = [AudioChunk findChannelIndex:[AudioChunk extractChannelFlag:i fromConfig:config]];
}
vDSP_vclr(outBuffer, 1, count * 2);
float tempBuffer[count * 2];
for(uint32_t i = 0; i < channels; ++i) {
float leftRatio = 0.0F;
float rightRatio = 0.0F;
switch(channelIndexes[i]) {
case 0:
leftRatio = FrontRatios[0];
rightRatio = FrontRatios[1];
break;
case 1:
leftRatio = FrontRatios[1];
rightRatio = FrontRatios[0];
break;
case 2:
leftRatio = FrontCenterRatio;
rightRatio = FrontCenterRatio;
break;
case 3:
leftRatio = LFERatio;
rightRatio = LFERatio;
break;
case 4:
leftRatio = BackRatios[0];
rightRatio = BackRatios[1];
break;
case 5:
leftRatio = BackRatios[1];
rightRatio = BackRatios[0];
break;
case 6:
case 7:
break;
case 8:
leftRatio = BackCenterRatio;
rightRatio = BackCenterRatio;
break;
case 9:
leftRatio = SideRatios[0];
rightRatio = SideRatios[1];
break;
case 10:
leftRatio = SideRatios[1];
rightRatio = SideRatios[0];
break;
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
default:
break;
}
vDSP_vsmul(inBuffer + i, channels, &leftRatio, tempBuffer, 1, count);
vDSP_vsmul(inBuffer + i, channels, &rightRatio, tempBuffer + count, 1, count);
vDSP_vadd(outBuffer, 2, tempBuffer, 1, outBuffer, 2, count);
vDSP_vadd(outBuffer + 1, 2, tempBuffer + count, 1, outBuffer + 1, 2, count);
}
}
static void downmix_to_mono(const float *inBuffer, int channels, uint32_t config, float *outBuffer, size_t count) {
float tempBuffer[count * 2];
if(channels > 2 || config != AudioConfigStereo) {
downmix_to_stereo(inBuffer, channels, config, tempBuffer, count);
inBuffer = tempBuffer;
channels = 2;
config = AudioConfigStereo;
}
cblas_scopy((int)count, inBuffer, 2, outBuffer, 1);
vDSP_vadd(outBuffer, 1, inBuffer + 1, 2, outBuffer, 1, count);
}
static void upmix(const float *inBuffer, int inchannels, uint32_t inconfig, float *outBuffer, int outchannels, uint32_t outconfig, size_t count) {
if(inconfig == AudioConfigMono && outconfig == AudioConfigStereo) {
cblas_scopy((int)count, inBuffer, 1, outBuffer, 2);
cblas_scopy((int)count, inBuffer, 1, outBuffer + 1, 2);
} else if(inconfig == AudioConfigMono && outconfig == AudioConfig4Point0) {
cblas_scopy((int)count, inBuffer, 1, outBuffer, 4);
cblas_scopy((int)count, inBuffer, 1, outBuffer + 1, 4);
vDSP_vclr(outBuffer + 2, 4, count);
vDSP_vclr(outBuffer + 3, 4, count);
} else if(inconfig == AudioConfigMono && (outconfig & AudioChannelFrontCenter)) {
uint32_t cIndex = [AudioChunk channelIndexFromConfig:outconfig forFlag:AudioChannelFrontCenter];
cblas_scopy((int)count, inBuffer, 1, outBuffer + cIndex, outchannels);
for(size_t i = 0; i < cIndex; ++i) {
vDSP_vclr(outBuffer + i, outchannels, (int)count);
}
for(size_t i = cIndex + 1; i < outchannels; ++i) {
vDSP_vclr(outBuffer + i, outchannels, (int)count);
}
} else if(inconfig == AudioConfig4Point0 && outchannels >= 5) {
uint32_t flIndex = [AudioChunk channelIndexFromConfig:outconfig forFlag:AudioChannelFrontLeft];
uint32_t frIndex = [AudioChunk channelIndexFromConfig:outconfig forFlag:AudioChannelFrontRight];
uint32_t blIndex = [AudioChunk channelIndexFromConfig:outconfig forFlag:AudioChannelBackLeft];
uint32_t brIndex = [AudioChunk channelIndexFromConfig:outconfig forFlag:AudioChannelBackRight];
vDSP_vclr(outBuffer, 1, count * outchannels);
if(flIndex != ~0)
cblas_scopy((int)count, inBuffer + 0, 4, outBuffer + flIndex, outchannels);
if(frIndex != ~0)
cblas_scopy((int)count, inBuffer + 1, 4, outBuffer + frIndex, outchannels);
if(blIndex != ~0)
cblas_scopy((int)count, inBuffer + 2, 4, outBuffer + blIndex, outchannels);
if(brIndex != ~0)
cblas_scopy((int)count, inBuffer + 3, 4, outBuffer + brIndex, outchannels);
} else if(inconfig == AudioConfig5Point0 && outchannels >= 6) {
uint32_t flIndex = [AudioChunk channelIndexFromConfig:outconfig forFlag:AudioChannelFrontLeft];
uint32_t frIndex = [AudioChunk channelIndexFromConfig:outconfig forFlag:AudioChannelFrontRight];
uint32_t cIndex = [AudioChunk channelIndexFromConfig:outconfig forFlag:AudioChannelFrontCenter];
uint32_t blIndex = [AudioChunk channelIndexFromConfig:outconfig forFlag:AudioChannelBackLeft];
uint32_t brIndex = [AudioChunk channelIndexFromConfig:outconfig forFlag:AudioChannelBackRight];
vDSP_vclr(outBuffer, 1, count * outchannels);
if(flIndex != ~0)
cblas_scopy((int)count, inBuffer + 0, 5, outBuffer + flIndex, outchannels);
if(frIndex != ~0)
cblas_scopy((int)count, inBuffer + 1, 5, outBuffer + frIndex, outchannels);
if(cIndex != ~0)
cblas_scopy((int)count, inBuffer + 2, 5, outBuffer + cIndex, outchannels);
if(blIndex != ~0)
cblas_scopy((int)count, inBuffer + 3, 5, outBuffer + blIndex, outchannels);
if(brIndex != ~0)
cblas_scopy((int)count, inBuffer + 4, 5, outBuffer + brIndex, outchannels);
} else if(inconfig == AudioConfig6Point1 && outchannels >= 8) {
uint32_t flIndex = [AudioChunk channelIndexFromConfig:outconfig forFlag:AudioChannelFrontLeft];
uint32_t frIndex = [AudioChunk channelIndexFromConfig:outconfig forFlag:AudioChannelFrontRight];
uint32_t cIndex = [AudioChunk channelIndexFromConfig:outconfig forFlag:AudioChannelFrontCenter];
uint32_t lfeIndex = [AudioChunk channelIndexFromConfig:outconfig forFlag:AudioChannelLFE];
uint32_t blIndex = [AudioChunk channelIndexFromConfig:outconfig forFlag:AudioChannelBackLeft];
uint32_t brIndex = [AudioChunk channelIndexFromConfig:outconfig forFlag:AudioChannelBackRight];
uint32_t bcIndex = [AudioChunk channelIndexFromConfig:outconfig forFlag:AudioChannelBackCenter];
uint32_t slIndex = [AudioChunk channelIndexFromConfig:outconfig forFlag:AudioChannelSideLeft];
uint32_t srIndex = [AudioChunk channelIndexFromConfig:outconfig forFlag:AudioChannelSideRight];
vDSP_vclr(outBuffer, 1, count * outchannels);
if(flIndex != ~0)
cblas_scopy((int)count, inBuffer + 0, 7, outBuffer + flIndex, outchannels);
if(frIndex != ~0)
cblas_scopy((int)count, inBuffer + 1, 7, outBuffer + frIndex, outchannels);
if(cIndex != ~0)
cblas_scopy((int)count, inBuffer + 2, 7, outBuffer + cIndex, outchannels);
if(lfeIndex != ~0)
cblas_scopy((int)count, inBuffer + 3, 7, outBuffer + lfeIndex, outchannels);
if(slIndex != ~0)
cblas_scopy((int)count, inBuffer + 4, 7, outBuffer + slIndex, outchannels);
if(srIndex != ~0)
cblas_scopy((int)count, inBuffer + 5, 7, outBuffer + srIndex, outchannels);
if(bcIndex != ~0)
cblas_scopy((int)count, inBuffer + 6, 7, outBuffer + bcIndex, outchannels);
else {
if(blIndex != ~0)
cblas_scopy((int)count, inBuffer + 6, 7, outBuffer + blIndex, outchannels);
if(brIndex != ~0)
cblas_scopy((int)count, inBuffer + 6, 7, outBuffer + brIndex, outchannels);
}
} else {
vDSP_vclr(outBuffer, 1, count * outchannels);
for(int i = 0; i < inchannels; ++i) {
uint32_t channelFlag = [AudioChunk extractChannelFlag:i fromConfig:inconfig];
uint32_t outIndex = [AudioChunk channelIndexFromConfig:outconfig forFlag:channelFlag];
if(outIndex != ~0)
cblas_scopy((int)count, inBuffer + i, inchannels, outBuffer + outIndex, outchannels);
}
}
}
@implementation DownmixProcessor
static void *kDownmixProcessorContext = &kDownmixProcessorContext;
- (id)initWithInputFormat:(AudioStreamBasicDescription)inf inputConfig:(uint32_t)iConfig andOutputFormat:(AudioStreamBasicDescription)outf outputConfig:(uint32_t)oConfig {
self = [super init];
if(self) {
if(inf.mFormatID != kAudioFormatLinearPCM ||
(inf.mFormatFlags & kAudioFormatFlagsNativeFloatPacked) != kAudioFormatFlagsNativeFloatPacked ||
inf.mBitsPerChannel != 32 ||
inf.mBytesPerFrame != (4 * inf.mChannelsPerFrame) ||
inf.mBytesPerPacket != inf.mFramesPerPacket * inf.mBytesPerFrame)
return nil;
if(outf.mFormatID != kAudioFormatLinearPCM ||
(outf.mFormatFlags & kAudioFormatFlagsNativeFloatPacked) != kAudioFormatFlagsNativeFloatPacked ||
outf.mBitsPerChannel != 32 ||
outf.mBytesPerFrame != (4 * outf.mChannelsPerFrame) ||
outf.mBytesPerPacket != outf.mFramesPerPacket * outf.mBytesPerFrame)
return nil;
inputFormat = inf;
outputFormat = outf;
inConfig = iConfig;
outConfig = oConfig;
}
return self;
}
- (void)process:(const void *)inBuffer frameCount:(size_t)frames output:(void *)outBuffer {
if(inputFormat.mChannelsPerFrame == 2 && outConfig == AudioConfigStereo &&
inConfig == (AudioChannelSideLeft | AudioChannelSideRight)) {
// Workaround for HRTF output
memcpy(outBuffer, inBuffer, frames * outputFormat.mBytesPerPacket);
} else if(inputFormat.mChannelsPerFrame > 2 && outConfig == AudioConfigStereo) {
downmix_to_stereo((const float *)inBuffer, inputFormat.mChannelsPerFrame, inConfig, (float *)outBuffer, frames);
} else if(inputFormat.mChannelsPerFrame > 1 && outConfig == AudioConfigMono) {
downmix_to_mono((const float *)inBuffer, inputFormat.mChannelsPerFrame, inConfig, (float *)outBuffer, frames);
} else if(inputFormat.mChannelsPerFrame < outputFormat.mChannelsPerFrame) {
upmix((const float *)inBuffer, inputFormat.mChannelsPerFrame, inConfig, (float *)outBuffer, outputFormat.mChannelsPerFrame, outConfig, frames);
} else if(inConfig == outConfig) {
memcpy(outBuffer, inBuffer, frames * outputFormat.mBytesPerPacket);
}
}
@end

View file

@ -0,0 +1,36 @@
//
// FSurroundFilter.h
// CogAudio
//
// Created by Christopher Snowhill on 7/9/22.
//
#ifndef FSurroundFilter_h
#define FSurroundFilter_h
#import <Cocoa/Cocoa.h>
#import <stdint.h>
#define FSurroundChunkSize 4096
@interface FSurroundFilter : NSObject {
void *decoder;
void *params;
double srate;
uint32_t channelCount;
uint32_t channelConfig;
float tempBuffer[4096 * 2];
}
- (id)initWithSampleRate:(double)srate;
- (uint32_t)channelCount;
- (uint32_t)channelConfig;
- (double)srate;
- (void)process:(const float *)samplesIn output:(float *)samplesOut count:(uint32_t)count;
@end
#endif /* FSurround_h */

View file

@ -0,0 +1,156 @@
//
// FSurroundFilter.m
// CogAudio Framework
//
// Created by Christopher Snowhill on 7/9/22.
//
#import "FSurroundFilter.h"
#import "freesurround_decoder.h"
#import "AudioChunk.h"
#import <Accelerate/Accelerate.h>
#import <map>
#import <vector>
struct freesurround_params {
// the user-configurable parameters
float center_image, shift, depth, circular_wrap, focus, front_sep, rear_sep, bass_lo, bass_hi;
bool use_lfe;
channel_setup channels_fs; // FreeSurround channel setup
std::vector<unsigned> chanmap; // FreeSurround -> WFX channel index translation (derived data for faster lookup)
// construct with defaults
freesurround_params()
: center_image(0.7), shift(0), depth(1), circular_wrap(90), focus(0), front_sep(1), rear_sep(1),
bass_lo(40), bass_hi(90), use_lfe(false) {
set_channels_fs(cs_5point1);
}
// compute the WFX version of the channel setup code
unsigned channel_count() {
return (unsigned)chanmap.size();
}
unsigned channels_wfx() {
unsigned res = 0;
for(unsigned i = 0; i < chanmap.size(); res |= chanmap[i++]) {};
return res;
}
// assign a channel setup & recompute derived data
void set_channels_fs(channel_setup setup) {
channels_fs = setup;
chanmap.clear();
// Note: Because WFX does not define a few of the more exotic channels (side front left&right, side rear left&right, back center left&right),
// the side front/back channel pairs (both left and right sides, resp.) are mapped here onto foobar's top front/back channel pairs and the
// back (off-)center left/right channels are mapped onto foobar's top front center and top back center, respectively.
// Therefore, these speakers should be connected to those outputs instead.
std::map<channel_id, uint32_t> fs2wfx;
fs2wfx[ci_front_left] = AudioChannelFrontLeft;
fs2wfx[ci_front_center_left] = AudioChannelFrontCenterLeft;
fs2wfx[ci_front_center] = AudioChannelFrontCenter;
fs2wfx[ci_front_center_right] = AudioChannelFrontCenterRight;
fs2wfx[ci_front_right] = AudioChannelFrontRight;
fs2wfx[ci_side_front_left] = AudioChannelFrontLeft;
fs2wfx[ci_side_front_right] = AudioChannelTopFrontRight;
fs2wfx[ci_side_center_left] = AudioChannelSideLeft;
fs2wfx[ci_side_center_right] = AudioChannelSideRight;
fs2wfx[ci_side_back_left] = AudioChannelTopBackLeft;
fs2wfx[ci_side_back_right] = AudioChannelTopBackRight;
fs2wfx[ci_back_left] = AudioChannelBackLeft;
fs2wfx[ci_back_center_left] = AudioChannelTopFrontCenter;
fs2wfx[ci_back_center] = AudioChannelBackCenter;
fs2wfx[ci_back_center_right] = AudioChannelTopBackCenter;
fs2wfx[ci_back_right] = AudioChannelBackRight;
fs2wfx[ci_lfe] = AudioChannelLFE;
for(unsigned i = 0; i < freesurround_decoder::num_channels(channels_fs); i++)
chanmap.push_back(fs2wfx[freesurround_decoder::channel_at(channels_fs, i)]);
}
};
@implementation FSurroundFilter
- (id)initWithSampleRate:(double)srate {
self = [super init];
if(!self) return nil;
self->srate = srate;
freesurround_params *_params = new freesurround_params;
params = (void *)_params;
freesurround_decoder *_decoder = new freesurround_decoder(cs_5point1, 4096);
decoder = (void *)_decoder;
_decoder->circular_wrap(_params->circular_wrap);
_decoder->shift(_params->shift);
_decoder->depth(_params->depth);
_decoder->focus(_params->focus);
_decoder->center_image(_params->center_image);
_decoder->front_separation(_params->front_sep);
_decoder->rear_separation(_params->rear_sep);
_decoder->bass_redirection(_params->use_lfe);
_decoder->low_cutoff(_params->bass_lo / (srate / 2.0));
_decoder->high_cutoff(_params->bass_hi / (srate / 2.0));
channelCount = _params->channel_count();
channelConfig = _params->channels_wfx();
return self;
}
- (void)dealloc {
if(decoder) {
freesurround_decoder *_decoder = (freesurround_decoder *)decoder;
delete _decoder;
}
if(params) {
freesurround_params *_params = (freesurround_params *)params;
delete _params;
}
}
- (uint32_t)channelCount {
return channelCount;
}
- (uint32_t)channelConfig {
return channelConfig;
}
- (double)srate {
return srate;
}
- (void)process:(const float *)samplesIn output:(float *)samplesOut count:(uint32_t)count {
freesurround_params *_params = (freesurround_params *)params;
freesurround_decoder *_decoder = (freesurround_decoder *)decoder;
uint32_t zeroCount = 0;
if(count > 4096) {
zeroCount = count - 4096;
count = 4096;
}
if(count < 4096) {
cblas_scopy(count * 2, samplesIn, 1, &tempBuffer[0], 1);
vDSP_vclr(&tempBuffer[count * 2], 1, (4096 - count) * 2);
samplesIn = &tempBuffer[0];
}
float *src = _decoder->decode(samplesIn);
for(unsigned c = 0, num = channelCount; c < num; c++) {
unsigned idx = [AudioChunk channelIndexFromConfig:channelConfig forFlag:_params->chanmap[c]];
cblas_scopy(count, src + c, num, samplesOut + idx, num);
if(zeroCount) {
vDSP_vclr(samplesOut + idx + count, num, zeroCount);
}
}
}
@end

View file

@ -0,0 +1,46 @@
//
// HeadphoneFilter.h
// CogAudio Framework
//
// Created by Christopher Snowhill on 1/24/22.
//
#ifndef HeadphoneFilter_h
#define HeadphoneFilter_h
#import <Accelerate/Accelerate.h>
#import <Cocoa/Cocoa.h>
#import <simd/simd.h>
@interface HeadphoneFilter : NSObject {
NSURL *URL;
int bufferSize;
int paddedBufferSize;
double sampleRate;
int channelCount;
uint32_t config;
float **mirroredImpulseResponses;
float **prevInputs;
float *paddedSignal[2];
}
+ (BOOL)validateImpulseFile:(NSURL *)url;
- (id)initWithImpulseFile:(NSURL *)url forSampleRate:(double)sampleRate withInputChannels:(int)channels withConfig:(uint32_t)config withMatrix:(simd_float4x4)matrix;
- (void)reloadWithMatrix:(simd_float4x4)matrix;
- (void)process:(const float *)inBuffer sampleCount:(int)count toBuffer:(float *)outBuffer;
- (void)reset;
- (size_t)needPrefill;
@end
#endif /* HeadphoneFilter_h */

View file

@ -0,0 +1,386 @@
//
// HeadphoneFilter.m
// CogAudio Framework
//
// Created by Christopher Snowhill on 1/24/22.
//
#import "HeadphoneFilter.h"
#import "AudioChunk.h"
#import "AudioDecoder.h"
#import "AudioSource.h"
#import <stdlib.h>
#import <fstream>
#import <soxr.h>
#import "HrtfData.h"
#import "Logging.h"
typedef struct speakerPosition {
float elevation;
float azimuth;
float distance;
} speakerPosition;
#define DEGREES(x) ((x)*M_PI / 180.0)
static const speakerPosition speakerPositions[18] = {
{ .elevation = DEGREES(0.0), .azimuth = DEGREES(-30.0), .distance = 1.0 },
{ .elevation = DEGREES(0.0), .azimuth = DEGREES(+30.0), .distance = 1.0 },
{ .elevation = DEGREES(0.0), .azimuth = DEGREES(0.0), .distance = 1.0 },
{ .elevation = DEGREES(0.0), .azimuth = DEGREES(0.0), .distance = 1.0 },
{ .elevation = DEGREES(0.0), .azimuth = DEGREES(-135.0), .distance = 1.0 },
{ .elevation = DEGREES(0.0), .azimuth = DEGREES(+135.0), .distance = 1.0 },
{ .elevation = DEGREES(0.0), .azimuth = DEGREES(-15.0), .distance = 1.0 },
{ .elevation = DEGREES(0.0), .azimuth = DEGREES(+15.0), .distance = 1.0 },
{ .elevation = DEGREES(0.0), .azimuth = DEGREES(-180.0), .distance = 1.0 },
{ .elevation = DEGREES(0.0), .azimuth = DEGREES(-90.0), .distance = 1.0 },
{ .elevation = DEGREES(0.0), .azimuth = DEGREES(+90.0), .distance = 1.0 },
{ .elevation = DEGREES(+90.0), .azimuth = DEGREES(0.0), .distance = 1.0 },
{ .elevation = DEGREES(+45.0), .azimuth = DEGREES(-30.0), .distance = 1.0 },
{ .elevation = DEGREES(+45.0), .azimuth = DEGREES(0.0), .distance = 1.0 },
{ .elevation = DEGREES(+45.0), .azimuth = DEGREES(+30.0), .distance = 1.0 },
{ .elevation = DEGREES(+45.0), .azimuth = DEGREES(-135.0), .distance = 1.0 },
{ .elevation = DEGREES(+45.0), .azimuth = DEGREES(0.0), .distance = 1.0 },
{ .elevation = DEGREES(+45.0), .azimuth = DEGREES(+135.0), .distance = 1.0 }
};
static simd_float4x4 matX(float theta) {
simd_float4x4 mat = {
simd_make_float4(1.0f, 0.0f, 0.0f, 0.0f),
simd_make_float4(0.0f, cosf(theta), -sinf(theta), 0.0f),
simd_make_float4(0.0f, sinf(theta), cosf(theta), 0.0f),
simd_make_float4(0.0f, 0.0f, 0.0f, 1.0f)
};
return mat;
};
static simd_float4x4 matY(float theta) {
simd_float4x4 mat = {
simd_make_float4(cosf(theta), 0.0f, sinf(theta), 0.0f),
simd_make_float4(0.0f, 1.0f, 0.0f, 0.0f),
simd_make_float4(-sinf(theta), 0.0f, cosf(theta), 0.0f),
simd_make_float4(0.0f, 0.0f, 0.0f, 1.0f)
};
return mat;
}
#if 0
static simd_float4x4 matZ(float theta) {
simd_float4x4 mat = {
simd_make_float4(cosf(theta), -sinf(theta), 0.0f, 0.0f),
simd_make_float4(sinf(theta), cosf(theta), 0.0f, 0.0f),
simd_make_float4(0.0f, 0.0f, 1.0f, 0.0f),
simd_make_float4(0.0f, 0.0f, 0.0f, 1.0f)
};
return mat;
};
#endif
static void transformPosition(float &elevation, float &azimuth, const simd_float4x4 &matrix) {
simd_float4x4 mat_x = matX(azimuth);
simd_float4x4 mat_y = matY(elevation);
//simd_float4x4 mat_z = matrix_identity_float4x4;
simd_float4x4 offsetMatrix = simd_mul(mat_x, mat_y);
//offsetMatrix = simd_mul(offsetMatrix, mat_z);
offsetMatrix = simd_mul(offsetMatrix, matrix);
double sy = sqrt(offsetMatrix.columns[0].x * offsetMatrix.columns[0].x + offsetMatrix.columns[1].x * offsetMatrix.columns[1].x);
bool singular = sy < 1e-6; // If
float x, y/*, z*/;
if(!singular) {
x = atan2(offsetMatrix.columns[2].y, offsetMatrix.columns[2].z);
y = atan2(-offsetMatrix.columns[2].x, sy);
//z = atan2(offsetMatrix.columns[1].x, offsetMatrix.columns[0].x);
} else {
x = atan2(-offsetMatrix.columns[1].z, offsetMatrix.columns[1].y);
y = atan2(-offsetMatrix.columns[2].x, sy);
//z = 0;
}
elevation = y;
azimuth = x;
if(elevation < (M_PI * (-0.5))) {
elevation = (M_PI * (-0.5));
} else if(elevation > M_PI * 0.5) {
elevation = M_PI * 0.5;
}
while(azimuth < (M_PI * (-2.0))) {
azimuth += M_PI * 2.0;
}
while(azimuth > M_PI * 2.0) {
azimuth -= M_PI * 2.0;
}
}
@interface impulseSetCache : NSObject {
NSURL *URL;
HrtfData *data;
}
+ (impulseSetCache *)sharedController;
- (void)getImpulse:(NSURL *)url outImpulse:(float **)outImpulse outSampleCount:(int *)outSampleCount sampleRate:(double)sampleRate channelCount:(int)channelCount channelConfig:(uint32_t)channelConfig withMatrix:(simd_float4x4)matrix;
@end
@implementation impulseSetCache
static impulseSetCache *_sharedController = nil;
+ (impulseSetCache *)sharedController {
@synchronized(self) {
if(!_sharedController) {
_sharedController = [[impulseSetCache alloc] init];
}
}
return _sharedController;
}
- (id)init {
self = [super init];
if(self) {
data = NULL;
}
return self;
}
- (void)dealloc {
delete data;
}
- (void)getImpulse:(NSURL *)url outImpulse:(float **)outImpulse outSampleCount:(int *)outSampleCount sampleRate:(double)sampleRate channelCount:(int)channelCount channelConfig:(uint32_t)channelConfig withMatrix:(simd_float4x4)matrix {
double sampleRateOfSource = 0;
int sampleCount = 0;
if(!data || ![url isEqualTo:URL]) {
delete data;
data = NULL;
URL = url;
NSString *filePath = [url path];
try {
std::ifstream file([filePath UTF8String], std::fstream::binary);
if(!file.is_open()) {
throw std::logic_error("Cannot open file.");
}
data = new HrtfData(file);
file.close();
} catch(std::exception &e) {
ALog(@"Exception caught: %s", e.what());
}
}
try {
soxr_quality_spec_t q_spec = soxr_quality_spec(SOXR_HQ, 0);
soxr_io_spec_t io_spec = soxr_io_spec(SOXR_FLOAT32_I, SOXR_FLOAT32_I);
soxr_runtime_spec_t runtime_spec = soxr_runtime_spec(0);
bool resampling;
sampleRateOfSource = data->get_sample_rate();
resampling = !!(fabs(sampleRateOfSource - sampleRate) > 1e-6);
uint32_t sampleCountResampled;
uint32_t sampleCountExact = data->get_response_length();
sampleCount = sampleCountExact + ((data->get_longest_delay() + 2) >> 2);
uint32_t actualSampleCount = sampleCount;
if(resampling) {
sampleCountResampled = (uint32_t)(((double)sampleCountExact) * sampleRate / sampleRateOfSource);
actualSampleCount = (uint32_t)(((double)actualSampleCount) * sampleRate / sampleRateOfSource);
io_spec.scale = sampleRateOfSource / sampleRate;
}
actualSampleCount = (actualSampleCount + 15) & ~15;
*outImpulse = (float *)calloc(sizeof(float), actualSampleCount * channelCount * 2);
if(!*outImpulse) {
throw std::bad_alloc();
}
float *hrtfData = *outImpulse;
for(uint32_t i = 0; i < channelCount; ++i) {
uint32_t channelFlag = [AudioChunk extractChannelFlag:i fromConfig:channelConfig];
uint32_t channelNumber = [AudioChunk findChannelIndex:channelFlag];
if(channelNumber < 18) {
const speakerPosition &speaker = speakerPositions[channelNumber];
DirectionData hrtfLeft;
DirectionData hrtfRight;
float azimuth = speaker.azimuth;
float elevation = speaker.elevation;
transformPosition(elevation, azimuth, matrix);
data->get_direction_data(elevation, azimuth, speaker.distance, hrtfLeft, hrtfRight);
if(resampling) {
ssize_t leftDelay = (ssize_t)((double)(hrtfLeft.delay) * 0.25 * sampleRate / sampleRateOfSource);
ssize_t rightDelay = (ssize_t)((double)(hrtfRight.delay) * 0.25 * sampleRate / sampleRateOfSource);
soxr_oneshot(sampleRateOfSource, sampleRate, 1, &hrtfLeft.impulse_response[0], sampleCountExact, NULL, &hrtfData[leftDelay + actualSampleCount * i * 2], sampleCountResampled, NULL, &io_spec, &q_spec, &runtime_spec);
soxr_oneshot(sampleRateOfSource, sampleRate, 1, &hrtfRight.impulse_response[0], sampleCountExact, NULL, &hrtfData[rightDelay + actualSampleCount * (i * 2 + 1)], sampleCountResampled, NULL, &io_spec, &q_spec, &runtime_spec);
} else {
cblas_scopy(sampleCountExact, &hrtfLeft.impulse_response[0], 1, &hrtfData[((hrtfLeft.delay + 2) >> 2) + actualSampleCount * i * 2], 1);
cblas_scopy(sampleCountExact, &hrtfRight.impulse_response[0], 1, &hrtfData[((hrtfRight.delay + 2) >> 2) + actualSampleCount * (i * 2 + 1)], 1);
}
}
}
*outSampleCount = actualSampleCount;
} catch(std::exception &e) {
ALog(@"Exception caught: %s", e.what());
}
}
@end
@implementation HeadphoneFilter
+ (BOOL)validateImpulseFile:(NSURL *)url {
NSString *filePath = [url path];
try {
std::ifstream file([filePath UTF8String], std::fstream::binary);
if(!file.is_open()) {
throw std::logic_error("Cannot open file.");
}
HrtfData data(file);
file.close();
return YES;
} catch(std::exception &e) {
ALog(@"Exception thrown: %s", e.what());
return NO;
}
}
- (id)initWithImpulseFile:(NSURL *)url forSampleRate:(double)sampleRate withInputChannels:(int)channels withConfig:(uint32_t)config withMatrix:(simd_float4x4)matrix {
self = [super init];
if(self) {
URL = url;
self->sampleRate = sampleRate;
channelCount = channels;
self->config = config;
float *impulseBuffer = NULL;
int sampleCount = 0;
[[impulseSetCache sharedController] getImpulse:url outImpulse:&impulseBuffer outSampleCount:&sampleCount sampleRate:sampleRate channelCount:channels channelConfig:config withMatrix:matrix];
if(!impulseBuffer) {
return nil;
}
mirroredImpulseResponses = (float **)calloc(sizeof(float *), channelCount * 2);
if(!mirroredImpulseResponses) {
free(impulseBuffer);
return nil;
}
for(int i = 0; i < channelCount * 2; ++i) {
mirroredImpulseResponses[i] = &impulseBuffer[sampleCount * i];
vDSP_vrvrs(mirroredImpulseResponses[i], 1, sampleCount);
}
paddedBufferSize = sampleCount;
paddedSignal[0] = (float *)calloc(sizeof(float), paddedBufferSize * 2);
if(!paddedSignal[0]) {
return nil;
}
paddedSignal[1] = paddedSignal[0] + paddedBufferSize;
prevInputs = (float **)calloc(channels, sizeof(float *));
if(!prevInputs)
return nil;
prevInputs[0] = (float *)calloc(sizeof(float), sampleCount * channelCount);
if(!prevInputs[0])
return nil;
for(int i = 1; i < channels; ++i) {
prevInputs[i] = prevInputs[i - 1] + sampleCount;
}
}
return self;
}
- (void)dealloc {
if(paddedSignal[0]) {
free(paddedSignal[0]);
}
if(prevInputs) {
if(prevInputs[0]) {
free(prevInputs[0]);
}
free(prevInputs);
}
if(mirroredImpulseResponses) {
if(mirroredImpulseResponses[0]) {
free(mirroredImpulseResponses[0]);
}
free(mirroredImpulseResponses);
}
}
- (void)reloadWithMatrix:(simd_float4x4)matrix {
@synchronized (self) {
if(!mirroredImpulseResponses[0]) {
return;
}
free(mirroredImpulseResponses[0]);
float *impulseBuffer = NULL;
int sampleCount = 0;
[[impulseSetCache sharedController] getImpulse:URL outImpulse:&impulseBuffer outSampleCount:&sampleCount sampleRate:sampleRate channelCount:channelCount channelConfig:config withMatrix:matrix];
for(int i = 0; i < channelCount * 2; ++i) {
mirroredImpulseResponses[i] = &impulseBuffer[sampleCount * i];
vDSP_vrvrs(mirroredImpulseResponses[i], 1, sampleCount);
}
}
}
- (void)process:(const float *)inBuffer sampleCount:(int)count toBuffer:(float *)outBuffer {
@synchronized (self) {
int sampleCount = paddedBufferSize;
while(count > 0) {
float left = 0, right = 0;
for(int i = 0; i < channelCount; ++i) {
float thisleft, thisright;
vDSP_vmul(prevInputs[i], 1, mirroredImpulseResponses[i * 2], 1, paddedSignal[0], 1, sampleCount);
vDSP_vmul(prevInputs[i], 1, mirroredImpulseResponses[i * 2 + 1], 1, paddedSignal[1], 1, sampleCount);
vDSP_sve(paddedSignal[0], 1, &thisleft, sampleCount);
vDSP_sve(paddedSignal[1], 1, &thisright, sampleCount);
left += thisleft;
right += thisright;
memmove(prevInputs[i], prevInputs[i] + 1, sizeof(float) * (sampleCount - 1));
prevInputs[i][sampleCount - 1] = *inBuffer++;
}
outBuffer[0] = left;
outBuffer[1] = right;
outBuffer += 2;
--count;
}
}
}
- (void)reset {
for(int i = 0; i < channelCount; ++i) {
vDSP_vclr(prevInputs[i], 1, paddedBufferSize);
}
}
- (size_t)needPrefill {
return paddedBufferSize;
}
@end

26
Audio/Chain/DSPNode.h Normal file
View file

@ -0,0 +1,26 @@
//
// DSPNode.h
// CogAudio
//
// Created by Christopher Snowhill on 2/10/25.
//
#ifndef DSPNode_h
#define DSPNode_h
#import <CogAudio/Node.h>
@interface DSPNode : Node {
}
- (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p latency:(double)latency;
- (void)threadEntry:(id _Nullable)arg;
- (void)setShouldContinue:(BOOL)s;
- (double)secondsBuffered;
@end
#endif /* DSPNode_h */

76
Audio/Chain/DSPNode.m Normal file
View file

@ -0,0 +1,76 @@
//
// DSPNode.m
// CogAudio Framework
//
// Created by Christopher Snowhill on 2/10/25.
//
#import <Foundation/Foundation.h>
#import "DSPNode.h"
@implementation DSPNode {
BOOL threadTerminated;
}
- (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p latency:(double)latency {
self = [super init];
if(self) {
buffer = [[ChunkList alloc] initWithMaximumDuration:latency];
writeSemaphore = [[Semaphore alloc] init];
readSemaphore = [[Semaphore alloc] init];
accessLock = [[NSLock alloc] init];
initialBufferFilled = NO;
controller = c;
endOfStream = NO;
shouldContinue = YES;
nodeChannelConfig = 0;
nodeLossless = NO;
durationPrebuffer = latency * 0.25;
inWrite = NO;
inPeek = NO;
inRead = NO;
inMerge = NO;
[self setPreviousNode:p];
#ifdef LOG_CHAINS
[self initLogFiles];
#endif
}
return self;
}
// DSP threads buffer for low latency, and therefore should have high priority
- (void)threadEntry:(id _Nullable)arg {
@autoreleasepool {
NSThread *currentThread = [NSThread currentThread];
[currentThread setThreadPriority:0.75];
[currentThread setQualityOfService:NSQualityOfServiceUserInitiated];
threadTerminated = NO;
[self process];
threadTerminated = YES;
}
}
- (void)setShouldContinue:(BOOL)s {
BOOL currentShouldContinue = shouldContinue;
shouldContinue = s;
if(!currentShouldContinue && s && threadTerminated) {
[self launchThread];
}
}
- (double)secondsBuffered {
return [buffer listDuration];
}
@end

View file

@ -8,30 +8,47 @@
#import <Cocoa/Cocoa.h>
#import <CoreAudio/AudioHardware.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AudioUnit/AudioUnit.h>
#import <CoreAudio/AudioHardware.h>
#import "AudioDecoder.h"
#import "Converter.h"
#import "Node.h"
#import "Plugin.h"
#import <CogAudio/AudioDecoder.h>
#import <CogAudio/Node.h>
#import <CogAudio/Plugin.h>
#define INPUT_NODE_SEEK
@interface InputNode : Node {
id<CogDecoder> decoder;
Converter *converter;
AudioStreamBasicDescription outputFormat;
int bytesPerSample;
int bytesPerFrame;
BOOL floatingPoint;
BOOL swapEndian;
BOOL shouldSeek;
double seekTime;
}
long seekFrame;
BOOL observersAdded;
Semaphore *exitAtTheEndOfTheStream;
}
@property(readonly) Semaphore * _Nonnull exitAtTheEndOfTheStream;
@property(readonly) BOOL threadExited;
- (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p;
- (BOOL)openWithSource:(id<CogSource>_Nonnull)source;
- (BOOL)openWithDecoder:(id<CogDecoder>_Nonnull)d;
- (BOOL)openURL:(NSURL *)url withSource:(id<CogSource>)source outputFormat:(AudioStreamBasicDescription)of;
- (void)process;
- (NSDictionary *) properties;
- (void)seek:(double)time;
- (NSDictionary *_Nonnull)properties;
- (void)seek:(long)frame;
- (void)registerObservers;
- (BOOL)setTrack:(NSURL *_Nonnull)track;
- (id<CogDecoder>_Nonnull)decoder;
@end

View file

@ -7,137 +7,284 @@
//
#import "InputNode.h"
#import "AudioPlayer.h"
#import "BufferChain.h"
#import "Plugin.h"
#import "CoreAudioUtils.h"
#import "OutputNode.h"
#import "Plugin.h"
#import "NSDictionary+Merge.h"
#import "Logging.h"
@implementation InputNode
- (BOOL)openURL:(NSURL *)url withSource:(id<CogSource>)source outputFormat:(AudioStreamBasicDescription)of
{
outputFormat = of;
static void *kInputNodeContext = &kInputNodeContext;
decoder = [AudioDecoder audioDecoderForURL:url];
[decoder retain];
@synthesize threadExited;
@synthesize exitAtTheEndOfTheStream;
converter = [[Converter alloc] init];
if (converter == nil)
- (id)initWithController:(id)c previous:(id)p {
self = [super initWithController:c previous:p];
if(self) {
exitAtTheEndOfTheStream = [[Semaphore alloc] init];
threadExited = NO;
}
return self;
}
- (BOOL)openWithSource:(id<CogSource>)source {
[self removeObservers];
decoder = [AudioDecoder audioDecoderForSource:source];
if(decoder == nil)
return NO;
[self registerObservers];
if (decoder == nil)
return NO;
if (![decoder open:source])
{
NSLog(@"Couldn't open decoder...");
if(![decoder open:source]) {
ALog(@"Couldn't open decoder...");
return NO;
}
NSDictionary *properties = [decoder properties];
int bitsPerSample = [[properties objectForKey:@"bitsPerSample"] intValue];
int channels = [[properties objectForKey:@"channels"] intValue];
bytesPerFrame = ((bitsPerSample + 7) / 8) * channels;
nodeFormat = propertiesToASBD(properties);
if([properties valueForKey:@"channelConfig"])
nodeChannelConfig = [[properties valueForKey:@"channelConfig"] unsignedIntValue];
nodeLossless = [[properties valueForKey:@"encoding"] isEqualToString:@"lossless"];
shouldContinue = YES;
shouldSeek = NO;
return YES;
}
- (void)registerObservers
{
[decoder addObserver:self
forKeyPath:@"properties"
options:(NSKeyValueObservingOptionNew)
context:NULL];
- (BOOL)openWithDecoder:(id<CogDecoder>)d {
[self removeObservers];
[decoder addObserver:self
forKeyPath:@"metadata"
options:(NSKeyValueObservingOptionNew)
context:NULL];
DLog(@"Opening with old decoder: %@", d);
decoder = d;
NSDictionary *properties = [decoder properties];
int bitsPerSample = [[properties objectForKey:@"bitsPerSample"] intValue];
int channels = [[properties objectForKey:@"channels"] intValue];
bytesPerFrame = ((bitsPerSample + 7) / 8) * channels;
nodeFormat = propertiesToASBD(properties);
if([properties valueForKey:@"channelConfig"])
nodeChannelConfig = [[properties valueForKey:@"channelConfig"] unsignedIntValue];
nodeLossless = [[properties valueForKey:@"encoding"] isEqualToString:@"lossless"];
[self registerObservers];
shouldContinue = YES;
shouldSeek = NO;
DLog(@"DONES: %@", decoder);
return YES;
}
- (void)registerObservers {
if(!observersAdded) {
DLog(@"REGISTERING OBSERVERS");
[decoder addObserver:self
forKeyPath:@"properties"
options:(NSKeyValueObservingOptionNew)
context:kInputNodeContext];
[decoder addObserver:self
forKeyPath:@"metadata"
options:(NSKeyValueObservingOptionNew)
context:kInputNodeContext];
observersAdded = YES;
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if ([keyPath isEqual:@"properties"]) {
//Setup converter!
[converter cleanUp];
[converter setupWithInputFormat:propertiesToASBD([decoder properties]) outputFormat:outputFormat];
//Inform something of properties change
}
else if ([keyPath isEqual:@"metadata"]) {
//Inform something of metadata change
context:(void *)context {
if(context == kInputNodeContext) {
DLog(@"SOMETHING CHANGED!");
if([keyPath isEqual:@"properties"]) {
DLog(@"Input format changed");
// Converter may need resetting, it'll do that when it reaches the new chunks
NSDictionary *properties = [decoder properties];
int bitsPerSample = [[properties objectForKey:@"bitsPerSample"] intValue];
int channels = [[properties objectForKey:@"channels"] intValue];
bytesPerFrame = ((bitsPerSample + 7) / 8) * channels;
nodeFormat = propertiesToASBD(properties);
nodeChannelConfig = [[properties valueForKey:@"channelConfig"] unsignedIntValue];
nodeLossless = [[properties valueForKey:@"encoding"] isEqualToString:@"lossless"];
} else if([keyPath isEqual:@"metadata"]) {
// Inform something of metadata change
NSDictionary *entryProperties = [decoder properties];
if(entryProperties == nil)
return;
NSDictionary *entryInfo = [NSDictionary dictionaryByMerging:entryProperties with:[decoder metadata]];
[controller pushInfo:entryInfo];
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)process
{
int amountRead = 0, amountConverted = 0, amountInBuffer = 0;
void *inputBuffer = malloc(CHUNK_SIZE);
- (void)process {
BOOL shouldClose = YES;
BOOL seekError = NO;
while ([self shouldContinue] == YES && [self endOfStream] == NO)
{
if (shouldSeek == YES)
{
[decoder seekToTime:seekTime];
shouldSeek = NO;
BOOL isError = NO;
[self resetBuffer];
initialBufferFilled = NO;
if([decoder respondsToSelector:@selector(isSilence)]) {
if([decoder isSilence]) {
isError = YES;
}
}
if (amountInBuffer < CHUNK_SIZE) {
amountRead = [decoder fillBuffer:((char *)inputBuffer) + amountInBuffer ofSize:CHUNK_SIZE - amountInBuffer];
amountInBuffer += amountRead;
}
[controller setError:isError];
amountConverted = [converter convert:inputBuffer amount:amountInBuffer]; //Convert fills in converter buffer, til the next call
if (amountInBuffer - amountConverted > 0) {
memmove(inputBuffer,((char *)inputBuffer) + amountConverted, amountInBuffer - amountConverted);
}
amountInBuffer -= amountConverted;
while([self shouldContinue] == YES && [self endOfStream] == NO) {
if(shouldSeek == YES) {
BufferChain *bufferChain = controller;
AudioPlayer *audioPlayer = [bufferChain controller];
OutputNode *outputNode = [audioPlayer output];
if ([converter outputBufferSize] <= 0)
{
if (initialBufferFilled == NO) {
[controller initialBufferFilled];
DLog(@"SEEKING! Resetting Buffer");
[outputNode resetBackwards];
DLog(@"Reset buffer!");
DLog(@"SEEKING!");
@autoreleasepool {
seekError = [decoder seek:seekFrame] < 0;
}
endOfStream = YES;
[controller endOfInputReached];
break; //eof
shouldSeek = NO;
DLog(@"Seeked! Resetting Buffer");
initialBufferFilled = NO;
if(seekError) {
[controller setError:YES];
}
}
[self writeData:[converter outputBuffer] amount:[converter outputBufferSize]];
AudioChunk *chunk;
@autoreleasepool {
chunk = [decoder readAudio];
}
if(chunk && [chunk frameCount]) {
@autoreleasepool {
[self writeChunk:chunk];
chunk = nil;
}
} else {
if(chunk) {
@autoreleasepool {
chunk = nil;
}
}
DLog(@"End of stream? %@", [self properties]);
endOfStream = YES;
shouldClose = [controller endOfInputReached]; // Lets us know if we should keep going or not (occassionally, for track changes within a file)
DLog(@"closing? is %i", shouldClose);
// Move this here, so that the above endOfInputReached has a chance to queue another track before starting output
// Technically, the output should still play out its buffer first before checking if it should stop
if(initialBufferFilled == NO) {
[controller initialBufferFilled:self];
}
// wait before exiting, as we might still get seeking request
DLog("InputNode: Before wait")
[exitAtTheEndOfTheStream waitIndefinitely];
DLog("InputNode: After wait, should seek = %d", shouldSeek);
if(shouldSeek) {
endOfStream = NO;
shouldClose = NO;
continue;
} else {
break;
}
}
}
[decoder close];
[converter cleanUp];
if(shouldClose)
[decoder close];
free(inputBuffer);
[exitAtTheEndOfTheStream signal];
threadExited = YES;
DLog("Input node thread stopping");
}
- (void)seek:(double)time
{
seekTime = time;
- (void)seek:(long)frame {
seekFrame = frame;
shouldSeek = YES;
DLog(@"Should seek!");
[self resetBuffer];
[semaphore signal];
[writeSemaphore signal];
if(endOfStream) {
[exitAtTheEndOfTheStream signal];
}
}
- (void)dealloc
{
[decoder removeObserver:self forKeyPath:@"properties"];
[decoder removeObserver:self forKeyPath:@"metadata"];
- (BOOL)setTrack:(NSURL *)track {
if([decoder respondsToSelector:@selector(setTrack:)] && [decoder setTrack:track]) {
DLog(@"SET TRACK!");
[decoder release];
return YES;
}
[super dealloc];
return NO;
}
- (NSDictionary *) properties
{
- (void)removeObservers {
if(observersAdded) {
[decoder removeObserver:self forKeyPath:@"properties" context:kInputNodeContext];
[decoder removeObserver:self forKeyPath:@"metadata" context:kInputNodeContext];
observersAdded = NO;
}
}
- (void)setShouldContinue:(BOOL)s {
[super setShouldContinue:s];
if(!s)
[self removeObservers];
}
- (void)dealloc {
DLog(@"Input Node dealloc");
[self removeObservers];
[super cleanUp];
}
- (NSDictionary *)properties {
return [decoder properties];
}
- (id<CogDecoder>)decoder {
return decoder;
}
- (double)secondsBuffered {
return [buffer listDuration];
}
@end

View file

@ -6,50 +6,100 @@
// Copyright 2006 Vincent Spader. All rights reserved.
//
#import <CogAudio/ChunkList.h>
#import <CogAudio/CogSemaphore.h>
#import <Cocoa/Cocoa.h>
#import "VirtualRingBuffer.h"
#import "Semaphore.h"
#import <os/workgroup.h>
#define BUFFER_SIZE 1024 * 1024
#define CHUNK_SIZE 16 * 1024
@interface Node : NSObject {
VirtualRingBuffer *buffer;
Semaphore *semaphore;
NSLock *readLock;
NSLock *writeLock;
//#define LOG_CHAINS 1
id previousNode;
id controller;
@interface Node : NSObject {
ChunkList *buffer;
Semaphore *writeSemaphore;
Semaphore *readSemaphore;
NSLock *accessLock;
id __weak previousNode;
id __weak controller;
BOOL shouldReset;
BOOL inWrite;
BOOL inPeek;
BOOL inRead;
BOOL inMerge;
BOOL shouldContinue;
BOOL endOfStream; //All data is now in buffer
BOOL endOfStream; // All data is now in buffer
BOOL initialBufferFilled;
AudioStreamBasicDescription nodeFormat;
uint32_t nodeChannelConfig;
BOOL nodeLossless;
double durationPrebuffer;
#ifdef LOG_CHAINS
NSFileHandle *logFileOut;
NSFileHandle *logFileIn;
#endif
}
- (id)initWithController:(id)c previous:(id)p;
- (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p;
- (int)writeData:(void *)ptr amount:(int)a;
- (int)readData:(void *)ptr amount:(int)a;
#ifdef LOG_CHAINS
- (void)initLogFiles;
#endif
- (void)process; //Should be overwriten by subclass
- (void)threadEntry:(id)arg;
- (void)cleanUp;
- (BOOL)paused;
- (void)writeData:(const void *_Nonnull)ptr amount:(size_t)a;
- (void)writeChunk:(AudioChunk *_Nonnull)chunk;
- (AudioChunk *_Nonnull)readChunk:(size_t)maxFrames;
- (AudioChunk *_Nonnull)readChunkAsFloat32:(size_t)maxFrames;
- (AudioChunk *_Nonnull)readAndMergeChunks:(size_t)maxFrames;
- (AudioChunk *_Nonnull)readAndMergeChunksAsFloat32:(size_t)maxFrames;
- (BOOL)peekFormat:(AudioStreamBasicDescription *_Nonnull)format channelConfig:(uint32_t *_Nonnull)config;
- (BOOL)peekTimestamp:(double *_Nonnull)timestamp timeRatio:(double *_Nonnull)timeRatio;
- (void)process; // Should be overwriten by subclass
- (void)threadEntry:(id _Nullable)arg;
- (void)launchThread;
- (NSLock *)readLock;
- (NSLock *)writeLock;
- (void)setShouldReset:(BOOL)s;
- (BOOL)shouldReset;
- (void)resetBackwards;
- (id)previousNode;
- (void)setPreviousNode:(id _Nullable)p;
- (id _Nullable)previousNode;
- (BOOL)shouldContinue;
- (void)setShouldContinue:(BOOL)s;
- (VirtualRingBuffer *)buffer;
- (void)resetBuffer; //WARNING! DANGER WILL ROBINSON!
- (ChunkList *_Nonnull)buffer;
- (void)resetBuffer; // WARNING! DANGER WILL ROBINSON!
- (Semaphore *)semaphore;
- (AudioStreamBasicDescription)nodeFormat;
- (uint32_t)nodeChannelConfig;
- (BOOL)nodeLossless;
- (Semaphore *_Nonnull)writeSemaphore;
- (Semaphore *_Nonnull)readSemaphore;
//-(void)resetBuffer;
- (BOOL)endOfStream;
- (void)setEndOfStream:(BOOL)e;
- (double)secondsBuffered;
@end

View file

@ -8,191 +8,658 @@
#import "Node.h"
#import "BufferChain.h"
#import "Logging.h"
#import "OutputCoreAudio.h"
#import <pthread.h>
#import <mach/mach_time.h>
#ifdef LOG_CHAINS
#import "NSFileHandle+CreateFile.h"
static NSLock * _Node_lock = nil;
static uint64_t _Node_serial;
#endif
@implementation Node
- (id)initWithController:(id)c previous:(id)p
{
#ifdef LOG_CHAINS
+ (void)initialize {
@synchronized (_Node_lock) {
if(!_Node_lock) {
_Node_lock = [[NSLock alloc] init];
_Node_serial = 0;
}
}
}
- (void)initLogFiles {
[_Node_lock lock];
logFileOut = [NSFileHandle fileHandleForWritingAtPath:[NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%@_output_%08lld.raw", [self className], _Node_serial++]] createFile:YES];
logFileIn = [NSFileHandle fileHandleForWritingAtPath:[NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%@_input_%08lld.raw", [self className], _Node_serial++]] createFile:YES];
[_Node_lock unlock];
}
#endif
- (id)initWithController:(id)c previous:(id)p {
self = [super init];
if (self)
{
buffer = [[VirtualRingBuffer alloc] initWithLength:BUFFER_SIZE];
semaphore = [[Semaphore alloc] init];
readLock = [[NSLock alloc] init];
writeLock = [[NSLock alloc] init];
if(self) {
buffer = [[ChunkList alloc] initWithMaximumDuration:10.0];
writeSemaphore = [[Semaphore alloc] init];
readSemaphore = [[Semaphore alloc] init];
accessLock = [[NSLock alloc] init];
initialBufferFilled = NO;
controller = c;
previousNode = p;
endOfStream = NO;
shouldContinue = YES;
nodeChannelConfig = 0;
nodeLossless = NO;
durationPrebuffer = 2.0;
inWrite = NO;
inPeek = NO;
inRead = NO;
inMerge = NO;
[self setPreviousNode:p];
#ifdef LOG_CHAINS
[self initLogFiles];
#endif
}
return self;
}
- (int)writeData:(void *)ptr amount:(int)amount
{
void *writePtr;
int amountToCopy, availOutput;
int amountLeft = amount;
- (void)dealloc {
[self cleanUp];
}
[writeLock lock];
while (shouldContinue == YES && amountLeft > 0)
{
availOutput = [buffer lengthAvailableToWriteReturningPointer:&writePtr];
if (availOutput == 0)
{
[writeLock unlock];
if (initialBufferFilled == NO) {
initialBufferFilled = YES;\
if ([controller respondsToSelector:@selector(initialBufferFilled)])
[controller performSelector:@selector(initialBufferFilled)];
}
[semaphore wait];
[writeLock lock];
- (void)cleanUp {
[self setShouldContinue:NO];
while(inWrite || inPeek || inRead || inMerge) {
[writeSemaphore signal];
if(previousNode) {
[[previousNode readSemaphore] signal];
}
else
{
amountToCopy = availOutput;
if (amountToCopy > amountLeft)
amountToCopy = amountLeft;
usleep(500);
}
}
memcpy(writePtr, &((char *)ptr)[amount - amountLeft], amountToCopy);
if (amountToCopy > 0)
{
[buffer didWriteLength:amountToCopy];
}
- (AudioStreamBasicDescription)nodeFormat {
return nodeFormat;
}
amountLeft -= amountToCopy;
- (uint32_t)nodeChannelConfig {
return nodeChannelConfig;
}
- (BOOL)nodeLossless {
return nodeLossless;
}
- (void)writeData:(const void *)ptr amount:(size_t)amount {
inWrite = YES;
if(!shouldContinue || [self paused]) {
inWrite = NO;
return;
}
[accessLock lock];
AudioChunk *chunk = [[AudioChunk alloc] init];
[chunk setFormat:nodeFormat];
if(nodeChannelConfig) {
[chunk setChannelConfig:nodeChannelConfig];
}
[chunk setLossless:nodeLossless];
[chunk assignSamples:ptr frameCount:amount / nodeFormat.mBytesPerPacket];
#ifdef LOG_CHAINS
if(logFileOut) {
[logFileOut writeData:[NSData dataWithBytes:ptr length:amount]];
}
#endif
double durationList = [buffer listDuration];
double durationLeft = [buffer maxDuration] - durationList;
if(shouldContinue == YES && durationList >= durationPrebuffer) {
if(initialBufferFilled == NO) {
initialBufferFilled = YES;
if([controller respondsToSelector:@selector(initialBufferFilled:)])
[controller performSelector:@selector(initialBufferFilled:) withObject:self];
}
}
[writeLock unlock];
return (amount - amountLeft);
while(shouldContinue == YES && ![self paused] && durationLeft < 0.0) {
if(durationLeft < 0.0 || shouldReset) {
[accessLock unlock];
[writeSemaphore timedWait:2000];
[accessLock lock];
}
durationLeft = [buffer maxDuration] - [buffer listDuration];
}
BOOL doSignal = NO;
if([chunk frameCount]) {
[buffer addChunk:chunk];
doSignal = YES;
}
[accessLock unlock];
if(doSignal) {
[readSemaphore signal];
}
inWrite = NO;
}
//Should be overwriten by subclass.
- (void)process
{
- (void)writeChunk:(AudioChunk *)chunk {
inWrite = YES;
if(!shouldContinue || [self paused]) {
inWrite = NO;
return;
}
[accessLock lock];
double durationList = [buffer listDuration];
double durationLeft = [buffer maxDuration] - durationList;
if(shouldContinue == YES && durationList >= durationPrebuffer) {
if(initialBufferFilled == NO) {
initialBufferFilled = YES;
if([controller respondsToSelector:@selector(initialBufferFilled:)])
[controller performSelector:@selector(initialBufferFilled:) withObject:self];
}
}
while(shouldContinue == YES && ![self paused] && durationLeft < 0.0) {
if(previousNode && [previousNode shouldContinue] == NO) {
shouldContinue = NO;
break;
}
if(durationLeft < 0.0 || shouldReset) {
[accessLock unlock];
[writeSemaphore timedWait:2000];
[accessLock lock];
}
durationLeft = [buffer maxDuration] - [buffer listDuration];
}
BOOL doSignal = NO;
if([chunk frameCount]) {
#ifdef LOG_CHAINS
if(logFileOut) {
AudioChunk *chunkCopy = [chunk copy];
size_t frameCount = [chunkCopy frameCount];
NSData *chunkData = [chunkCopy removeSamples:frameCount];
[logFileOut writeData:chunkData];
}
#endif
[buffer addChunk:chunk];
doSignal = YES;
}
[accessLock unlock];
if(doSignal) {
[readSemaphore signal];
}
inWrite = NO;
}
- (void)threadEntry:(id)arg
{
[self retain];
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
[self process];
[pool release];
[self release];
// Should be overwriten by subclass.
- (void)process {
}
- (int)readData:(void *)ptr amount:(int)amount
{
void *readPtr;
int amountToCopy;
int availInput;
[readLock lock];
availInput = [[previousNode buffer] lengthAvailableToReadReturningPointer:&readPtr];
if (availInput <= amount && [previousNode endOfStream] == YES)
{
// [previousNode release];
//If it is the outputNode, [soundController newInputChain];
//else
endOfStream = YES;
- (void)threadEntry:(id)arg {
@autoreleasepool {
[self process];
}
/* if (availInput <= 0) {
NSLog(@"BUFFER RAN DRY!");
}
else if (availInput < amount) {
NSLog(@"BUFFER IN DANGER");
}
*/
amountToCopy = availInput;
if (amountToCopy > amount)
{
amountToCopy = amount;
}
memcpy(ptr, readPtr, amountToCopy);
if (amountToCopy > 0)
{
[[previousNode buffer] didReadLength:amountToCopy];
[[previousNode semaphore] signal];
}
[readLock unlock];
return amountToCopy;
}
- (void)launchThread
{
- (BOOL)peekFormat:(nonnull AudioStreamBasicDescription *)format channelConfig:(nonnull uint32_t *)config {
inPeek = YES;
if(!shouldContinue || [self paused]) {
inPeek = NO;
return NO;
}
[accessLock lock];
while(shouldContinue && ![self paused] &&
[[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) {
[accessLock unlock];
[writeSemaphore signal];
[[previousNode readSemaphore] timedWait:2000];
[accessLock lock];
}
if(!shouldContinue || [self paused]) {
[accessLock unlock];
inPeek = NO;
return NO;
}
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
[accessLock unlock];
inPeek = NO;
return NO;
}
BOOL ret = [[previousNode buffer] peekFormat:format channelConfig:config];
[accessLock unlock];
inPeek = NO;
return ret;
}
- (BOOL)peekTimestamp:(double *_Nonnull)timestamp timeRatio:(double *_Nonnull)timeRatio {
inPeek = YES;
if(!shouldContinue || [self paused]) {
inPeek = NO;
return NO;
}
[accessLock lock];
while(shouldContinue && ![self paused] &&
[[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) {
[accessLock unlock];
[writeSemaphore signal];
[[previousNode readSemaphore] timedWait:2000];
[accessLock lock];
}
if(!shouldContinue || [self paused]) {
[accessLock unlock];
inPeek = NO;
return NO;
}
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
[accessLock unlock];
inPeek = NO;
return NO;
}
BOOL ret = [[previousNode buffer] peekTimestamp:timestamp timeRatio:timeRatio];
[accessLock unlock];
inPeek = NO;
return ret;
}
- (AudioChunk *)readChunk:(size_t)maxFrames {
inRead = YES;
if(!shouldContinue || [self paused]) {
inRead = NO;
return [[AudioChunk alloc] init];
}
[accessLock lock];
while(shouldContinue && ![self paused] &&
[[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) {
[accessLock unlock];
[writeSemaphore signal];
[[previousNode readSemaphore] timedWait:2000];
[accessLock lock];
if([previousNode shouldReset] == YES) {
break;
}
}
if(!shouldContinue || [self paused]) {
[accessLock unlock];
inRead = NO;
return [[AudioChunk alloc] init];
}
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
[accessLock unlock];
inRead = NO;
return [[AudioChunk alloc] init];
}
if([previousNode shouldReset] == YES) {
@autoreleasepool {
[buffer reset];
}
shouldReset = YES;
[previousNode setShouldReset:NO];
[[previousNode writeSemaphore] signal];
}
AudioChunk *ret;
@autoreleasepool {
ret = [[previousNode buffer] removeSamples:maxFrames];
}
[accessLock unlock];
if([ret frameCount]) {
[[previousNode writeSemaphore] signal];
}
#ifdef LOG_CHAINS
if(logFileIn) {
AudioChunk *chunkCopy = [ret copy];
size_t frameCount = [chunkCopy frameCount];
NSData *chunkData = [chunkCopy removeSamples:frameCount];
[logFileIn writeData:chunkData];
}
#endif
inRead = NO;
return ret;
}
- (AudioChunk *)readChunkAsFloat32:(size_t)maxFrames {
inRead = YES;
if(!shouldContinue || [self paused]) {
inRead = NO;
return [[AudioChunk alloc] init];
}
[accessLock lock];
while(shouldContinue && ![self paused] &&
[[previousNode buffer] isEmpty] && [previousNode endOfStream] == NO) {
[accessLock unlock];
[writeSemaphore signal];
[[previousNode readSemaphore] timedWait:2000];
[accessLock lock];
if([previousNode shouldReset] == YES) {
break;
}
}
if(!shouldContinue || [self paused]) {
[accessLock unlock];
inRead = NO;
return [[AudioChunk alloc] init];
}
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
[accessLock unlock];
inRead = NO;
return [[AudioChunk alloc] init];
}
if([previousNode shouldReset] == YES) {
@autoreleasepool {
[buffer reset];
}
shouldReset = YES;
[previousNode setShouldReset:NO];
[[previousNode writeSemaphore] signal];
}
AudioChunk *ret;
@autoreleasepool {
ret = [[previousNode buffer] removeSamplesAsFloat32:maxFrames];
}
[accessLock unlock];
if([ret frameCount]) {
[[previousNode writeSemaphore] signal];
}
#ifdef LOG_CHAINS
if(logFileIn) {
AudioChunk *chunkCopy = [ret copy];
size_t frameCount = [chunkCopy frameCount];
NSData *chunkData = [chunkCopy removeSamples:frameCount];
[logFileIn writeData:chunkData];
}
#endif
inRead = NO;
return ret;
}
- (AudioChunk *)readAndMergeChunks:(size_t)maxFrames {
inMerge = YES;
if(!shouldContinue || [self paused]) {
inMerge = NO;
return [[AudioChunk alloc] init];
}
[accessLock lock];
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
[accessLock unlock];
inMerge = NO;
return [[AudioChunk alloc] init];
}
AudioChunk *ret;
@autoreleasepool {
ret = [[previousNode buffer] removeAndMergeSamples:maxFrames callBlock:^BOOL{
if([previousNode shouldReset] == YES) {
@autoreleasepool {
[buffer reset];
}
shouldReset = YES;
[previousNode setShouldReset:NO];
}
[accessLock unlock];
[[previousNode writeSemaphore] signal];
[[previousNode readSemaphore] timedWait:2000];
[accessLock lock];
return !shouldContinue || [self paused] || ([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES);
}];
}
[accessLock unlock];
if([ret frameCount]) {
[[previousNode writeSemaphore] signal];
#ifdef LOG_CHAINS
if(logFileIn) {
AudioChunk *chunkCopy = [ret copy];
size_t frameCount = [chunkCopy frameCount];
NSData *chunkData = [chunkCopy removeSamples:frameCount];
[logFileIn writeData:chunkData];
}
#endif
}
inMerge = NO;
return ret;
}
- (AudioChunk *)readAndMergeChunksAsFloat32:(size_t)maxFrames {
inMerge = YES;
if(!shouldContinue || [self paused]) {
inMerge = NO;
return [[AudioChunk alloc] init];
}
[accessLock lock];
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
[accessLock unlock];
inMerge = NO;
return [[AudioChunk alloc] init];
}
AudioChunk *ret;
@autoreleasepool {
ret = [[previousNode buffer] removeAndMergeSamplesAsFloat32:maxFrames callBlock:^BOOL{
if([previousNode shouldReset] == YES) {
@autoreleasepool {
[buffer reset];
}
shouldReset = YES;
[previousNode setShouldReset:NO];
}
[accessLock unlock];
[[previousNode writeSemaphore] signal];
[[previousNode readSemaphore] timedWait:2000];
[accessLock lock];
return !shouldContinue || [self paused] || ([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES);
}];
}
[accessLock unlock];
if([ret frameCount]) {
[[previousNode writeSemaphore] signal];
#ifdef LOG_CHAINS
if(logFileIn) {
AudioChunk *chunkCopy = [ret copy];
size_t frameCount = [chunkCopy frameCount];
NSData *chunkData = [chunkCopy removeSamples:frameCount];
[logFileIn writeData:chunkData];
}
#endif
}
inMerge = NO;
return ret;
}
- (void)launchThread {
[NSThread detachNewThreadSelector:@selector(threadEntry:) toTarget:self withObject:nil];
}
- (id)previousNode
{
- (void)setPreviousNode:(id)p {
previousNode = p;
}
- (id)previousNode {
return previousNode;
}
- (BOOL)shouldContinue
{
- (BOOL)shouldContinue {
return shouldContinue;
}
- (void)setShouldContinue:(BOOL)s
{
- (void)setShouldContinue:(BOOL)s {
shouldContinue = s;
}
- (VirtualRingBuffer *)buffer
{
- (ChunkList *)buffer {
return buffer;
}
- (void)resetBuffer
{
[readLock lock];
[writeLock lock];
[buffer empty];
[writeLock unlock];
[readLock unlock];
- (void)resetBuffer {
shouldReset = YES; // Will reset on next write.
if(previousNode == nil) {
@autoreleasepool {
[accessLock lock];
[buffer reset];
[accessLock unlock];
}
}
}
- (NSLock *)readLock
{
return readLock;
- (void)lockedResetBuffer {
@autoreleasepool {
[buffer reset];
}
}
- (NSLock *)writeLock
{
return writeLock;
- (void)unlockedResetBuffer {
@autoreleasepool {
[accessLock lock];
[buffer reset];
[accessLock unlock];
}
}
- (Semaphore *)semaphore
{
return semaphore;
// Implementations should override
- (BOOL)paused {
return NO;
}
- (BOOL)endOfStream
{
- (Semaphore *)writeSemaphore {
return writeSemaphore;
}
- (Semaphore *)readSemaphore {
return readSemaphore;
}
- (BOOL)endOfStream {
return endOfStream;
}
- (void)setEndOfStream:(BOOL)e
{
- (void)setEndOfStream:(BOOL)e {
endOfStream = e;
}
- (void)setShouldReset:(BOOL)s {
shouldReset = s;
}
- (BOOL)shouldReset {
return shouldReset;
}
// Buffering nodes should implement this
- (double)secondsBuffered {
return 0.0;
}
// Reset everything in the chain
- (void)resetBackwards {
[accessLock lock];
if(buffer) {
[self lockedResetBuffer];
[writeSemaphore signal];
[readSemaphore signal];
}
Node *node = previousNode;
while(node) {
[node unlockedResetBuffer];
[node setShouldReset:YES];
[[node writeSemaphore] signal];
[[node readSemaphore] signal];
node = [node previousNode];
}
[accessLock unlock];
}
@end

View file

@ -8,37 +8,84 @@
#import <Cocoa/Cocoa.h>
#import <CoreAudio/AudioHardware.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AudioUnit/AudioUnit.h>
#import <CoreAudio/AudioHardware.h>
#import "Node.h"
#import "OutputCoreAudio.h"
#import <CogAudio/Node.h>
#import <CogAudio/OutputCoreAudio.h>
@interface OutputNode : Node {
AudioStreamBasicDescription format;
uint32_t config;
unsigned long amountPlayed;
double amountPlayed;
double amountPlayedInterval;
OutputCoreAudio *output;
BOOL paused;
BOOL started;
BOOL intervalReported;
}
- (double)amountPlayed;
- (double)amountPlayedInterval;
- (void)incrementAmountPlayed:(double)seconds;
- (void)setAmountPlayed:(double)seconds;
- (void)resetAmountPlayed;
- (void)resetAmountPlayedInterval;
- (BOOL)selectNextBuffer;
- (void)endOfInputPlayed;
- (BOOL)endOfStream;
- (BOOL)chainQueueHasTracks;
- (double)secondsBuffered;
- (void)setup;
- (void)setupWithInterval:(BOOL)resumeInterval;
- (void)process;
- (void)close;
- (void)seek:(double)time;
- (int)readData:(void *)ptr amount:(int)amount;
- (void)fadeOut;
- (void)fadeOutBackground;
- (void)fadeIn;
- (void)setFormat:(AudioStreamBasicDescription *)f;
- (AudioStreamBasicDescription) format;
- (AudioChunk *)readChunk:(size_t)amount;
- (void)setVolume:(double) v;
- (void)setFormat:(AudioStreamBasicDescription *)f channelConfig:(uint32_t)channelConfig;
- (AudioStreamBasicDescription)format;
- (uint32_t)config;
- (AudioStreamBasicDescription)deviceFormat;
- (uint32_t)deviceChannelConfig;
- (double)volume;
- (void)setVolume:(double)v;
- (void)setShouldContinue:(BOOL)s;
- (void)setShouldPlayOutBuffer:(BOOL)s;
- (void)pause;
- (void)resume;
- (BOOL)isPaused;
- (void)sustainHDCD;
- (void)restartPlaybackAtCurrentPosition;
- (double)latency;
- (double)getVisLatency;
- (double)getTotalLatency;
- (id)controller;
- (id)downmix;
@end

View file

@ -7,106 +7,384 @@
//
#import "OutputNode.h"
#import "OutputCoreAudio.h"
#import "AudioPlayer.h"
#import "BufferChain.h"
#import "OutputCoreAudio.h"
@implementation OutputNode
#import "DSPRubberbandNode.h"
#import "DSPFSurroundNode.h"
#import "DSPHRTFNode.h"
#import "DSPEqualizerNode.h"
#import "VisualizationNode.h"
#import "DSPDownmixNode.h"
- (void)setup
{
amountPlayed = 0;
#import "Logging.h"
@implementation OutputNode {
BOOL DSPsLaunched;
Node *previousInput;
DSPRubberbandNode *rubberbandNode;
DSPFSurroundNode *fsurroundNode;
DSPHRTFNode *hrtfNode;
DSPEqualizerNode *equalizerNode;
DSPDownmixNode *downmixNode;
VisualizationNode *visualizationNode;
}
- (void)setup {
[self setupWithInterval:NO];
}
- (void)setupWithInterval:(BOOL)resumeInterval {
if(!resumeInterval) {
amountPlayed = 0.0;
amountPlayedInterval = 0.0;
intervalReported = NO;
}
paused = YES;
started = NO;
output = [[OutputCoreAudio alloc] initWithController:self];
[output setup];
if(!DSPsLaunched) {
rubberbandNode = [[DSPRubberbandNode alloc] initWithController:self previous:nil latency:0.1];
if(!rubberbandNode) return;
fsurroundNode = [[DSPFSurroundNode alloc] initWithController:self previous:rubberbandNode latency:0.03];
if(!fsurroundNode) return;
equalizerNode = [[DSPEqualizerNode alloc] initWithController:self previous:fsurroundNode latency:0.03];
if(!equalizerNode) return;
hrtfNode = [[DSPHRTFNode alloc] initWithController:self previous:equalizerNode latency:0.03];
if(!hrtfNode) return;
downmixNode = [[DSPDownmixNode alloc] initWithController:self previous:hrtfNode latency:0.03];
if(!downmixNode) return;
// Approximately double the chunk size for Vis at 44100Hz
visualizationNode = [[VisualizationNode alloc] initWithController:self previous:downmixNode latency:8192.0 / 44100.0];
if(!visualizationNode) return;
[self setPreviousNode:visualizationNode];
DSPsLaunched = YES;
[self launchDSPs];
previousInput = nil;
}
}
- (void)seek:(double)time
{
[output pause];
- (void)seek:(double)time {
// [output pause];
[self resetBuffer];
amountPlayed = time*format.mBytesPerFrame*(format.mSampleRate/1000.0);
amountPlayed = time;
}
- (void)process
{
- (void)process {
paused = NO;
[output start];
}
- (void)pause
{
- (void)pause {
paused = YES;
[output pause];
}
- (void)resume
{
- (void)resume {
paused = NO;
[output resume];
}
- (int)readData:(void *)ptr amount:(int)amount
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int n;
previousNode = [[controller bufferChain] finalNode];
n = [super readData:ptr amount:amount];
if (endOfStream == YES)
{
amountPlayed = 0;
[controller endOfInputPlayed]; //Updates shouldContinue appropriately?
}
/* if (n == 0) {
NSLog(@"Output Buffer dry!");
}
*/
amountPlayed += n;
[pool release];
return n;
- (void)fadeOut {
[output fadeOut];
}
- (double)amountPlayed
{
return (amountPlayed/format.mBytesPerFrame)/(format.mSampleRate/1000.0);
- (void)fadeOutBackground {
[output fadeOutBackground];
}
- (AudioStreamBasicDescription) format
{
- (void)fadeIn {
[self reconnectInputAndReplumb];
[output fadeIn];
}
- (void)incrementAmountPlayed:(double)seconds {
amountPlayed += seconds;
amountPlayedInterval += seconds;
if(!intervalReported && amountPlayedInterval >= 60.0) {
intervalReported = YES;
[controller reportPlayCount];
}
}
- (void)setAmountPlayed:(double)seconds {
double delta = seconds - amountPlayed;
if(delta > 0.0 && delta < 5.0) {
[self incrementAmountPlayed:delta];
} else if(delta) {
amountPlayed = seconds;
}
}
- (void)resetAmountPlayed {
amountPlayed = 0;
}
- (void)resetAmountPlayedInterval {
amountPlayedInterval = 0;
intervalReported = NO;
}
- (BOOL)selectNextBuffer {
BOOL ret = [controller selectNextBuffer];
if(!ret) {
[self reconnectInputAndReplumb];
}
return ret;
}
- (void)endOfInputPlayed {
if(!intervalReported) {
intervalReported = YES;
[controller reportPlayCount];
}
[controller endOfInputPlayed];
[self resetAmountPlayedInterval];
}
- (BOOL)chainQueueHasTracks {
return [controller chainQueueHasTracks];
}
- (double)secondsBuffered {
return [buffer listDuration];
}
- (NSArray *)DSPs {
if(DSPsLaunched) {
return @[rubberbandNode, fsurroundNode, equalizerNode, hrtfNode, downmixNode, visualizationNode];
} else {
return @[];
}
}
- (BOOL)reconnectInput {
Node *finalNode = nil;
if(rubberbandNode) {
finalNode = [[controller bufferChain] finalNode];
[rubberbandNode setPreviousNode:finalNode];
}
return !!finalNode;
}
- (void)reconnectInputAndReplumb {
Node *finalNode = nil;
if(rubberbandNode) {
finalNode = [[controller bufferChain] finalNode];
[rubberbandNode setPreviousNode:finalNode];
}
NSArray *DSPs = [self DSPs];
for (Node *node in DSPs) {
[node setEndOfStream:NO];
[node setShouldContinue:YES];
}
}
- (void)launchDSPs {
NSArray *DSPs = [self DSPs];
for (Node *node in DSPs) {
[node launchThread];
}
}
- (AudioChunk *)readChunk:(size_t)amount {
@autoreleasepool {
if([self reconnectInput]) {
AudioChunk *ret = [super readChunk:amount];
if((!ret || ![ret frameCount]) && [previousNode endOfStream]) {
endOfStream = YES;
}
return ret;
} else {
return [[AudioChunk alloc] init];
}
}
}
- (BOOL)peekFormat:(nonnull AudioStreamBasicDescription *)format channelConfig:(nonnull uint32_t *)config {
@autoreleasepool {
if([self reconnectInput]) {
BOOL ret = [super peekFormat:format channelConfig:config];
if(!ret && [previousNode endOfStream]) {
endOfStream = YES;
}
return ret;
} else {
return NO;
}
}
}
- (double)amountPlayed {
return amountPlayed;
}
- (double)amountPlayedInterval {
return amountPlayedInterval;
}
- (AudioStreamBasicDescription)format {
return format;
}
- (void)setFormat:(AudioStreamBasicDescription *)f
{
- (uint32_t)config {
return config;
}
- (AudioStreamBasicDescription)deviceFormat {
return [output deviceFormat];
}
- (uint32_t)deviceChannelConfig {
return [output deviceChannelConfig];
}
- (void)setFormat:(AudioStreamBasicDescription *)f channelConfig:(uint32_t)channelConfig {
if(!shouldContinue) return;
format = *f;
config = channelConfig;
// Calculate a ratio and add to double(seconds) instead, as format may change
// double oldSampleRatio = sampleRatio;
AudioPlayer *audioPlayer = controller;
BufferChain *bufferChain = [audioPlayer bufferChain];
if(bufferChain) {
ConverterNode *converter = [bufferChain converter];
AudioStreamBasicDescription outputFormat;
uint32_t outputChannelConfig;
BOOL formatChanged = NO;
if(converter) {
AudioStreamBasicDescription converterFormat = [converter nodeFormat];
if(memcmp(&converterFormat, &format, sizeof(converterFormat)) != 0) {
formatChanged = YES;
}
}
if(downmixNode && output && !formatChanged) {
outputFormat = [output deviceFormat];
outputChannelConfig = [output deviceChannelConfig];
AudioStreamBasicDescription currentOutputFormat = [downmixNode nodeFormat];
uint32_t currentOutputChannelConfig = [downmixNode nodeChannelConfig];
if(memcmp(&currentOutputFormat, &outputFormat, sizeof(currentOutputFormat)) != 0 ||
currentOutputChannelConfig != outputChannelConfig) {
formatChanged = YES;
}
}
if(formatChanged) {
InputNode *inputNode = [bufferChain inputNode];
if(converter) {
[converter setOutputFormat:format];
}
if(downmixNode && output) {
[downmixNode setOutputFormat:[output deviceFormat] withChannelConfig:[output deviceChannelConfig]];
}
if(inputNode) {
AudioStreamBasicDescription inputFormat = [inputNode nodeFormat];
if(converter) {
[converter inputFormatDidChange:inputFormat inputConfig:[inputNode nodeChannelConfig]];
}
[inputNode seek:(long)(amountPlayed * inputFormat.mSampleRate)];
}
}
}
}
- (void)close
{
- (void)close {
[output stop];
output = nil;
if(DSPsLaunched) {
NSArray *DSPs = [self DSPs];
for(Node *node in DSPs) {
[node setShouldContinue:NO];
}
previousNode = nil;
visualizationNode = nil;
downmixNode = nil;
hrtfNode = nil;
fsurroundNode = nil;
rubberbandNode = nil;
previousInput = nil;
DSPsLaunched = NO;
}
}
- (void)dealloc
{
[output release];
[super dealloc];
- (double)volume {
return [output volume];
}
- (void)setVolume:(double) v
{
- (void)setVolume:(double)v {
[output setVolume:v];
}
- (void)setShouldContinue:(BOOL)s
{
- (void)setShouldContinue:(BOOL)s {
[super setShouldContinue:s];
// if (s == NO)
// [output stop];
NSArray *DSPs = [self DSPs];
for(Node *node in DSPs) {
[node setShouldContinue:s];
}
// if (s == NO)
// [output stop];
}
- (void)setShouldPlayOutBuffer:(BOOL)s {
[output setShouldPlayOutBuffer:s];
}
- (BOOL)isPaused {
return paused;
}
- (void)sustainHDCD {
[output sustainHDCD];
}
- (void)restartPlaybackAtCurrentPosition {
[controller restartPlaybackAtCurrentPosition];
}
- (double)latency {
double latency = 0.0;
NSArray *DSPs = [self DSPs];
for(Node *node in DSPs) {
latency += [node secondsBuffered];
}
return [output latency] + latency;
}
- (double)getVisLatency {
return [output latency] + [visualizationNode secondsBuffered];
}
- (double)getTotalLatency {
return [[controller bufferChain] secondsBuffered] + [self latency];
}
- (id)controller {
return controller;
}
- (id)downmix {
return downmixNode;
}
@end

View file

@ -0,0 +1,35 @@
//
// VisualizationNode.h
// CogAudio
//
// Created by Christopher Snowhill on 2/12/25.
//
#ifndef VisualizationNode_h
#define VisualizationNode_h
#import <CogAudio/Node.h>
@interface VisualizationNode : Node {
}
- (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p latency:(double)latency;
- (void)threadEntry:(id _Nullable)arg;
- (BOOL)setup;
- (void)cleanUp;
- (BOOL)paused;
- (void)resetBuffer;
- (void)setShouldContinue:(BOOL)s;
- (void)process;
- (double)secondsBuffered;
@end
#endif /* VisualizationNode_h */

View file

@ -0,0 +1,273 @@
//
// VisualizationNode.m
// CogAudio Framework
//
// Created by Christopher Snowhill on 2/12/25.
//
#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import <Accelerate/Accelerate.h>
#import "Downmix.h"
#import <CogAudio/VisualizationController.h>
#import "BufferChain.h"
#import "Logging.h"
#import "rsstate.h"
#import "VisualizationNode.h"
@implementation VisualizationNode {
void *rs;
double lastVisRate;
BOOL processEntered;
BOOL stopping;
BOOL paused;
BOOL threadTerminated;
AudioStreamBasicDescription inputFormat;
AudioStreamBasicDescription visFormat; // Mono format for vis
uint32_t inputChannelConfig;
uint32_t visChannelConfig;
size_t resamplerRemain;
DownmixProcessor *downmixer;
VisualizationController *visController;
float visAudio[512];
float resamplerInput[8192];
float visTemp[8192];
}
- (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p latency:(double)latency {
self = [super init];
if(self) {
buffer = [[ChunkList alloc] initWithMaximumDuration:latency];
writeSemaphore = [[Semaphore alloc] init];
readSemaphore = [[Semaphore alloc] init];
accessLock = [[NSLock alloc] init];
initialBufferFilled = NO;
controller = c;
endOfStream = NO;
shouldContinue = YES;
nodeChannelConfig = 0;
nodeLossless = NO;
durationPrebuffer = latency * 0.25;
visController = [VisualizationController sharedController];
inWrite = NO;
inPeek = NO;
inRead = NO;
inMerge = NO;
[self setPreviousNode:p];
}
return self;
}
- (void)dealloc {
DLog(@"Visualization node dealloc");
[self setShouldContinue:NO];
[self cleanUp];
[super cleanUp];
}
// Visualization thread should be fairly high priority, too
- (void)threadEntry:(id _Nullable)arg {
@autoreleasepool {
NSThread *currentThread = [NSThread currentThread];
[currentThread setThreadPriority:0.75];
[currentThread setQualityOfService:NSQualityOfServiceUserInitiated];
threadTerminated = NO;
[self process];
threadTerminated = YES;
}
}
- (void)resetBuffer {
paused = YES;
while(processEntered) {
usleep(500);
}
[buffer reset];
[self fullShutdown];
paused = NO;
}
- (double)secondsBuffered {
return [buffer listDuration];
}
- (void)setShouldContinue:(BOOL)s {
BOOL currentShouldContinue = shouldContinue;
shouldContinue = s;
if(!currentShouldContinue && s && threadTerminated) {
[self launchThread];
}
}
- (BOOL)setup {
if(fabs(inputFormat.mSampleRate - 44100.0) > 1e-6) {
rs = rsstate_new(1, inputFormat.mSampleRate, 44100.0);
if(!rs) {
return NO;
}
resamplerRemain = 0;
}
visFormat = inputFormat;
visFormat.mChannelsPerFrame = 1;
visFormat.mBytesPerFrame = sizeof(float);
visFormat.mBytesPerPacket = visFormat.mBytesPerFrame * visFormat.mFramesPerPacket;
visChannelConfig = AudioChannelFrontCenter;
downmixer = [[DownmixProcessor alloc] initWithInputFormat:inputFormat inputConfig:inputChannelConfig andOutputFormat:visFormat outputConfig:visChannelConfig];
if(!downmixer) {
return NO;
}
return YES;
}
- (void)cleanUp {
stopping = YES;
while(processEntered) {
usleep(500);
}
[self fullShutdown];
}
- (void)fullShutdown {
if(rs) {
rsstate_delete(rs);
rs = NULL;
}
downmixer = nil;
}
- (BOOL)paused {
return paused;
}
- (void)process {
while([self shouldContinue] == YES) {
if(paused || endOfStream) {
usleep(500);
continue;
}
@autoreleasepool {
AudioChunk *chunk = nil;
chunk = [self readAndMergeChunksAsFloat32:512];
if(!chunk || ![chunk frameCount]) {
if([previousNode endOfStream] == YES) {
usleep(500);
endOfStream = YES;
continue;
}
} else {
[self processVis:[chunk copy]];
[self writeChunk:chunk];
chunk = nil;
}
}
}
endOfStream = YES;
}
- (void)postVisPCM:(const float *)visTemp amount:(size_t)samples {
[visController postVisPCM:visTemp amount:(int)samples];
}
- (void)processVis:(AudioChunk *)chunk {
processEntered = YES;
if(paused) {
processEntered = NO;
return;
}
AudioStreamBasicDescription format = [chunk format];
uint32_t channelConfig = [chunk channelConfig];
[visController postSampleRate:44100.0];
if(!rs || !downmixer ||
memcmp(&format, &inputFormat, sizeof(format)) != 0 ||
channelConfig != inputChannelConfig) {
if(rs) {
while(!stopping) {
int samplesFlushed;
samplesFlushed = (int)rsstate_flush(rs, &visTemp[0], 8192);
if(samplesFlushed > 1) {
[self postVisPCM:visTemp amount:samplesFlushed];
} else {
break;
}
}
}
[self fullShutdown];
inputFormat = format;
inputChannelConfig = channelConfig;
if(![self setup]) {
processEntered = NO;
return;
}
}
size_t frameCount = [chunk frameCount];
NSData *sampleData = [chunk removeSamples:frameCount];
[downmixer process:[sampleData bytes] frameCount:frameCount output:&visAudio[0]];
if(rs) {
int samplesProcessed;
size_t totalDone = 0;
size_t inDone = 0;
size_t visFrameCount = frameCount;
do {
if(stopping) {
break;
}
int visTodo = (int)MIN(visFrameCount, resamplerRemain + visFrameCount - 8192);
if(visTodo) {
cblas_scopy(visTodo, &visAudio[0], 1, &resamplerInput[resamplerRemain], 1);
}
visTodo += resamplerRemain;
resamplerRemain = 0;
samplesProcessed = (int)rsstate_resample(rs, &resamplerInput[0], visTodo, &inDone, &visTemp[0], 8192);
resamplerRemain = (int)(visTodo - inDone);
if(resamplerRemain && inDone) {
memmove(&resamplerInput[0], &resamplerInput[inDone], resamplerRemain * sizeof(float));
}
if(samplesProcessed) {
[self postVisPCM:&visTemp[0] amount:samplesProcessed];
}
totalDone += inDone;
visFrameCount -= inDone;
} while(samplesProcessed && visFrameCount);
} else {
[self postVisPCM:&visAudio[0] amount:frameCount];
}
processEntered = NO;
}
@end

View file

@ -0,0 +1 @@
#import "ThirdParty/deadbeef/fft.h"

View file

@ -3,10 +3,12 @@
archiveVersion = 1;
classes = {
};
objectVersion = 42;
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
07DB5F3E0ED353A900C2E3EF /* AudioMetadataWriter.h in Headers */ = {isa = PBXBuildFile; fileRef = 07DB5F3C0ED353A900C2E3EF /* AudioMetadataWriter.h */; };
07DB5F3F0ED353A900C2E3EF /* AudioMetadataWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 07DB5F3D0ED353A900C2E3EF /* AudioMetadataWriter.m */; };
17A2D3C50B8D1D37000778C4 /* AudioDecoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 17A2D3C30B8D1D37000778C4 /* AudioDecoder.h */; settings = {ATTRIBUTES = (Public, ); }; };
17A2D3C60B8D1D37000778C4 /* AudioDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 17A2D3C40B8D1D37000778C4 /* AudioDecoder.m */; };
17ADB13C0B97926D00257CA2 /* AudioSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 17ADB13A0B97926D00257CA2 /* AudioSource.h */; };
@ -23,15 +25,9 @@
17D21CA80B8BE4BA00D1EBDE /* Node.m in Sources */ = {isa = PBXBuildFile; fileRef = 17D21C7D0B8BE4BA00D1EBDE /* Node.m */; };
17D21CA90B8BE4BA00D1EBDE /* OutputNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 17D21C7E0B8BE4BA00D1EBDE /* OutputNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
17D21CAA0B8BE4BA00D1EBDE /* OutputNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 17D21C7F0B8BE4BA00D1EBDE /* OutputNode.m */; };
17D21CC50B8BE4BA00D1EBDE /* OutputCoreAudio.h in Headers */ = {isa = PBXBuildFile; fileRef = 17D21C9C0B8BE4BA00D1EBDE /* OutputCoreAudio.h */; settings = {ATTRIBUTES = (Public, ); }; };
17D21CC60B8BE4BA00D1EBDE /* OutputCoreAudio.m in Sources */ = {isa = PBXBuildFile; fileRef = 17D21C9D0B8BE4BA00D1EBDE /* OutputCoreAudio.m */; };
17D21CC70B8BE4BA00D1EBDE /* Status.h in Headers */ = {isa = PBXBuildFile; fileRef = 17D21C9E0B8BE4BA00D1EBDE /* Status.h */; settings = {ATTRIBUTES = (Public, ); }; };
17D21CDF0B8BE5B400D1EBDE /* VirtualRingBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 17D21CDA0B8BE5B400D1EBDE /* VirtualRingBuffer.h */; settings = {ATTRIBUTES = (Public, ); }; };
17D21CE00B8BE5B400D1EBDE /* VirtualRingBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = 17D21CDB0B8BE5B400D1EBDE /* VirtualRingBuffer.m */; };
17D21CE10B8BE5B400D1EBDE /* DBLog.h in Headers */ = {isa = PBXBuildFile; fileRef = 17D21CDD0B8BE5B400D1EBDE /* DBLog.h */; settings = {ATTRIBUTES = (Public, ); }; };
17D21CE20B8BE5B400D1EBDE /* DBLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 17D21CDE0B8BE5B400D1EBDE /* DBLog.m */; };
17D21CF30B8BE5EF00D1EBDE /* Semaphore.h in Headers */ = {isa = PBXBuildFile; fileRef = 17D21CF10B8BE5EF00D1EBDE /* Semaphore.h */; settings = {ATTRIBUTES = (Public, ); }; };
17D21CF40B8BE5EF00D1EBDE /* Semaphore.m in Sources */ = {isa = PBXBuildFile; fileRef = 17D21CF20B8BE5EF00D1EBDE /* Semaphore.m */; };
17D21CF30B8BE5EF00D1EBDE /* CogSemaphore.h in Headers */ = {isa = PBXBuildFile; fileRef = 17D21CF10B8BE5EF00D1EBDE /* CogSemaphore.h */; settings = {ATTRIBUTES = (Public, ); }; };
17D21CF40B8BE5EF00D1EBDE /* CogSemaphore.m in Sources */ = {isa = PBXBuildFile; fileRef = 17D21CF20B8BE5EF00D1EBDE /* CogSemaphore.m */; };
17D21DAD0B8BE76800D1EBDE /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 17D21DA90B8BE76800D1EBDE /* AudioToolbox.framework */; };
17D21DAE0B8BE76800D1EBDE /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 17D21DAA0B8BE76800D1EBDE /* AudioUnit.framework */; };
17D21DAF0B8BE76800D1EBDE /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 17D21DAB0B8BE76800D1EBDE /* CoreAudio.framework */; };
@ -41,15 +37,89 @@
17D21EBD0B8BF44000D1EBDE /* AudioPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 17D21EBB0B8BF44000D1EBDE /* AudioPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
17D21EBE0B8BF44000D1EBDE /* AudioPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 17D21EBC0B8BF44000D1EBDE /* AudioPlayer.m */; };
17F94DD50B8D0F7000A34E87 /* PluginController.h in Headers */ = {isa = PBXBuildFile; fileRef = 17F94DD30B8D0F7000A34E87 /* PluginController.h */; settings = {ATTRIBUTES = (Public, ); }; };
17F94DD60B8D0F7000A34E87 /* PluginController.m in Sources */ = {isa = PBXBuildFile; fileRef = 17F94DD40B8D0F7000A34E87 /* PluginController.m */; };
17F94DD60B8D0F7000A34E87 /* PluginController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 17F94DD40B8D0F7000A34E87 /* PluginController.mm */; };
17F94DDD0B8D101100A34E87 /* Plugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 17F94DDC0B8D101100A34E87 /* Plugin.h */; settings = {ATTRIBUTES = (Public, ); }; };
831A50142865A7FD0049CFE4 /* rsstate.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 831A50132865A7FD0049CFE4 /* rsstate.hpp */; };
831A50162865A8800049CFE4 /* rsstate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 831A50152865A8800049CFE4 /* rsstate.cpp */; };
831A50182865A8B30049CFE4 /* rsstate.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A50172865A8B30049CFE4 /* rsstate.h */; };
8328995327CB511000D7F028 /* RedundantPlaylistDataStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 8328995127CB510F00D7F028 /* RedundantPlaylistDataStore.m */; };
8328995427CB511000D7F028 /* RedundantPlaylistDataStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 8328995227CB511000D7F028 /* RedundantPlaylistDataStore.h */; };
8328995727CB51B700D7F028 /* SHA256Digest.h in Headers */ = {isa = PBXBuildFile; fileRef = 8328995527CB51B700D7F028 /* SHA256Digest.h */; };
8328995827CB51B700D7F028 /* SHA256Digest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8328995627CB51B700D7F028 /* SHA256Digest.m */; };
8328995A27CB51C900D7F028 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8328995927CB51C900D7F028 /* Security.framework */; };
833442422D6EFA6700C51D38 /* VisualizationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 833442402D6EFA6700C51D38 /* VisualizationController.h */; settings = {ATTRIBUTES = (Public, ); }; };
833442432D6EFA6700C51D38 /* VisualizationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 833442412D6EFA6700C51D38 /* VisualizationController.m */; };
833738EA2D5EA52500278628 /* DSPDownmixNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 833738E92D5EA52500278628 /* DSPDownmixNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
833738EC2D5EA53500278628 /* DSPDownmixNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 833738EB2D5EA53500278628 /* DSPDownmixNode.m */; };
833738EF2D5EA5B700278628 /* Downmix.m in Sources */ = {isa = PBXBuildFile; fileRef = 833738EE2D5EA5B700278628 /* Downmix.m */; };
833738F02D5EA5B700278628 /* Downmix.h in Headers */ = {isa = PBXBuildFile; fileRef = 833738ED2D5EA5B700278628 /* Downmix.h */; settings = {ATTRIBUTES = (Public, ); }; };
8347C7412796C58800FA8A7D /* NSFileHandle+CreateFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8347C73F2796C58800FA8A7D /* NSFileHandle+CreateFile.h */; };
8347C7422796C58800FA8A7D /* NSFileHandle+CreateFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 8347C7402796C58800FA8A7D /* NSFileHandle+CreateFile.m */; };
834A41A9287A90AB00EB9D9B /* freesurround_decoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 834A41A5287A90AB00EB9D9B /* freesurround_decoder.h */; };
834A41AA287A90AB00EB9D9B /* freesurround_decoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 834A41A6287A90AB00EB9D9B /* freesurround_decoder.cpp */; };
834A41AB287A90AB00EB9D9B /* channelmaps.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 834A41A7287A90AB00EB9D9B /* channelmaps.cpp */; };
834A41AC287A90AB00EB9D9B /* channelmaps.h in Headers */ = {isa = PBXBuildFile; fileRef = 834A41A8287A90AB00EB9D9B /* channelmaps.h */; };
834FD4EB27AF8F380063BC83 /* AudioChunk.h in Headers */ = {isa = PBXBuildFile; fileRef = 834FD4EA27AF8F380063BC83 /* AudioChunk.h */; settings = {ATTRIBUTES = (Public, ); }; };
834FD4ED27AF91220063BC83 /* AudioChunk.m in Sources */ = {isa = PBXBuildFile; fileRef = 834FD4EC27AF91220063BC83 /* AudioChunk.m */; };
834FD4F027AF93680063BC83 /* ChunkList.h in Headers */ = {isa = PBXBuildFile; fileRef = 834FD4EE27AF93680063BC83 /* ChunkList.h */; settings = {ATTRIBUTES = (Public, ); }; };
834FD4F127AF93680063BC83 /* ChunkList.m in Sources */ = {isa = PBXBuildFile; fileRef = 834FD4EF27AF93680063BC83 /* ChunkList.m */; };
8350416D28646149006B32CC /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8350416C28646149006B32CC /* CoreMedia.framework */; };
835C88B1279811A500E28EAE /* hdcd_decode2.h in Headers */ = {isa = PBXBuildFile; fileRef = 835C88AF279811A500E28EAE /* hdcd_decode2.h */; };
835C88B2279811A500E28EAE /* hdcd_decode2.c in Sources */ = {isa = PBXBuildFile; fileRef = 835C88B0279811A500E28EAE /* hdcd_decode2.c */; };
835DD2672ACAF1D90057E319 /* OutputCoreAudio.m in Sources */ = {isa = PBXBuildFile; fileRef = 835DD2652ACAF1D90057E319 /* OutputCoreAudio.m */; };
835DD2682ACAF1D90057E319 /* OutputCoreAudio.h in Headers */ = {isa = PBXBuildFile; fileRef = 835DD2662ACAF1D90057E319 /* OutputCoreAudio.h */; settings = {ATTRIBUTES = (Public, ); }; };
835DD2722ACAF5AD0057E319 /* lpc.h in Headers */ = {isa = PBXBuildFile; fileRef = 835DD26D2ACAF5AD0057E319 /* lpc.h */; };
835DD2732ACAF5AD0057E319 /* util.h in Headers */ = {isa = PBXBuildFile; fileRef = 835DD26E2ACAF5AD0057E319 /* util.h */; };
835DD2742ACAF5AD0057E319 /* lpc.c in Sources */ = {isa = PBXBuildFile; fileRef = 835DD26F2ACAF5AD0057E319 /* lpc.c */; };
835FAC5E27BCA14D00BA8562 /* BadSampleCleaner.h in Headers */ = {isa = PBXBuildFile; fileRef = 835FAC5C27BCA14D00BA8562 /* BadSampleCleaner.h */; };
835FAC5F27BCA14D00BA8562 /* BadSampleCleaner.m in Sources */ = {isa = PBXBuildFile; fileRef = 835FAC5D27BCA14D00BA8562 /* BadSampleCleaner.m */; };
83725A9027AA16C90003F694 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83725A7B27AA0D8A0003F694 /* Accelerate.framework */; };
83725A9127AA16D50003F694 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83725A7C27AA0D8E0003F694 /* AVFoundation.framework */; };
8377C64C27B8C51500E8BC0F /* fft_accelerate.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377C64B27B8C51500E8BC0F /* fft_accelerate.c */; };
8377C64E27B8C54400E8BC0F /* fft.h in Headers */ = {isa = PBXBuildFile; fileRef = 8377C64D27B8C54400E8BC0F /* fft.h */; };
8384912718080FF100E7332D /* Logging.h in Headers */ = {isa = PBXBuildFile; fileRef = 8384912618080FF100E7332D /* Logging.h */; };
838A33722D06A97D00D0D770 /* librubberband.3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 838A33712D06A97D00D0D770 /* librubberband.3.dylib */; };
839065F32853338700636FBB /* dsd2float.h in Headers */ = {isa = PBXBuildFile; fileRef = 839065F22853338700636FBB /* dsd2float.h */; };
839366671815923C006DD712 /* CogPluginMulti.h in Headers */ = {isa = PBXBuildFile; fileRef = 839366651815923C006DD712 /* CogPluginMulti.h */; };
839366681815923C006DD712 /* CogPluginMulti.m in Sources */ = {isa = PBXBuildFile; fileRef = 839366661815923C006DD712 /* CogPluginMulti.m */; };
8399CF2C27B5D1D5008751F1 /* NSDictionary+Merge.h in Headers */ = {isa = PBXBuildFile; fileRef = 8399CF2A27B5D1D4008751F1 /* NSDictionary+Merge.h */; };
8399CF2D27B5D1D5008751F1 /* NSDictionary+Merge.m in Sources */ = {isa = PBXBuildFile; fileRef = 8399CF2B27B5D1D4008751F1 /* NSDictionary+Merge.m */; };
839E56E52879450300DFB5F4 /* HrtfData.h in Headers */ = {isa = PBXBuildFile; fileRef = 839E56E12879450300DFB5F4 /* HrtfData.h */; };
839E56E62879450300DFB5F4 /* Endianness.h in Headers */ = {isa = PBXBuildFile; fileRef = 839E56E22879450300DFB5F4 /* Endianness.h */; };
839E56E72879450300DFB5F4 /* HrtfData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 839E56E32879450300DFB5F4 /* HrtfData.cpp */; };
839E56E82879450300DFB5F4 /* IHrtfData.h in Headers */ = {isa = PBXBuildFile; fileRef = 839E56E42879450300DFB5F4 /* IHrtfData.h */; };
839E56EA28794F6300DFB5F4 /* HrtfTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 839E56E928794F6300DFB5F4 /* HrtfTypes.h */; };
839E56F7287974A100DFB5F4 /* SandboxBroker.h in Headers */ = {isa = PBXBuildFile; fileRef = 839E56F6287974A100DFB5F4 /* SandboxBroker.h */; };
839E899E2D5DB9D500A13526 /* VisualizationNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 839E899D2D5DB9D500A13526 /* VisualizationNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
839E89A02D5DBA1700A13526 /* VisualizationNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 839E899F2D5DBA1700A13526 /* VisualizationNode.m */; };
83A3496A2D5C3F430096D530 /* DSPRubberbandNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 83A349682D5C3F430096D530 /* DSPRubberbandNode.m */; };
83A3496B2D5C3F430096D530 /* DSPRubberbandNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A349672D5C3F430096D530 /* DSPRubberbandNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
83A3496D2D5C40490096D530 /* DSPFSurroundNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A3496C2D5C40490096D530 /* DSPFSurroundNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
83A3496F2D5C405E0096D530 /* DSPFSurroundNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 83A3496E2D5C405E0096D530 /* DSPFSurroundNode.m */; };
83A349722D5C41810096D530 /* FSurroundFilter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83A349712D5C41810096D530 /* FSurroundFilter.mm */; };
83A349732D5C41810096D530 /* FSurroundFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A349702D5C41810096D530 /* FSurroundFilter.h */; settings = {ATTRIBUTES = (Public, ); }; };
83A349752D5C50A10096D530 /* DSPHRTFNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A349742D5C50A10096D530 /* DSPHRTFNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
83A349772D5C50B20096D530 /* DSPHRTFNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 83A349762D5C50B20096D530 /* DSPHRTFNode.m */; };
83B74281289E027F005AAC28 /* CogAudio-Bridging-Header.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B74280289E027F005AAC28 /* CogAudio-Bridging-Header.h */; };
83F843202D5C6272008C123B /* HeadphoneFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F8431E2D5C6272008C123B /* HeadphoneFilter.h */; settings = {ATTRIBUTES = (Public, ); }; };
83F843212D5C6272008C123B /* HeadphoneFilter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83F8431F2D5C6272008C123B /* HeadphoneFilter.mm */; };
83F843232D5C66DA008C123B /* DSPEqualizerNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F843222D5C66DA008C123B /* DSPEqualizerNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
83F843252D5C66E9008C123B /* DSPEqualizerNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 83F843242D5C66E9008C123B /* DSPEqualizerNode.m */; };
83F9FFF62D6EC43900026576 /* soxr.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F9FFF02D6EC43900026576 /* soxr.h */; settings = {ATTRIBUTES = (Public, ); }; };
83F9FFF82D6EC43900026576 /* libsoxr.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 83F9FFF22D6EC43900026576 /* libsoxr.0.dylib */; };
83FFED512D5B08BC0044CCAF /* DSPNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 83FFED502D5B08BC0044CCAF /* DSPNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
83FFED532D5B09320044CCAF /* DSPNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 83FFED522D5B09320044CCAF /* DSPNode.m */; };
8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */; };
8EC1225F0B993BD500C5B3AD /* Converter.h in Headers */ = {isa = PBXBuildFile; fileRef = 8EC1225D0B993BD500C5B3AD /* Converter.h */; };
8EC122600B993BD500C5B3AD /* Converter.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EC1225E0B993BD500C5B3AD /* Converter.m */; };
8E8D3D2F0CBAEE6E00135C1B /* AudioContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E8D3D2D0CBAEE6E00135C1B /* AudioContainer.h */; settings = {ATTRIBUTES = (Public, ); }; };
8E8D3D300CBAEE6E00135C1B /* AudioContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E8D3D2E0CBAEE6E00135C1B /* AudioContainer.m */; };
8EC1225F0B993BD500C5B3AD /* ConverterNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 8EC1225D0B993BD500C5B3AD /* ConverterNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
8EC122600B993BD500C5B3AD /* ConverterNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EC1225E0B993BD500C5B3AD /* ConverterNode.m */; };
B0575F2D0D687A0800411D77 /* Helper.h in Headers */ = {isa = PBXBuildFile; fileRef = B0575F2C0D687A0800411D77 /* Helper.h */; settings = {ATTRIBUTES = (Public, ); }; };
B0575F300D687A4000411D77 /* Helper.m in Sources */ = {isa = PBXBuildFile; fileRef = B0575F2F0D687A4000411D77 /* Helper.m */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
17D21D2B0B8BE6A200D1EBDE /* CopyFiles */ = {
83725A8D27AA0DDB0003F694 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
@ -61,6 +131,8 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
07DB5F3C0ED353A900C2E3EF /* AudioMetadataWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioMetadataWriter.h; sourceTree = "<group>"; };
07DB5F3D0ED353A900C2E3EF /* AudioMetadataWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AudioMetadataWriter.m; sourceTree = "<group>"; };
0867D69BFE84028FC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
0867D6A5FE840307C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
@ -80,15 +152,9 @@
17D21C7D0B8BE4BA00D1EBDE /* Node.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = Node.m; sourceTree = "<group>"; };
17D21C7E0B8BE4BA00D1EBDE /* OutputNode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = OutputNode.h; sourceTree = "<group>"; };
17D21C7F0B8BE4BA00D1EBDE /* OutputNode.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = OutputNode.m; sourceTree = "<group>"; };
17D21C9C0B8BE4BA00D1EBDE /* OutputCoreAudio.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = OutputCoreAudio.h; sourceTree = "<group>"; };
17D21C9D0B8BE4BA00D1EBDE /* OutputCoreAudio.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = OutputCoreAudio.m; sourceTree = "<group>"; };
17D21C9E0B8BE4BA00D1EBDE /* Status.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Status.h; sourceTree = "<group>"; };
17D21CDA0B8BE5B400D1EBDE /* VirtualRingBuffer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = VirtualRingBuffer.h; sourceTree = "<group>"; };
17D21CDB0B8BE5B400D1EBDE /* VirtualRingBuffer.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = VirtualRingBuffer.m; sourceTree = "<group>"; };
17D21CDD0B8BE5B400D1EBDE /* DBLog.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DBLog.h; sourceTree = "<group>"; };
17D21CDE0B8BE5B400D1EBDE /* DBLog.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = DBLog.m; sourceTree = "<group>"; };
17D21CF10B8BE5EF00D1EBDE /* Semaphore.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Semaphore.h; sourceTree = "<group>"; };
17D21CF20B8BE5EF00D1EBDE /* Semaphore.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = Semaphore.m; sourceTree = "<group>"; };
17D21CF10B8BE5EF00D1EBDE /* CogSemaphore.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CogSemaphore.h; sourceTree = "<group>"; };
17D21CF20B8BE5EF00D1EBDE /* CogSemaphore.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = CogSemaphore.m; sourceTree = "<group>"; };
17D21DA90B8BE76800D1EBDE /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = /System/Library/Frameworks/AudioToolbox.framework; sourceTree = "<absolute>"; };
17D21DAA0B8BE76800D1EBDE /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = /System/Library/Frameworks/AudioUnit.framework; sourceTree = "<absolute>"; };
17D21DAB0B8BE76800D1EBDE /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = /System/Library/Frameworks/CoreAudio.framework; sourceTree = "<absolute>"; };
@ -98,13 +164,90 @@
17D21EBB0B8BF44000D1EBDE /* AudioPlayer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = AudioPlayer.h; sourceTree = "<group>"; };
17D21EBC0B8BF44000D1EBDE /* AudioPlayer.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = AudioPlayer.m; sourceTree = "<group>"; };
17F94DD30B8D0F7000A34E87 /* PluginController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PluginController.h; sourceTree = "<group>"; };
17F94DD40B8D0F7000A34E87 /* PluginController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = PluginController.m; sourceTree = "<group>"; };
17F94DD40B8D0F7000A34E87 /* PluginController.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = PluginController.mm; sourceTree = "<group>"; };
17F94DDC0B8D101100A34E87 /* Plugin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Plugin.h; sourceTree = "<group>"; };
32DBCF5E0370ADEE00C91783 /* CogAudio_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CogAudio_Prefix.pch; sourceTree = "<group>"; };
831A50132865A7FD0049CFE4 /* rsstate.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = rsstate.hpp; sourceTree = "<group>"; };
831A50152865A8800049CFE4 /* rsstate.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = rsstate.cpp; sourceTree = "<group>"; };
831A50172865A8B30049CFE4 /* rsstate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = rsstate.h; sourceTree = "<group>"; };
8328995127CB510F00D7F028 /* RedundantPlaylistDataStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RedundantPlaylistDataStore.m; path = ../../Utils/RedundantPlaylistDataStore.m; sourceTree = "<group>"; };
8328995227CB511000D7F028 /* RedundantPlaylistDataStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RedundantPlaylistDataStore.h; path = ../../Utils/RedundantPlaylistDataStore.h; sourceTree = "<group>"; };
8328995527CB51B700D7F028 /* SHA256Digest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SHA256Digest.h; path = ../../Utils/SHA256Digest.h; sourceTree = "<group>"; };
8328995627CB51B700D7F028 /* SHA256Digest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SHA256Digest.m; path = ../../Utils/SHA256Digest.m; sourceTree = "<group>"; };
8328995927CB51C900D7F028 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
833442402D6EFA6700C51D38 /* VisualizationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VisualizationController.h; sourceTree = "<group>"; };
833442412D6EFA6700C51D38 /* VisualizationController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VisualizationController.m; sourceTree = "<group>"; };
833738E92D5EA52500278628 /* DSPDownmixNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DSPDownmixNode.h; sourceTree = "<group>"; };
833738EB2D5EA53500278628 /* DSPDownmixNode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DSPDownmixNode.m; sourceTree = "<group>"; };
833738ED2D5EA5B700278628 /* Downmix.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Downmix.h; sourceTree = "<group>"; };
833738EE2D5EA5B700278628 /* Downmix.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Downmix.m; sourceTree = "<group>"; };
8347C73F2796C58800FA8A7D /* NSFileHandle+CreateFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSFileHandle+CreateFile.h"; path = "../../Utils/NSFileHandle+CreateFile.h"; sourceTree = "<group>"; };
8347C7402796C58800FA8A7D /* NSFileHandle+CreateFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSFileHandle+CreateFile.m"; path = "../../Utils/NSFileHandle+CreateFile.m"; sourceTree = "<group>"; };
834A41A5287A90AB00EB9D9B /* freesurround_decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = freesurround_decoder.h; sourceTree = "<group>"; };
834A41A6287A90AB00EB9D9B /* freesurround_decoder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = freesurround_decoder.cpp; sourceTree = "<group>"; };
834A41A7287A90AB00EB9D9B /* channelmaps.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = channelmaps.cpp; sourceTree = "<group>"; };
834A41A8287A90AB00EB9D9B /* channelmaps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = channelmaps.h; sourceTree = "<group>"; };
834FD4EA27AF8F380063BC83 /* AudioChunk.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AudioChunk.h; sourceTree = "<group>"; };
834FD4EC27AF91220063BC83 /* AudioChunk.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AudioChunk.m; sourceTree = "<group>"; };
834FD4EE27AF93680063BC83 /* ChunkList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ChunkList.h; sourceTree = "<group>"; };
834FD4EF27AF93680063BC83 /* ChunkList.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ChunkList.m; sourceTree = "<group>"; };
8350416C28646149006B32CC /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
835C88AF279811A500E28EAE /* hdcd_decode2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hdcd_decode2.h; sourceTree = "<group>"; };
835C88B0279811A500E28EAE /* hdcd_decode2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hdcd_decode2.c; sourceTree = "<group>"; };
835DD2652ACAF1D90057E319 /* OutputCoreAudio.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OutputCoreAudio.m; sourceTree = "<group>"; };
835DD2662ACAF1D90057E319 /* OutputCoreAudio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OutputCoreAudio.h; sourceTree = "<group>"; };
835DD26B2ACAF5AD0057E319 /* LICENSE.LGPL */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE.LGPL; sourceTree = "<group>"; };
835DD26C2ACAF5AD0057E319 /* License.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = License.txt; sourceTree = "<group>"; };
835DD26D2ACAF5AD0057E319 /* lpc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lpc.h; sourceTree = "<group>"; };
835DD26E2ACAF5AD0057E319 /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = util.h; sourceTree = "<group>"; };
835DD26F2ACAF5AD0057E319 /* lpc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lpc.c; sourceTree = "<group>"; };
835FAC5C27BCA14D00BA8562 /* BadSampleCleaner.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BadSampleCleaner.h; path = Utils/BadSampleCleaner.h; sourceTree = SOURCE_ROOT; };
835FAC5D27BCA14D00BA8562 /* BadSampleCleaner.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = BadSampleCleaner.m; path = Utils/BadSampleCleaner.m; sourceTree = SOURCE_ROOT; };
83725A7B27AA0D8A0003F694 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; };
83725A7C27AA0D8E0003F694 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
8377C64B27B8C51500E8BC0F /* fft_accelerate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fft_accelerate.c; sourceTree = "<group>"; };
8377C64D27B8C54400E8BC0F /* fft.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fft.h; sourceTree = "<group>"; };
8384912618080FF100E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = "<group>"; };
838A33712D06A97D00D0D770 /* librubberband.3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = librubberband.3.dylib; path = ../ThirdParty/rubberband/lib/librubberband.3.dylib; sourceTree = SOURCE_ROOT; };
839065F22853338700636FBB /* dsd2float.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dsd2float.h; sourceTree = "<group>"; };
839366651815923C006DD712 /* CogPluginMulti.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CogPluginMulti.h; sourceTree = "<group>"; };
839366661815923C006DD712 /* CogPluginMulti.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CogPluginMulti.m; sourceTree = "<group>"; };
8399CF2A27B5D1D4008751F1 /* NSDictionary+Merge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSDictionary+Merge.h"; path = "../../Utils/NSDictionary+Merge.h"; sourceTree = "<group>"; };
8399CF2B27B5D1D4008751F1 /* NSDictionary+Merge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSDictionary+Merge.m"; path = "../../Utils/NSDictionary+Merge.m"; sourceTree = "<group>"; };
839E56E12879450300DFB5F4 /* HrtfData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HrtfData.h; sourceTree = "<group>"; };
839E56E22879450300DFB5F4 /* Endianness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Endianness.h; sourceTree = "<group>"; };
839E56E32879450300DFB5F4 /* HrtfData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HrtfData.cpp; sourceTree = "<group>"; };
839E56E42879450300DFB5F4 /* IHrtfData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IHrtfData.h; sourceTree = "<group>"; };
839E56E928794F6300DFB5F4 /* HrtfTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HrtfTypes.h; sourceTree = "<group>"; };
839E56F6287974A100DFB5F4 /* SandboxBroker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SandboxBroker.h; path = ../Utils/SandboxBroker.h; sourceTree = "<group>"; };
839E899D2D5DB9D500A13526 /* VisualizationNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VisualizationNode.h; sourceTree = "<group>"; };
839E899F2D5DBA1700A13526 /* VisualizationNode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VisualizationNode.m; sourceTree = "<group>"; };
83A349672D5C3F430096D530 /* DSPRubberbandNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DSPRubberbandNode.h; sourceTree = "<group>"; };
83A349682D5C3F430096D530 /* DSPRubberbandNode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DSPRubberbandNode.m; sourceTree = "<group>"; };
83A3496C2D5C40490096D530 /* DSPFSurroundNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DSPFSurroundNode.h; sourceTree = "<group>"; };
83A3496E2D5C405E0096D530 /* DSPFSurroundNode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DSPFSurroundNode.m; sourceTree = "<group>"; };
83A349702D5C41810096D530 /* FSurroundFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FSurroundFilter.h; sourceTree = "<group>"; };
83A349712D5C41810096D530 /* FSurroundFilter.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FSurroundFilter.mm; sourceTree = "<group>"; };
83A349742D5C50A10096D530 /* DSPHRTFNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DSPHRTFNode.h; sourceTree = "<group>"; };
83A349762D5C50B20096D530 /* DSPHRTFNode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DSPHRTFNode.m; sourceTree = "<group>"; };
83B74280289E027F005AAC28 /* CogAudio-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CogAudio-Bridging-Header.h"; sourceTree = "<group>"; };
83F8431E2D5C6272008C123B /* HeadphoneFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HeadphoneFilter.h; sourceTree = "<group>"; };
83F8431F2D5C6272008C123B /* HeadphoneFilter.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = HeadphoneFilter.mm; sourceTree = "<group>"; };
83F843222D5C66DA008C123B /* DSPEqualizerNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DSPEqualizerNode.h; sourceTree = "<group>"; };
83F843242D5C66E9008C123B /* DSPEqualizerNode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DSPEqualizerNode.m; sourceTree = "<group>"; };
83F9FFF02D6EC43900026576 /* soxr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = soxr.h; sourceTree = "<group>"; };
83F9FFF22D6EC43900026576 /* libsoxr.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libsoxr.0.dylib; sourceTree = "<group>"; };
83F9FFF42D6EC43900026576 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
83FFED502D5B08BC0044CCAF /* DSPNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DSPNode.h; sourceTree = "<group>"; };
83FFED522D5B09320044CCAF /* DSPNode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DSPNode.m; sourceTree = "<group>"; };
8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
8DC2EF5B0486A6940098B216 /* CogAudio.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CogAudio.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8EC1225D0B993BD500C5B3AD /* Converter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Converter.h; sourceTree = "<group>"; };
8EC1225E0B993BD500C5B3AD /* Converter.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = Converter.m; sourceTree = "<group>"; };
8E8D3D2D0CBAEE6E00135C1B /* AudioContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioContainer.h; sourceTree = "<group>"; };
8E8D3D2E0CBAEE6E00135C1B /* AudioContainer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AudioContainer.m; sourceTree = "<group>"; };
8EC1225D0B993BD500C5B3AD /* ConverterNode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ConverterNode.h; sourceTree = "<group>"; };
8EC1225E0B993BD500C5B3AD /* ConverterNode.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ConverterNode.m; sourceTree = "<group>"; };
B0575F2C0D687A0800411D77 /* Helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Helper.h; sourceTree = "<group>"; };
B0575F2F0D687A4000411D77 /* Helper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Helper.m; sourceTree = "<group>"; };
D2F7E79907B2D74100F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
/* End PBXFileReference section */
@ -113,11 +256,17 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
8328995A27CB51C900D7F028 /* Security.framework in Frameworks */,
83725A9127AA16D50003F694 /* AVFoundation.framework in Frameworks */,
83F9FFF82D6EC43900026576 /* libsoxr.0.dylib in Frameworks */,
8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */,
8350416D28646149006B32CC /* CoreMedia.framework in Frameworks */,
83725A9027AA16C90003F694 /* Accelerate.framework in Frameworks */,
17D21DAD0B8BE76800D1EBDE /* AudioToolbox.framework in Frameworks */,
17D21DAE0B8BE76800D1EBDE /* AudioUnit.framework in Frameworks */,
17D21DAF0B8BE76800D1EBDE /* CoreAudio.framework in Frameworks */,
17D21DB00B8BE76800D1EBDE /* CoreAudioKit.framework in Frameworks */,
838A33722D06A97D00D0D770 /* librubberband.3.dylib in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -140,6 +289,7 @@
089C1665FE841158C02AAC07 /* Resources */,
0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */,
034768DFFF38A50411DB9C8B /* Products */,
83725A8F27AA16C90003F694 /* Frameworks */,
);
name = CogAudio;
sourceTree = "<group>";
@ -164,22 +314,33 @@
08FB77AEFE84172EC02AAC07 /* Classes */ = {
isa = PBXGroup;
children = (
83B74280289E027F005AAC28 /* CogAudio-Bridging-Header.h */,
8377C64F27B8CAAB00E8BC0F /* Visualization */,
17F94DDC0B8D101100A34E87 /* Plugin.h */,
17D21EBB0B8BF44000D1EBDE /* AudioPlayer.h */,
17D21EBC0B8BF44000D1EBDE /* AudioPlayer.m */,
8E8D3D2D0CBAEE6E00135C1B /* AudioContainer.h */,
8E8D3D2E0CBAEE6E00135C1B /* AudioContainer.m */,
17A2D3C30B8D1D37000778C4 /* AudioDecoder.h */,
17A2D3C40B8D1D37000778C4 /* AudioDecoder.m */,
17C940210B900909008627D6 /* AudioMetadataReader.h */,
17C940220B900909008627D6 /* AudioMetadataReader.m */,
07DB5F3C0ED353A900C2E3EF /* AudioMetadataWriter.h */,
07DB5F3D0ED353A900C2E3EF /* AudioMetadataWriter.m */,
17B6192E0B909BC300BC003F /* AudioPropertiesReader.h */,
17B6192F0B909BC300BC003F /* AudioPropertiesReader.m */,
17ADB13A0B97926D00257CA2 /* AudioSource.h */,
17ADB13B0B97926D00257CA2 /* AudioSource.m */,
839366651815923C006DD712 /* CogPluginMulti.h */,
839366661815923C006DD712 /* CogPluginMulti.m */,
17F94DD30B8D0F7000A34E87 /* PluginController.h */,
17F94DD40B8D0F7000A34E87 /* PluginController.m */,
17F94DD40B8D0F7000A34E87 /* PluginController.mm */,
17D21C750B8BE4BA00D1EBDE /* Chain */,
17D21C9B0B8BE4BA00D1EBDE /* Output */,
839E56F6287974A100DFB5F4 /* SandboxBroker.h */,
17D21C9E0B8BE4BA00D1EBDE /* Status.h */,
B0575F2C0D687A0800411D77 /* Helper.h */,
B0575F2F0D687A4000411D77 /* Helper.m */,
17D21CD80B8BE5B400D1EBDE /* ThirdParty */,
17D21CDC0B8BE5B400D1EBDE /* Utils */,
);
@ -197,8 +358,11 @@
1058C7B2FEA5585E11CA2CBB /* Other Frameworks */ = {
isa = PBXGroup;
children = (
17D21DA90B8BE76800D1EBDE /* AudioToolbox.framework */,
838A33712D06A97D00D0D770 /* librubberband.3.dylib */,
83725A7B27AA0D8A0003F694 /* Accelerate.framework */,
17D21DAA0B8BE76800D1EBDE /* AudioUnit.framework */,
17D21DA90B8BE76800D1EBDE /* AudioToolbox.framework */,
83725A7C27AA0D8E0003F694 /* AVFoundation.framework */,
17D21DAB0B8BE76800D1EBDE /* CoreAudio.framework */,
17D21DAC0B8BE76800D1EBDE /* CoreAudioKit.framework */,
0867D6A5FE840307C02AAC07 /* AppKit.framework */,
@ -211,16 +375,25 @@
17D21C750B8BE4BA00D1EBDE /* Chain */ = {
isa = PBXGroup;
children = (
83A349692D5C3F430096D530 /* DSP */,
834FD4EA27AF8F380063BC83 /* AudioChunk.h */,
834FD4EC27AF91220063BC83 /* AudioChunk.m */,
17D21C760B8BE4BA00D1EBDE /* BufferChain.h */,
17D21C770B8BE4BA00D1EBDE /* BufferChain.m */,
8EC1225D0B993BD500C5B3AD /* Converter.h */,
8EC1225E0B993BD500C5B3AD /* Converter.m */,
834FD4EE27AF93680063BC83 /* ChunkList.h */,
834FD4EF27AF93680063BC83 /* ChunkList.m */,
8EC1225D0B993BD500C5B3AD /* ConverterNode.h */,
8EC1225E0B993BD500C5B3AD /* ConverterNode.m */,
17D21C7A0B8BE4BA00D1EBDE /* InputNode.h */,
17D21C7B0B8BE4BA00D1EBDE /* InputNode.m */,
17D21C7C0B8BE4BA00D1EBDE /* Node.h */,
17D21C7D0B8BE4BA00D1EBDE /* Node.m */,
17D21C7E0B8BE4BA00D1EBDE /* OutputNode.h */,
17D21C7F0B8BE4BA00D1EBDE /* OutputNode.m */,
83FFED502D5B08BC0044CCAF /* DSPNode.h */,
83FFED522D5B09320044CCAF /* DSPNode.m */,
839E899D2D5DB9D500A13526 /* VisualizationNode.h */,
839E899F2D5DBA1700A13526 /* VisualizationNode.m */,
);
path = Chain;
sourceTree = "<group>";
@ -228,8 +401,8 @@
17D21C9B0B8BE4BA00D1EBDE /* Output */ = {
isa = PBXGroup;
children = (
17D21C9C0B8BE4BA00D1EBDE /* OutputCoreAudio.h */,
17D21C9D0B8BE4BA00D1EBDE /* OutputCoreAudio.m */,
835DD2662ACAF1D90057E319 /* OutputCoreAudio.h */,
835DD2652ACAF1D90057E319 /* OutputCoreAudio.m */,
);
path = Output;
sourceTree = "<group>";
@ -237,28 +410,37 @@
17D21CD80B8BE5B400D1EBDE /* ThirdParty */ = {
isa = PBXGroup;
children = (
83F9FFF52D6EC43900026576 /* soxr */,
835DD2692ACAF5AD0057E319 /* lvqcl */,
834A41A4287A90AB00EB9D9B /* fsurround */,
839E56E02879450300DFB5F4 /* hrtf */,
831A50152865A8800049CFE4 /* rsstate.cpp */,
831A50172865A8B30049CFE4 /* rsstate.h */,
831A50132865A7FD0049CFE4 /* rsstate.hpp */,
8377C64A27B8C51500E8BC0F /* deadbeef */,
835C88AE279811A500E28EAE /* hdcd */,
17D21DC40B8BE79700D1EBDE /* CoreAudioUtils */,
17D21CD90B8BE5B400D1EBDE /* VirtualRingBuffer */,
);
path = ThirdParty;
sourceTree = "<group>";
};
17D21CD90B8BE5B400D1EBDE /* VirtualRingBuffer */ = {
isa = PBXGroup;
children = (
17D21CDA0B8BE5B400D1EBDE /* VirtualRingBuffer.h */,
17D21CDB0B8BE5B400D1EBDE /* VirtualRingBuffer.m */,
);
path = VirtualRingBuffer;
sourceTree = "<group>";
};
17D21CDC0B8BE5B400D1EBDE /* Utils */ = {
isa = PBXGroup;
children = (
17D21CDD0B8BE5B400D1EBDE /* DBLog.h */,
17D21CDE0B8BE5B400D1EBDE /* DBLog.m */,
17D21CF10B8BE5EF00D1EBDE /* Semaphore.h */,
17D21CF20B8BE5EF00D1EBDE /* Semaphore.m */,
839065F22853338700636FBB /* dsd2float.h */,
8328995527CB51B700D7F028 /* SHA256Digest.h */,
8328995627CB51B700D7F028 /* SHA256Digest.m */,
8328995227CB511000D7F028 /* RedundantPlaylistDataStore.h */,
8328995127CB510F00D7F028 /* RedundantPlaylistDataStore.m */,
835FAC5C27BCA14D00BA8562 /* BadSampleCleaner.h */,
835FAC5D27BCA14D00BA8562 /* BadSampleCleaner.m */,
8399CF2A27B5D1D4008751F1 /* NSDictionary+Merge.h */,
8399CF2B27B5D1D4008751F1 /* NSDictionary+Merge.m */,
8347C73F2796C58800FA8A7D /* NSFileHandle+CreateFile.h */,
8347C7402796C58800FA8A7D /* NSFileHandle+CreateFile.m */,
8384912618080FF100E7332D /* Logging.h */,
17D21CF10B8BE5EF00D1EBDE /* CogSemaphore.h */,
17D21CF20B8BE5EF00D1EBDE /* CogSemaphore.m */,
);
path = Utils;
sourceTree = "<group>";
@ -280,6 +462,135 @@
name = "Other Sources";
sourceTree = "<group>";
};
834A41A4287A90AB00EB9D9B /* fsurround */ = {
isa = PBXGroup;
children = (
834A41A5287A90AB00EB9D9B /* freesurround_decoder.h */,
834A41A6287A90AB00EB9D9B /* freesurround_decoder.cpp */,
834A41A7287A90AB00EB9D9B /* channelmaps.cpp */,
834A41A8287A90AB00EB9D9B /* channelmaps.h */,
);
path = fsurround;
sourceTree = "<group>";
};
835C88AE279811A500E28EAE /* hdcd */ = {
isa = PBXGroup;
children = (
835C88AF279811A500E28EAE /* hdcd_decode2.h */,
835C88B0279811A500E28EAE /* hdcd_decode2.c */,
);
path = hdcd;
sourceTree = "<group>";
};
835DD2692ACAF5AD0057E319 /* lvqcl */ = {
isa = PBXGroup;
children = (
835DD26A2ACAF5AD0057E319 /* License */,
835DD26D2ACAF5AD0057E319 /* lpc.h */,
835DD26E2ACAF5AD0057E319 /* util.h */,
835DD26F2ACAF5AD0057E319 /* lpc.c */,
);
path = lvqcl;
sourceTree = "<group>";
};
835DD26A2ACAF5AD0057E319 /* License */ = {
isa = PBXGroup;
children = (
835DD26B2ACAF5AD0057E319 /* LICENSE.LGPL */,
835DD26C2ACAF5AD0057E319 /* License.txt */,
);
path = License;
sourceTree = "<group>";
};
83725A8F27AA16C90003F694 /* Frameworks */ = {
isa = PBXGroup;
children = (
8350416C28646149006B32CC /* CoreMedia.framework */,
8328995927CB51C900D7F028 /* Security.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
8377C64A27B8C51500E8BC0F /* deadbeef */ = {
isa = PBXGroup;
children = (
8377C64D27B8C54400E8BC0F /* fft.h */,
8377C64B27B8C51500E8BC0F /* fft_accelerate.c */,
);
path = deadbeef;
sourceTree = "<group>";
};
8377C64F27B8CAAB00E8BC0F /* Visualization */ = {
isa = PBXGroup;
children = (
833442402D6EFA6700C51D38 /* VisualizationController.h */,
833442412D6EFA6700C51D38 /* VisualizationController.m */,
);
path = Visualization;
sourceTree = "<group>";
};
839E56E02879450300DFB5F4 /* hrtf */ = {
isa = PBXGroup;
children = (
839E56E22879450300DFB5F4 /* Endianness.h */,
839E56E32879450300DFB5F4 /* HrtfData.cpp */,
839E56E12879450300DFB5F4 /* HrtfData.h */,
839E56E928794F6300DFB5F4 /* HrtfTypes.h */,
839E56E42879450300DFB5F4 /* IHrtfData.h */,
);
path = hrtf;
sourceTree = "<group>";
};
83A349692D5C3F430096D530 /* DSP */ = {
isa = PBXGroup;
children = (
833738ED2D5EA5B700278628 /* Downmix.h */,
833738EE2D5EA5B700278628 /* Downmix.m */,
83F8431E2D5C6272008C123B /* HeadphoneFilter.h */,
83F8431F2D5C6272008C123B /* HeadphoneFilter.mm */,
83A349702D5C41810096D530 /* FSurroundFilter.h */,
83A349712D5C41810096D530 /* FSurroundFilter.mm */,
83A349672D5C3F430096D530 /* DSPRubberbandNode.h */,
83A349682D5C3F430096D530 /* DSPRubberbandNode.m */,
83A3496C2D5C40490096D530 /* DSPFSurroundNode.h */,
83A3496E2D5C405E0096D530 /* DSPFSurroundNode.m */,
83A349742D5C50A10096D530 /* DSPHRTFNode.h */,
83A349762D5C50B20096D530 /* DSPHRTFNode.m */,
83F843222D5C66DA008C123B /* DSPEqualizerNode.h */,
83F843242D5C66E9008C123B /* DSPEqualizerNode.m */,
833738E92D5EA52500278628 /* DSPDownmixNode.h */,
833738EB2D5EA53500278628 /* DSPDownmixNode.m */,
);
path = DSP;
sourceTree = "<group>";
};
83F9FFF12D6EC43900026576 /* include */ = {
isa = PBXGroup;
children = (
83F9FFF02D6EC43900026576 /* soxr.h */,
);
path = include;
sourceTree = "<group>";
};
83F9FFF32D6EC43900026576 /* lib */ = {
isa = PBXGroup;
children = (
83F9FFF22D6EC43900026576 /* libsoxr.0.dylib */,
);
path = lib;
sourceTree = "<group>";
};
83F9FFF52D6EC43900026576 /* soxr */ = {
isa = PBXGroup;
children = (
83F9FFF12D6EC43900026576 /* include */,
83F9FFF32D6EC43900026576 /* lib */,
83F9FFF42D6EC43900026576 /* README.md */,
);
name = soxr;
path = ../ThirdParty/soxr;
sourceTree = SOURCE_ROOT;
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
@ -287,45 +598,82 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
833442422D6EFA6700C51D38 /* VisualizationController.h in Headers */,
833738F02D5EA5B700278628 /* Downmix.h in Headers */,
834FD4EB27AF8F380063BC83 /* AudioChunk.h in Headers */,
83F843202D5C6272008C123B /* HeadphoneFilter.h in Headers */,
83A349732D5C41810096D530 /* FSurroundFilter.h in Headers */,
839E56E82879450300DFB5F4 /* IHrtfData.h in Headers */,
17D21CA10B8BE4BA00D1EBDE /* BufferChain.h in Headers */,
831A50142865A7FD0049CFE4 /* rsstate.hpp in Headers */,
835DD2682ACAF1D90057E319 /* OutputCoreAudio.h in Headers */,
834A41AC287A90AB00EB9D9B /* channelmaps.h in Headers */,
83A3496D2D5C40490096D530 /* DSPFSurroundNode.h in Headers */,
83A3496B2D5C3F430096D530 /* DSPRubberbandNode.h in Headers */,
17D21CA50B8BE4BA00D1EBDE /* InputNode.h in Headers */,
833738EA2D5EA52500278628 /* DSPDownmixNode.h in Headers */,
83F843232D5C66DA008C123B /* DSPEqualizerNode.h in Headers */,
834A41A9287A90AB00EB9D9B /* freesurround_decoder.h in Headers */,
834FD4F027AF93680063BC83 /* ChunkList.h in Headers */,
835DD2732ACAF5AD0057E319 /* util.h in Headers */,
17D21CA70B8BE4BA00D1EBDE /* Node.h in Headers */,
8399CF2C27B5D1D5008751F1 /* NSDictionary+Merge.h in Headers */,
17D21CA90B8BE4BA00D1EBDE /* OutputNode.h in Headers */,
17D21CC50B8BE4BA00D1EBDE /* OutputCoreAudio.h in Headers */,
8EC1225F0B993BD500C5B3AD /* ConverterNode.h in Headers */,
8328995427CB511000D7F028 /* RedundantPlaylistDataStore.h in Headers */,
839E56E52879450300DFB5F4 /* HrtfData.h in Headers */,
83FFED512D5B08BC0044CCAF /* DSPNode.h in Headers */,
839E899E2D5DB9D500A13526 /* VisualizationNode.h in Headers */,
83A349752D5C50A10096D530 /* DSPHRTFNode.h in Headers */,
83F9FFF62D6EC43900026576 /* soxr.h in Headers */,
17D21CC70B8BE4BA00D1EBDE /* Status.h in Headers */,
17D21CDF0B8BE5B400D1EBDE /* VirtualRingBuffer.h in Headers */,
17D21CE10B8BE5B400D1EBDE /* DBLog.h in Headers */,
17D21CF30B8BE5EF00D1EBDE /* Semaphore.h in Headers */,
17D21CF30B8BE5EF00D1EBDE /* CogSemaphore.h in Headers */,
839E56E62879450300DFB5F4 /* Endianness.h in Headers */,
17D21DC70B8BE79700D1EBDE /* CoreAudioUtils.h in Headers */,
835DD2722ACAF5AD0057E319 /* lpc.h in Headers */,
17D21EBD0B8BF44000D1EBDE /* AudioPlayer.h in Headers */,
831A50182865A8B30049CFE4 /* rsstate.h in Headers */,
17F94DD50B8D0F7000A34E87 /* PluginController.h in Headers */,
17F94DDD0B8D101100A34E87 /* Plugin.h in Headers */,
8328995727CB51B700D7F028 /* SHA256Digest.h in Headers */,
17A2D3C50B8D1D37000778C4 /* AudioDecoder.h in Headers */,
8347C7412796C58800FA8A7D /* NSFileHandle+CreateFile.h in Headers */,
83B74281289E027F005AAC28 /* CogAudio-Bridging-Header.h in Headers */,
17C940230B900909008627D6 /* AudioMetadataReader.h in Headers */,
839E56F7287974A100DFB5F4 /* SandboxBroker.h in Headers */,
839065F32853338700636FBB /* dsd2float.h in Headers */,
17B619300B909BC300BC003F /* AudioPropertiesReader.h in Headers */,
839366671815923C006DD712 /* CogPluginMulti.h in Headers */,
17ADB13C0B97926D00257CA2 /* AudioSource.h in Headers */,
8EC1225F0B993BD500C5B3AD /* Converter.h in Headers */,
835C88B1279811A500E28EAE /* hdcd_decode2.h in Headers */,
8384912718080FF100E7332D /* Logging.h in Headers */,
8377C64E27B8C54400E8BC0F /* fft.h in Headers */,
835FAC5E27BCA14D00BA8562 /* BadSampleCleaner.h in Headers */,
8E8D3D2F0CBAEE6E00135C1B /* AudioContainer.h in Headers */,
B0575F2D0D687A0800411D77 /* Helper.h in Headers */,
07DB5F3E0ED353A900C2E3EF /* AudioMetadataWriter.h in Headers */,
839E56EA28794F6300DFB5F4 /* HrtfTypes.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
8DC2EF4F0486A6940098B216 /* CogAudio Framework */ = {
8DC2EF4F0486A6940098B216 /* CogAudio */ = {
isa = PBXNativeTarget;
buildConfigurationList = 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "CogAudio Framework" */;
buildConfigurationList = 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "CogAudio" */;
buildPhases = (
17D21D2B0B8BE6A200D1EBDE /* CopyFiles */,
8DC2EF500486A6940098B216 /* Headers */,
8DC2EF540486A6940098B216 /* Sources */,
8DC2EF560486A6940098B216 /* Frameworks */,
8DC2EF520486A6940098B216 /* Resources */,
83725A8D27AA0DDB0003F694 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = "CogAudio Framework";
name = CogAudio;
productInstallPath = "$(HOME)/Library/Frameworks";
productName = CogAudio;
productReference = 8DC2EF5B0486A6940098B216 /* CogAudio.framework */;
@ -336,13 +684,30 @@
/* Begin PBXProject section */
0867D690FE84028FC02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1620;
TargetAttributes = {
8DC2EF4F0486A6940098B216 = {
LastSwiftMigration = 1330;
ProvisioningStyle = Manual;
};
};
};
buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "CogAudio" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
hasScannedForEncodings = 1;
knownRegions = (
en,
Base,
);
mainGroup = 0867D691FE84028FC02AAC07 /* CogAudio */;
productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
8DC2EF4F0486A6940098B216 /* CogAudio Framework */,
8DC2EF4F0486A6940098B216 /* CogAudio */,
);
};
/* End PBXProject section */
@ -363,21 +728,48 @@
buildActionMask = 2147483647;
files = (
17D21CA20B8BE4BA00D1EBDE /* BufferChain.m in Sources */,
83A349772D5C50B20096D530 /* DSPHRTFNode.m in Sources */,
17D21CA60B8BE4BA00D1EBDE /* InputNode.m in Sources */,
83A3496A2D5C3F430096D530 /* DSPRubberbandNode.m in Sources */,
8399CF2D27B5D1D5008751F1 /* NSDictionary+Merge.m in Sources */,
83F843252D5C66E9008C123B /* DSPEqualizerNode.m in Sources */,
834A41AB287A90AB00EB9D9B /* channelmaps.cpp in Sources */,
833738EC2D5EA53500278628 /* DSPDownmixNode.m in Sources */,
833442432D6EFA6700C51D38 /* VisualizationController.m in Sources */,
831A50162865A8800049CFE4 /* rsstate.cpp in Sources */,
17D21CA80B8BE4BA00D1EBDE /* Node.m in Sources */,
17D21CAA0B8BE4BA00D1EBDE /* OutputNode.m in Sources */,
17D21CC60B8BE4BA00D1EBDE /* OutputCoreAudio.m in Sources */,
17D21CE00B8BE5B400D1EBDE /* VirtualRingBuffer.m in Sources */,
17D21CE20B8BE5B400D1EBDE /* DBLog.m in Sources */,
17D21CF40B8BE5EF00D1EBDE /* Semaphore.m in Sources */,
835C88B2279811A500E28EAE /* hdcd_decode2.c in Sources */,
835FAC5F27BCA14D00BA8562 /* BadSampleCleaner.m in Sources */,
834FD4ED27AF91220063BC83 /* AudioChunk.m in Sources */,
833738EF2D5EA5B700278628 /* Downmix.m in Sources */,
17D21CF40B8BE5EF00D1EBDE /* CogSemaphore.m in Sources */,
839E89A02D5DBA1700A13526 /* VisualizationNode.m in Sources */,
8347C7422796C58800FA8A7D /* NSFileHandle+CreateFile.m in Sources */,
83A3496F2D5C405E0096D530 /* DSPFSurroundNode.m in Sources */,
17D21DC80B8BE79700D1EBDE /* CoreAudioUtils.m in Sources */,
8328995327CB511000D7F028 /* RedundantPlaylistDataStore.m in Sources */,
8377C64C27B8C51500E8BC0F /* fft_accelerate.c in Sources */,
839366681815923C006DD712 /* CogPluginMulti.m in Sources */,
17D21EBE0B8BF44000D1EBDE /* AudioPlayer.m in Sources */,
17F94DD60B8D0F7000A34E87 /* PluginController.m in Sources */,
17F94DD60B8D0F7000A34E87 /* PluginController.mm in Sources */,
839E56E72879450300DFB5F4 /* HrtfData.cpp in Sources */,
17A2D3C60B8D1D37000778C4 /* AudioDecoder.m in Sources */,
8328995827CB51B700D7F028 /* SHA256Digest.m in Sources */,
17C940240B900909008627D6 /* AudioMetadataReader.m in Sources */,
17B619310B909BC300BC003F /* AudioPropertiesReader.m in Sources */,
83F843212D5C6272008C123B /* HeadphoneFilter.mm in Sources */,
17ADB13D0B97926D00257CA2 /* AudioSource.m in Sources */,
8EC122600B993BD500C5B3AD /* Converter.m in Sources */,
834FD4F127AF93680063BC83 /* ChunkList.m in Sources */,
83FFED532D5B09320044CCAF /* DSPNode.m in Sources */,
8EC122600B993BD500C5B3AD /* ConverterNode.m in Sources */,
835DD2672ACAF1D90057E319 /* OutputCoreAudio.m in Sources */,
83A349722D5C41810096D530 /* FSurroundFilter.mm in Sources */,
8E8D3D300CBAEE6E00135C1B /* AudioContainer.m in Sources */,
B0575F300D687A4000411D77 /* Helper.m in Sources */,
835DD2742ACAF5AD0057E319 /* lpc.c in Sources */,
834A41AA287A90AB00EB9D9B /* freesurround_decoder.cpp in Sources */,
07DB5F3F0ED353A900C2E3EF /* AudioMetadataWriter.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -387,46 +779,76 @@
1DEB91AE08733DA50010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_ENABLE_MODULES = YES;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
FRAMEWORK_SEARCH_PATHS = "";
ENABLE_MODULE_VERIFIER = YES;
FRAMEWORK_VERSION = A;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_MODEL_TUNING = G5;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = CogAudio_Prefix.pch;
GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
HEADER_SEARCH_PATHS = (
../ThirdParty/soxr/include,
../ThirdParty/rubberband/include,
);
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "@executable_path/../Frameworks";
LD_RUNPATH_SEARCH_PATHS = "@loader_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
../ThirdParty/soxr/lib,
../ThirdParty/rubberband/lib,
);
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 c++17";
OTHER_LDFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = org.cogx.cogaudio;
PRODUCT_NAME = CogAudio;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
WARNING_LDFLAGS = "";
WRAPPER_EXTENSION = framework;
ZERO_LINK = YES;
};
name = Debug;
};
1DEB91AF08733DA50010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = (
ppc,
i386,
);
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_ENABLE_MODULES = YES;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
FRAMEWORK_SEARCH_PATHS = "";
ENABLE_MODULE_VERIFIER = YES;
FRAMEWORK_VERSION = A;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_MODEL_TUNING = G5;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = CogAudio_Prefix.pch;
GCC_PREPROCESSOR_DEFINITIONS = "";
HEADER_SEARCH_PATHS = (
../ThirdParty/soxr/include,
../ThirdParty/rubberband/include,
);
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "@executable_path/../Frameworks";
LD_RUNPATH_SEARCH_PATHS = "@loader_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
../ThirdParty/soxr/lib,
../ThirdParty/rubberband/lib,
);
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 c++17";
OTHER_LDFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = org.cogx.cogaudio;
PRODUCT_NAME = CogAudio;
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
WARNING_LDFLAGS = "";
WRAPPER_EXTENSION = framework;
};
@ -435,10 +857,52 @@
1DEB91B208733DA50010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEFINES_MODULE = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"HAVE_CONFIG_H=1",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PREBINDING = NO;
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
MACOSX_DEPLOYMENT_TARGET = 10.13;
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = "-Wframe-larger-than=4000";
OTHER_CPLUSPLUSFLAGS = "-Wframe-larger-than=16000";
PRODUCT_MODULE_NAME = CogAudio;
SDKROOT = macosx;
SWIFT_OBJC_BRIDGING_HEADER = "CogAudio-Bridging-Header.h";
SYMROOT = ../build;
};
name = Debug;
@ -446,14 +910,48 @@
1DEB91B308733DA50010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = (
ppc,
i386,
);
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = "HAVE_CONFIG_H=1";
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PREBINDING = NO;
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
MACOSX_DEPLOYMENT_TARGET = 10.13;
OTHER_CFLAGS = "-Wframe-larger-than=4000";
OTHER_CPLUSPLUSFLAGS = "-Wframe-larger-than=16000";
PRODUCT_MODULE_NAME = CogAudio;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OBJC_BRIDGING_HEADER = "CogAudio-Bridging-Header.h";
SYMROOT = ../build;
};
name = Release;
@ -461,7 +959,7 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "CogAudio Framework" */ = {
1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "CogAudio" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB91AE08733DA50010E9CD /* Debug */,

View file

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1620"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8DC2EF4F0486A6940098B216"
BuildableName = "CogAudio.framework"
BlueprintName = "CogAudio"
ReferencedContainer = "container:CogAudio.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8DC2EF4F0486A6940098B216"
BuildableName = "CogAudio.framework"
BlueprintName = "CogAudio"
ReferencedContainer = "container:CogAudio.xcodeproj">
</BuildableReference>
</MacroExpansion>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8DC2EF4F0486A6940098B216"
BuildableName = "CogAudio.framework"
BlueprintName = "CogAudio"
ReferencedContainer = "container:CogAudio.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View file

@ -3,5 +3,6 @@
//
#ifdef __OBJC__
#import <AssertMacros.h>
#import <Cocoa/Cocoa.h>
#endif

42
Audio/CogPluginMulti.h Normal file
View file

@ -0,0 +1,42 @@
//
// CogPluginMulti.h
// CogAudio
//
// Created by Christopher Snowhill on 10/21/13.
//
//
#import "Plugin.h"
#import <Cocoa/Cocoa.h>
@interface CogDecoderMulti : NSObject <CogDecoder> {
NSArray *theDecoders;
id<CogDecoder> theDecoder;
BOOL observersAdded;
}
- (id)initWithDecoders:(NSArray *)decoders;
@end
@interface CogContainerMulti : NSObject {
}
+ (NSArray *)urlsForContainerURL:(NSURL *)url containers:(NSArray *)containers;
+ (NSArray *)dependencyUrlsForContainerURL:(NSURL *)url containers:(NSArray *)containers;
@end
@interface CogMetadataReaderMulti : NSObject {
}
+ (NSDictionary *)metadataForURL:(NSURL *)url readers:(NSArray *)readers;
@end
@interface CogPropertiesReaderMulti : NSObject {
}
+ (NSDictionary *)propertiesForSource:(id<CogSource>)source readers:(NSArray *)readers;
@end

219
Audio/CogPluginMulti.m Normal file
View file

@ -0,0 +1,219 @@
//
// CogPluginMulti.m
// CogAudio
//
// Created by Christopher Snowhill on 10/21/13.
//
//
#import "CogPluginMulti.h"
NSArray *sortClassesByPriority(NSArray *theClasses) {
NSMutableArray *sortedClasses = [NSMutableArray arrayWithArray:theClasses];
[sortedClasses sortUsingComparator:
^NSComparisonResult(id obj1, id obj2) {
NSString *classString1 = (NSString *)obj1;
NSString *classString2 = (NSString *)obj2;
Class class1 = NSClassFromString(classString1);
Class class2 = NSClassFromString(classString2);
float priority1 = [class1 priority];
float priority2 = [class2 priority];
if(priority1 == priority2)
return NSOrderedSame;
else if(priority1 > priority2)
return NSOrderedAscending;
else
return NSOrderedDescending;
}];
return sortedClasses;
}
@interface CogDecoderMulti (Private)
- (void)registerObservers;
- (void)removeObservers;
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context;
@end
@implementation CogDecoderMulti
static void *kCogDecoderMultiContext = &kCogDecoderMultiContext;
+ (NSArray *)mimeTypes {
return nil;
}
+ (NSArray *)fileTypes {
return nil;
}
+ (float)priority {
return -1.0;
}
+ (NSArray *)fileTypeAssociations {
return nil;
}
- (id)initWithDecoders:(NSArray *)decoders {
self = [super init];
if(self) {
theDecoders = sortClassesByPriority(decoders);
theDecoder = nil;
}
return self;
}
- (NSDictionary *)properties {
if(theDecoder != nil) return [theDecoder properties];
return nil;
}
- (NSDictionary *)metadata {
if(theDecoder != nil) return [theDecoder metadata];
return @{};
}
- (AudioChunk *)readAudio {
if(theDecoder != nil) return [theDecoder readAudio];
return nil;
}
- (BOOL)open:(id<CogSource>)source {
for(NSString *classString in theDecoders) {
Class decoder = NSClassFromString(classString);
theDecoder = [[decoder alloc] init];
[self registerObservers];
if([theDecoder open:source])
return YES;
[self removeObservers];
// HTTP reader supports limited rewinding
[source seek:0 whence:SEEK_SET];
}
theDecoder = nil;
return NO;
}
- (long)seek:(long)frame {
if(theDecoder != nil) return [theDecoder seek:frame];
return -1;
}
- (void)close {
if(theDecoder != nil) {
[self removeObservers];
[theDecoder close];
theDecoder = nil;
}
}
- (void)dealloc {
[self close];
}
- (void)registerObservers {
if(!observersAdded) {
[theDecoder addObserver:self
forKeyPath:@"properties"
options:(NSKeyValueObservingOptionNew)
context:kCogDecoderMultiContext];
[theDecoder addObserver:self
forKeyPath:@"metadata"
options:(NSKeyValueObservingOptionNew)
context:kCogDecoderMultiContext];
observersAdded = YES;
}
}
- (void)removeObservers {
if(observersAdded) {
observersAdded = NO;
[theDecoder removeObserver:self forKeyPath:@"properties" context:kCogDecoderMultiContext];
[theDecoder removeObserver:self forKeyPath:@"metadata" context:kCogDecoderMultiContext];
}
}
- (BOOL)setTrack:(NSURL *)track {
if(theDecoder != nil && [theDecoder respondsToSelector:@selector(setTrack:)]) return [theDecoder setTrack:track];
return NO;
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if(context == kCogDecoderMultiContext) {
[self willChangeValueForKey:keyPath];
[self didChangeValueForKey:keyPath];
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
@end
@implementation CogContainerMulti
+ (NSArray *)urlsForContainerURL:(NSURL *)url containers:(NSArray *)containers {
NSArray *sortedContainers = sortClassesByPriority(containers);
for(NSString *classString in sortedContainers) {
Class container = NSClassFromString(classString);
NSArray *urls = [container urlsForContainerURL:url];
if([urls count])
return urls;
}
return nil;
}
+ (NSArray *)dependencyUrlsForContainerURL:(NSURL *)url containers:(NSArray *)containers {
NSArray *sortedContainers = sortClassesByPriority(containers);
for(NSString *classString in sortedContainers) {
Class container = NSClassFromString(classString);
if([container respondsToSelector:@selector(dependencyUrlsForContainerURL:)]) {
NSArray *urls = [container dependencyUrlsForContainerURL:url];
if([urls count])
return urls;
}
}
return nil;
}
@end
@implementation CogMetadataReaderMulti
+ (NSDictionary *)metadataForURL:(NSURL *)url readers:(NSArray *)readers {
NSArray *sortedReaders = sortClassesByPriority(readers);
for(NSString *classString in sortedReaders) {
Class reader = NSClassFromString(classString);
NSDictionary *data = [reader metadataForURL:url];
if([data count])
return data;
}
return nil;
}
@end
@implementation CogPropertiesReaderMulti
+ (NSDictionary *)propertiesForSource:(id<CogSource>)source readers:(NSArray *)readers {
NSArray *sortedReaders = sortClassesByPriority(readers);
for(NSString *classString in sortedReaders) {
Class reader = NSClassFromString(classString);
NSDictionary *data = [reader propertiesForSource:source];
if([data count])
return data;
if([source seekable])
[source seek:0 whence:SEEK_SET];
}
return nil;
}
@end

11
Audio/Helper.h Normal file
View file

@ -0,0 +1,11 @@
/*
* Helper.h
* CogAudio
*
* Created by Andre Reffhaug on 2/17/08.
* Copyright 2008 __MyCompanyName__. All rights reserved.
*
*/
double logarithmicToLinear(const double logarithmic, double MAX_VOLUME);
double linearToLogarithmic(const double linear, double MAX_VOLUME);

25
Audio/Helper.m Normal file
View file

@ -0,0 +1,25 @@
/*
* Helper.c
* CogAudio
*
* Created by Andre Reffhaug on 2/17/08.
* Copyright 2008 __MyCompanyName__. All rights reserved.
*
*/
#include "Helper.h"
#include <math.h>
// These functions are helpers for the process of converting volume from a linear to logarithmic scale.
// Numbers that goes in to audioPlayer should be logarithmic. Numbers that are displayed to the user should be linear.
// Here's why: http://www.dr-lex.34sp.com/info-stuff/volumecontrols.html
// We are using the approximation of X^2 when volume is limited to 100% and X^4 when volume is limited to 800%.
// Input/Output values are in percents.
double logarithmicToLinear(const double logarithmic, double MAX_VOLUME) {
return (MAX_VOLUME == 100.0) ? pow((logarithmic / MAX_VOLUME), 0.5) * 100.0 : pow((logarithmic / MAX_VOLUME), 0.25) * 100.0;
}
double linearToLogarithmic(const double linear, double MAX_VOLUME) {
return (MAX_VOLUME == 100.0) ? (linear / 100.0) * (linear / 100.0) * MAX_VOLUME : (linear / 100.0) * (linear / 100.0) * (linear / 100.0) * (linear / 100.0) * MAX_VOLUME;
}
// End helper volume function thingies. ONWARDS TO GLORY!

View file

@ -1,19 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>com.yourcompany.yourcocoaframework</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleSignature</key>

View file

@ -0,0 +1,160 @@
//
// OutputAVFoundation.h
// Cog
//
// Created by Christopher Snowhill on 6/23/22.
// Copyright 2022 Christopher Snowhill. All rights reserved.
//
#import <AssertMacros.h>
#import <Cocoa/Cocoa.h>
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AudioUnit/AudioUnit.h>
#import <CoreAudio/AudioHardware.h>
#import <CoreAudio/CoreAudioTypes.h>
#ifdef __cplusplus
#import <atomic>
using std::atomic_long;
#else
#import <stdatomic.h>
#endif
#import "Downmix.h"
#import <CogAudio/CogAudio-Swift.h>
#import "HeadphoneFilter.h"
//#define OUTPUT_LOG
#ifdef OUTPUT_LOG
#import <stdio.h>
#endif
@class OutputNode;
@class FSurroundFilter;
@interface OutputAVFoundation : NSObject {
OutputNode *outputController;
BOOL rsDone;
void *rsstate, *rsold;
double lastClippedSampleRate;
void *rsvis;
double lastVisRate;
BOOL stopInvoked;
BOOL stopCompleted;
BOOL running;
BOOL stopping;
BOOL stopped;
BOOL started;
BOOL paused;
BOOL restarted;
BOOL commandStop;
BOOL eqEnabled;
BOOL eqInitialized;
BOOL streamFormatStarted;
BOOL streamFormatChanged;
double secondsHdcdSustained;
BOOL defaultdevicelistenerapplied;
BOOL currentdevicelistenerapplied;
BOOL devicealivelistenerapplied;
BOOL observersapplied;
BOOL outputdevicechanged;
float volume;
float eqPreamp;
AudioDeviceID outputDeviceID;
AudioStreamBasicDescription realStreamFormat; // stream format pre-hrtf
AudioStreamBasicDescription streamFormat; // stream format last seen in render callback
AudioStreamBasicDescription realNewFormat; // in case of resampler flush
AudioStreamBasicDescription newFormat; // in case of resampler flush
AudioStreamBasicDescription visFormat; // Mono format for vis
uint32_t realStreamChannelConfig;
uint32_t streamChannelConfig;
uint32_t realNewChannelConfig;
uint32_t newChannelConfig;
AVSampleBufferAudioRenderer *audioRenderer;
AVSampleBufferRenderSynchronizer *renderSynchronizer;
CMAudioFormatDescriptionRef audioFormatDescription;
id currentPtsObserver;
NSLock *currentPtsLock;
CMTime currentPts, lastPts;
double secondsLatency;
CMTime outputPts, trackPts, lastCheckpointPts;
AudioTimeStamp timeStamp;
size_t _bufferSize;
AudioUnit _eq;
DownmixProcessor *downmixerForVis;
VisualizationController *visController;
BOOL enableHrtf;
HeadphoneFilter *hrtf;
BOOL enableFSurround;
BOOL FSurroundDelayRemoved;
int inputBufferLastTime;
FSurroundFilter *fsurround;
BOOL resetStreamFormat;
BOOL shouldPlayOutBuffer;
float *samplePtr;
float tempBuffer[512 * 32];
float rsTempBuffer[4096 * 32];
float inputBuffer[4096 * 32]; // 4096 samples times maximum supported channel count
float fsurroundBuffer[8192 * 6];
float hrtfBuffer[4096 * 2];
float eqBuffer[4096 * 32];
float visAudio[4096];
float visTemp[8192];
#ifdef OUTPUT_LOG
FILE *_logFile;
#endif
}
- (id)initWithController:(OutputNode *)c;
- (BOOL)setup;
- (OSStatus)setOutputDeviceByID:(AudioDeviceID)deviceID;
- (BOOL)setOutputDeviceWithDeviceDict:(NSDictionary *)deviceDict;
- (void)start;
- (void)pause;
- (void)resume;
- (void)stop;
- (double)latency;
- (void)setVolume:(double)v;
- (void)setEqualizerEnabled:(BOOL)enabled;
- (void)setShouldPlayOutBuffer:(BOOL)enabled;
- (void)sustainHDCD;
@end

File diff suppressed because it is too large Load diff

View file

@ -2,35 +2,131 @@
// OutputCoreAudio.h
// Cog
//
// Created by Vincent Spader on 8/2/05.
// Copyright 2005 Vincent Spader. All rights reserved.
// Created by Christopher Snowhill on 7/25/23.
// Copyright 2023-2024 Christopher Snowhill. All rights reserved.
//
#import <AssertMacros.h>
#import <Cocoa/Cocoa.h>
#import <CoreAudio/AudioHardware.h>
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AudioUnit/AudioUnit.h>
#import <CoreAudio/AudioHardware.h>
#import <CoreAudio/CoreAudioTypes.h>
#ifdef __cplusplus
#import <atomic>
using std::atomic_long;
#else
#import <stdatomic.h>
#endif
#import <simd/simd.h>
#import <CogAudio/ChunkList.h>
#import <CogAudio/HeadphoneFilter.h>
//#define OUTPUT_LOG
@class OutputNode;
@interface OutputCoreAudio : NSObject {
OutputNode * outputController;
@class AudioChunk;
AudioUnit outputUnit;
AURenderCallbackStruct renderCallback;
AudioStreamBasicDescription deviceFormat; // info about the default device
@interface OutputCoreAudio : NSObject {
OutputNode *outputController;
dispatch_semaphore_t writeSemaphore;
dispatch_semaphore_t readSemaphore;
NSLock *outputLock;
double streamTimestamp;
BOOL stopInvoked;
BOOL stopCompleted;
BOOL running;
BOOL stopping;
BOOL stopped;
BOOL started;
BOOL paused;
BOOL restarted;
BOOL commandStop;
BOOL resetting;
BOOL cutOffInput;
BOOL fading, faded;
float fadeLevel;
float fadeStep;
float fadeTarget;
BOOL eqEnabled;
BOOL eqInitialized;
BOOL streamFormatStarted;
BOOL streamFormatChanged;
double secondsHdcdSustained;
BOOL defaultdevicelistenerapplied;
BOOL currentdevicelistenerapplied;
BOOL devicealivelistenerapplied;
BOOL observersapplied;
BOOL outputdevicechanged;
float volume;
float eqPreamp;
AVAudioFormat *_deviceFormat;
AudioDeviceID outputDeviceID;
AudioStreamBasicDescription deviceFormat;
AudioStreamBasicDescription realStreamFormat; // stream format pre-hrtf
AudioStreamBasicDescription streamFormat; // stream format last seen in render callback
uint32_t deviceChannelConfig;
uint32_t realStreamChannelConfig;
uint32_t streamChannelConfig;
AUAudioUnit *_au;
size_t _bufferSize;
BOOL resetStreamFormat;
BOOL shouldPlayOutBuffer;
ChunkList *outputBuffer;
#ifdef OUTPUT_LOG
NSFileHandle *_logFile;
#endif
}
- (id)initWithController:(OutputNode *)c;
- (BOOL)setup;
- (BOOL)setOutputDevice:(AudioDeviceID)outputDevice;
- (OSStatus)setOutputDeviceByID:(int)deviceID;
- (BOOL)setOutputDeviceWithDeviceDict:(NSDictionary *)deviceDict;
- (void)start;
- (void)pause;
- (void)resume;
- (void)stop;
- (void)setVolume:(double) v;
- (void)fadeOut;
- (void)fadeOutBackground;
- (void)fadeIn;
- (double)latency;
- (double)volume;
- (void)setVolume:(double)v;
- (void)setShouldPlayOutBuffer:(BOOL)enabled;
- (void)sustainHDCD;
- (AudioStreamBasicDescription)deviceFormat;
- (uint32_t)deviceChannelConfig;
@end

File diff suppressed because it is too large Load diff

View file

@ -1,55 +1,119 @@
/*
Are defines really appropriate for this?
We want something easily insertable into a dictionary.
Maybe should extern these, and shove the instances in PluginController.m, but will that cause linking problems?
*/
// Plugins! HOORAY!
#define kCogSource @"CogSource"
#define kCogDecoder @"CogDecoder"
#define kCogMetadataReader @"CogMetadataReader"
#define kCogPropertiesReader @"CogPropertiesReader"
@protocol CogPlugin <NSObject>
//Dictionary containing classname/plugintype pairs. ex: @"VorbisDecoder": kCogDecoder, @"VorbisPropertiesRaeder": kCogPropertiesReader
+ (NSDictionary *)pluginInfo;
@end
#if __has_include(<CogAudio/AudioChunk.h>)
# import <CogAudio/AudioChunk.h>
#else
# import "AudioChunk.h"
#endif
@protocol CogSource <NSObject>
+ (NSArray *)schemes; //http, file, etc
+ (NSArray *)schemes; // http, file, etc
- (NSURL *)url;
- (NSString *)mimeType;
- (BOOL)open:(NSURL *)url;
- (NSDictionary *)properties; //Perhaps contains header info for HTTP stream, or path for a regular file.
- (BOOL)seekable;
- (BOOL)seek:(long)position whence:(int)whence;
- (long)tell;
- (int)read:(void *)buffer amount:(int)amount; //reads UP TO amount, returns amount read.
- (long)read:(void *)buffer amount:(long)amount; // reads UP TO amount, returns amount read.
- (void)close;
- (void)dealloc;
@end
@protocol CogVersionCheck <NSObject>
+ (BOOL)shouldLoadForOSVersion:(NSOperatingSystemVersion)version;
@end
@protocol CogContainer <NSObject>
+ (NSArray *)fileTypes; // mp3, ogg, etc
+ (NSArray *)mimeTypes;
+ (float)priority;
+ (NSArray *)urlsForContainerURL:(NSURL *)url;
@optional
+ (NSArray *)dependencyUrlsForContainerURL:(NSURL *)url;
@end
@protocol CogDecoder <NSObject>
+ (NSArray *)fileTypes; //mp3, ogg, etc
@required
+ (NSArray *)mimeTypes;
+ (NSArray *)fileTypes; // mp3, ogg, etc
+ (NSArray *)fileTypeAssociations; // array of NSArray of NSString, where first item in array is the type name, the second is the icon name, and the rest are the extensions
+ (float)priority; // should be 0.0 ... 1.0, higher means you get selected first, should default to 1.0 unless you know a reason why any of your extensions may behave badly, ie. greedily taking over some file type extension without performing any header validation on it
//For KVO
// For KVO
//- (void)setProperties:(NSDictionary *)p;
- (NSDictionary *)properties;
- (NSDictionary *)metadata; // Only to be implemented for dynamic metadata, send events on change
- (AudioChunk *)readAudio;
- (BOOL)open:(id<CogSource>)source;
- (double)seekToTime:(double)time; //time is in milleseconds, should return the time actually seeked to.
- (int)fillBuffer:(void *)buf ofSize:(UInt32)size;
- (long)seek:(long)frame;
- (void)close;
@optional
- (void)dealloc;
- (BOOL)setTrack:(NSURL *)track;
// These are in NSObject, so as long as you are a subclass of that, you are ok.
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(void *)context;
- (BOOL)isSilence;
@end
@protocol CogMetadataReader <NSObject>
+ (NSArray *)fileTypes;
+ (NSDictionary *)metadataForURL;
+ (NSArray *)mimeTypes;
+ (float)priority;
+ (NSDictionary *)metadataForURL:(NSURL *)url;
@end
@protocol CogMetadataWriter <NSObject>
//+ (NSArray *)fileTypes;
//+ (NSArray *)mimeTypes;
+ (int)putMetadataInURL:(NSURL *)url tagData:(NSDictionary *)tagData;
@end
@protocol CogPropertiesReader <NSObject>
+ (NSArray *)fileTypes;
+ (NSArray *)mimeTypes;
+ (float)priority;
+ (NSDictionary *)propertiesForSource:(id<CogSource>)source;
@end
@protocol CogPluginController <NSObject>
+ (id<CogPluginController>)sharedPluginController;
- (NSDictionary *)sources;
- (NSDictionary *)containers;
- (NSDictionary *)metadataReaders;
- (NSDictionary *)propertiesReadersByExtension;
- (NSDictionary *)propertiesReadersByMimeType;
- (NSDictionary *)decodersByExtension;
- (NSDictionary *)decodersByMimeType;
- (id<CogSource>)audioSourceForURL:(NSURL *)url;
- (NSArray *)urlsForContainerURL:(NSURL *)url;
- (NSArray *)dependencyUrlsForContainerURL:(NSURL *)url;
- (NSDictionary *)metadataForURL:(NSURL *)url skipCue:(BOOL)skip;
- (NSDictionary *)propertiesForURL:(NSURL *)url skipCue:(BOOL)skip;
- (id<CogDecoder>)audioDecoderForSource:(id<CogSource>)source skipCue:(BOOL)skip;
- (int)putMetadataInURL:(NSURL *)url;
@end
#ifdef __cplusplus
extern "C" {
#endif
extern NSString *guess_encoding_of_string(const char *input);
#ifdef __cplusplus
}
#endif

View file

@ -2,16 +2,34 @@
#import <Cocoa/Cocoa.h>
//Singleton
@interface PluginController : NSObject
{
#import <CogAudio/Plugin.h>
// Singletonish
@interface PluginController : NSObject <CogPluginController> {
NSMutableDictionary *sources;
NSMutableDictionary *decoders;
NSMutableDictionary *containers;
NSMutableDictionary *metadataReaders;
NSMutableDictionary *propertiesReaders;
NSMutableDictionary *propertiesReadersByExtension;
NSMutableDictionary *propertiesReadersByMimeType;
NSMutableDictionary *decodersByExtension;
NSMutableDictionary *decodersByMimeType;
BOOL configured;
}
+ (PluginController *)sharedPluginController; //Use this to get the instance.
@property(retain) NSMutableDictionary *sources;
@property(retain) NSMutableDictionary *containers;
@property(retain) NSMutableDictionary *metadataReaders;
@property(retain) NSMutableDictionary *propertiesReadersByExtension;
@property(retain) NSMutableDictionary *propertiesReadersByMimeType;
@property(retain) NSMutableDictionary *decodersByExtension;
@property(retain) NSMutableDictionary *decodersByMimeType;
@property BOOL configured;
- (void)setup;
- (void)printPluginInfo;
@ -20,13 +38,9 @@
- (void)loadPluginsAtPath:(NSString *)path;
- (void)setupSource:(NSString *)className;
- (void)setupContainer:(NSString *)className;
- (void)setupDecoder:(NSString *)className;
- (void)setupMetadataReader:(NSString *)className;
- (void)setupPropertiesReader:(NSString *)className;
- (NSDictionary *)sources;
- (NSDictionary *)decoders;
- (NSDictionary *)metadataReaders;
- (NSDictionary *)propertiesReaders;
@end

View file

@ -1,230 +0,0 @@
#import "PluginController.h"
#import "Plugin.h"
@implementation PluginController
//Start of singleton-related stuff.
static PluginController *sharedPluginController = nil;
+ (PluginController*)sharedPluginController
{
@synchronized(self) {
if (sharedPluginController == nil) {
[[self alloc] init]; // assignment not done here
}
}
return sharedPluginController;
}
+ (id)allocWithZone:(NSZone *)zone
{
@synchronized(self) {
if (sharedPluginController == nil) {
sharedPluginController = [super allocWithZone:zone];
return sharedPluginController; // assignment and return on first allocation
}
}
return nil; //on subsequent allocation attempts return nil
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
- (id)retain
{
return self;
}
- (unsigned)retainCount
{
return UINT_MAX; //denotes an object that cannot be released
}
- (void)release
{
//do nothing
}
- (id)autorelease
{
return self;
}
//End of singleton-related stuff
- (id)init {
self = [super init];
if (self) {
sources = [[NSMutableDictionary alloc] init];
decoders = [[NSMutableDictionary alloc] init];
metadataReaders = [[NSMutableDictionary alloc] init];
propertiesReaders = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void)setup
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self loadPlugins];
[self printPluginInfo];
[pool release];
}
- (void)loadPluginsAtPath:(NSString *)path
{
NSArray *dirContents = [[NSFileManager defaultManager] directoryContentsAtPath:path];
NSEnumerator *dirEnum = [dirContents objectEnumerator];
NSString *pname;
while (pname = [dirEnum nextObject])
{
NSString *ppath;
ppath = [NSString pathWithComponents:[NSArray arrayWithObjects:path,pname,nil]];
if ([[pname pathExtension] isEqualToString:@"bundle"])
{
NSBundle *b = [NSBundle bundleWithPath:ppath];
if (b)
{
Class plugin = [b principalClass];
if ([plugin respondsToSelector:@selector(pluginInfo)])
{
//PluginInfo is a dictionary that contains keys/values like pluginClass,classType...ex: VorbisDecoder, Decoder
NSDictionary *pluginInfo = [plugin pluginInfo];
NSEnumerator *e = [pluginInfo keyEnumerator];
id className;
while (className = [e nextObject]) {
id pluginType = [pluginInfo objectForKey:className];
if ([pluginType isEqualToString:kCogDecoder]) {
[self setupDecoder:className];
}
else if ([pluginType isEqualToString:kCogMetadataReader]) {
[self setupMetadataReader:className];
}
else if ([pluginType isEqualToString:kCogPropertiesReader]) {
[self setupPropertiesReader:className];
}
else if ([pluginType isEqualToString:kCogSource]) {
[self setupSource:className];
}
else {
NSLog(@"Unknown plugin type!!");
}
}
}
}
}
}
}
- (void)loadPlugins
{
[self loadPluginsAtPath:[[NSBundle mainBundle] builtInPlugInsPath]];
[self loadPluginsAtPath:[@"~/Library/Application Support/Cog/Plugins" stringByExpandingTildeInPath]];
}
- (void)setupDecoder:(NSString *)className
{
Class decoder = NSClassFromString(className);
if (decoder && [decoder respondsToSelector:@selector(fileTypes)]) {
NSEnumerator *fileTypesEnum = [[decoder fileTypes] objectEnumerator];
id fileType;
while (fileType = [fileTypesEnum nextObject])
{
[decoders setObject:className forKey:[fileType lowercaseString]];
}
}
}
- (void)setupMetadataReader:(NSString *)className
{
Class metadataReader = NSClassFromString(className);
if (metadataReader && [metadataReader respondsToSelector:@selector(fileTypes)]) {
NSEnumerator *fileTypesEnum = [[metadataReader fileTypes] objectEnumerator];
id fileType;
while (fileType = [fileTypesEnum nextObject])
{
[metadataReaders setObject:className forKey:[fileType lowercaseString]];
}
}
}
- (void)setupPropertiesReader:(NSString *)className
{
Class propertiesReader = NSClassFromString(className);
if (propertiesReader && [propertiesReader respondsToSelector:@selector(fileTypes)]) {
NSEnumerator *fileTypesEnum = [[propertiesReader fileTypes] objectEnumerator];
id fileType;
while (fileType = [fileTypesEnum nextObject])
{
[propertiesReaders setObject:className forKey:[fileType lowercaseString]];
}
}
}
- (void)setupSource:(NSString *)className
{
Class source = NSClassFromString(className);
if (source && [source respondsToSelector:@selector(schemes)]) {
NSEnumerator *schemeEnum = [[source schemes] objectEnumerator];
id scheme;
while (scheme = [schemeEnum nextObject])
{
[sources setObject:className forKey:scheme];
}
}
}
- (void)printPluginInfo
{
/* NSLog(@"Sources: %@", sources);
NSLog(@"Decoders: %@", decoders);
NSLog(@"Metadata Readers: %@", metadataReaders);
NSLog(@"Properties Readers: %@", propertiesReaders); */
}
- (NSDictionary *)sources
{
return sources;
}
- (NSDictionary *)decoders
{
return decoders;
}
- (NSDictionary *)propertiesReaders
{
return propertiesReaders;
}
- (NSDictionary *)metadataReaders
{
return metadataReaders;
}
@end
//This is called when the framework is loaded.
void __attribute__ ((constructor)) InitializePlugins(void) {
static BOOL wasInitialized = NO;
if (!wasInitialized) {
// safety in case we get called twice.
[[PluginController sharedPluginController] setup];
wasInitialized = YES;
}
}

853
Audio/PluginController.mm Normal file
View file

@ -0,0 +1,853 @@
#import "PluginController.h"
#import "CogPluginMulti.h"
#import "Plugin.h"
#import "Logging.h"
#import "NSFileHandle+CreateFile.h"
#import "NSDictionary+Merge.h"
#import "RedundantPlaylistDataStore.h"
#import <chrono>
#import <map>
#import <mutex>
#import <thread>
struct Cached_Metadata {
std::chrono::steady_clock::time_point time_accessed;
NSDictionary *properties;
NSDictionary *metadata;
Cached_Metadata()
: properties(nil), metadata(nil) {
}
};
static std::mutex Cache_Lock;
static std::map<std::string, Cached_Metadata> Cache_List;
static RedundantPlaylistDataStore *Cache_Data_Store = nil;
static bool Cache_Running = false;
static bool Cache_Stopped = false;
static std::thread *Cache_Thread = NULL;
static void cache_run();
static void cache_init() {
Cache_Data_Store = [[RedundantPlaylistDataStore alloc] init];
Cache_Thread = new std::thread(cache_run);
}
static void cache_deinit() {
Cache_Running = false;
Cache_Thread->join();
while(!Cache_Stopped)
usleep(500);
delete Cache_Thread;
Cache_Data_Store = nil;
}
static void cache_insert_properties(NSURL *url, NSDictionary *properties) {
if(properties == nil) return;
std::lock_guard<std::mutex> lock(Cache_Lock);
std::string path = [[url absoluteString] UTF8String];
properties = [Cache_Data_Store coalesceEntryInfo:properties];
Cached_Metadata &entry = Cache_List[path];
entry.properties = properties;
entry.time_accessed = std::chrono::steady_clock::now();
}
static void cache_insert_metadata(NSURL *url, NSDictionary *metadata) {
if(metadata == nil) return;
std::lock_guard<std::mutex> lock(Cache_Lock);
std::string path = [[url absoluteString] UTF8String];
metadata = [Cache_Data_Store coalesceEntryInfo:metadata];
Cached_Metadata &entry = Cache_List[path];
entry.metadata = metadata;
entry.time_accessed = std::chrono::steady_clock::now();
}
static NSDictionary *cache_access_properties(NSURL *url) {
std::lock_guard<std::mutex> lock(Cache_Lock);
std::string path = [[url absoluteString] UTF8String];
Cached_Metadata &entry = Cache_List[path];
if(entry.properties) {
entry.time_accessed = std::chrono::steady_clock::now();
return entry.properties;
}
return nil;
}
static NSDictionary *cache_access_metadata(NSURL *url) {
std::lock_guard<std::mutex> lock(Cache_Lock);
std::string path = [[url absoluteString] UTF8String];
Cached_Metadata &entry = Cache_List[path];
if(entry.metadata) {
entry.time_accessed = std::chrono::steady_clock::now();
return entry.metadata;
}
return nil;
}
static void cache_run() {
std::chrono::milliseconds dura(250);
Cache_Running = true;
while(Cache_Running) {
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
@autoreleasepool {
std::lock_guard<std::mutex> lock(Cache_Lock);
size_t cacheListOriginalSize = Cache_List.size();
for(auto it = Cache_List.begin(); it != Cache_List.end();) {
auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(now - it->second.time_accessed);
if(elapsed.count() >= 10) {
it = Cache_List.erase(it);
continue;
}
++it;
}
if(cacheListOriginalSize && Cache_List.size() == 0) {
[Cache_Data_Store reset];
}
}
std::this_thread::sleep_for(dura);
}
Cache_Stopped = true;
}
@implementation PluginController
@synthesize sources;
@synthesize containers;
@synthesize metadataReaders;
@synthesize propertiesReadersByExtension;
@synthesize propertiesReadersByMimeType;
@synthesize decodersByExtension;
@synthesize decodersByMimeType;
@synthesize configured;
static PluginController *sharedPluginController = nil;
+ (id<CogPluginController>)sharedPluginController {
@synchronized(self) {
if(sharedPluginController == nil) {
sharedPluginController = [[self alloc] init];
}
}
return sharedPluginController;
}
- (id)init {
self = [super init];
if(self) {
self.sources = [[NSMutableDictionary alloc] init];
self.containers = [[NSMutableDictionary alloc] init];
self.metadataReaders = [[NSMutableDictionary alloc] init];
self.propertiesReadersByExtension = [[NSMutableDictionary alloc] init];
self.propertiesReadersByMimeType = [[NSMutableDictionary alloc] init];
self.decodersByExtension = [[NSMutableDictionary alloc] init];
self.decodersByMimeType = [[NSMutableDictionary alloc] init];
[self setup];
cache_init();
}
return self;
}
- (void)dealloc {
cache_deinit();
}
- (void)setup {
if(self.configured == NO) {
self.configured = YES;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(bundleDidLoad:) name:NSBundleDidLoadNotification object:nil];
[self loadPlugins];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSBundleDidLoadNotification object:nil];
[self printPluginInfo];
}
}
- (void)bundleDidLoad:(NSNotification *)notification {
NSArray *classNames = [[notification userInfo] objectForKey:@"NSLoadedClasses"];
for(NSString *className in classNames) {
Class bundleClass = NSClassFromString(className);
if([bundleClass conformsToProtocol:@protocol(CogVersionCheck)]) {
DLog(@"Component has version check: %@", className);
if(![bundleClass shouldLoadForOSVersion:[[NSProcessInfo processInfo] operatingSystemVersion]]) {
DLog(@"Plugin fails OS version check, ignoring");
return;
}
}
}
for(NSString *className in classNames) {
DLog(@"Class loaded: %@", className);
Class bundleClass = NSClassFromString(className);
if([bundleClass conformsToProtocol:@protocol(CogContainer)]) {
[self setupContainer:className];
}
if([bundleClass conformsToProtocol:@protocol(CogDecoder)]) {
[self setupDecoder:className];
}
if([bundleClass conformsToProtocol:@protocol(CogMetadataReader)]) {
[self setupMetadataReader:className];
}
if([bundleClass conformsToProtocol:@protocol(CogPropertiesReader)]) {
[self setupPropertiesReader:className];
}
if([bundleClass conformsToProtocol:@protocol(CogSource)]) {
[self setupSource:className];
}
}
}
- (void)loadPluginsAtPath:(NSString *)path {
NSArray *dirContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
for(NSString *pname in dirContents) {
NSString *ppath;
ppath = [NSString pathWithComponents:@[path, pname]];
if([[pname pathExtension] isEqualToString:@"bundle"]) {
NSBundle *b = [NSBundle bundleWithPath:ppath];
[b load];
}
}
}
- (void)loadPlugins {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *basePath = [[paths firstObject] stringByAppendingPathComponent:@"Cog"];
[self loadPluginsAtPath:[[NSBundle mainBundle] builtInPlugInsPath]];
[self loadPluginsAtPath:[basePath stringByAppendingPathComponent:@"Plugins"]];
}
- (void)setupContainer:(NSString *)className {
Class container = NSClassFromString(className);
if(container && [container respondsToSelector:@selector(fileTypes)]) {
for(id fileType in [container fileTypes]) {
NSString *ext = [fileType lowercaseString];
NSMutableArray *containerSet;
if(![containers objectForKey:ext]) {
containerSet = [[NSMutableArray alloc] init];
[containers setObject:containerSet forKey:ext];
} else
containerSet = [containers objectForKey:ext];
[containerSet addObject:className];
}
}
}
- (void)setupDecoder:(NSString *)className {
Class decoder = NSClassFromString(className);
if(decoder && [decoder respondsToSelector:@selector(fileTypes)]) {
for(id fileType in [decoder fileTypes]) {
NSString *ext = [fileType lowercaseString];
NSMutableArray *decoders;
if(![decodersByExtension objectForKey:ext]) {
decoders = [[NSMutableArray alloc] init];
[decodersByExtension setObject:decoders forKey:ext];
} else
decoders = [decodersByExtension objectForKey:ext];
[decoders addObject:className];
}
}
if(decoder && [decoder respondsToSelector:@selector(mimeTypes)]) {
for(id mimeType in [decoder mimeTypes]) {
NSString *mimetype = [mimeType lowercaseString];
NSMutableArray *decoders;
if(![decodersByMimeType objectForKey:mimetype]) {
decoders = [[NSMutableArray alloc] init];
[decodersByMimeType setObject:decoders forKey:mimetype];
} else
decoders = [decodersByMimeType objectForKey:mimetype];
[decoders addObject:className];
}
}
}
- (void)setupMetadataReader:(NSString *)className {
Class metadataReader = NSClassFromString(className);
if(metadataReader && [metadataReader respondsToSelector:@selector(fileTypes)]) {
for(id fileType in [metadataReader fileTypes]) {
NSString *ext = [fileType lowercaseString];
NSMutableArray *readers;
if(![metadataReaders objectForKey:ext]) {
readers = [[NSMutableArray alloc] init];
[metadataReaders setObject:readers forKey:ext];
} else
readers = [metadataReaders objectForKey:ext];
[readers addObject:className];
}
}
}
- (void)setupPropertiesReader:(NSString *)className {
Class propertiesReader = NSClassFromString(className);
if(propertiesReader && [propertiesReader respondsToSelector:@selector(fileTypes)]) {
for(id fileType in [propertiesReader fileTypes]) {
NSString *ext = [fileType lowercaseString];
NSMutableArray *readers;
if(![propertiesReadersByExtension objectForKey:ext]) {
readers = [[NSMutableArray alloc] init];
[propertiesReadersByExtension setObject:readers forKey:ext];
} else
readers = [propertiesReadersByExtension objectForKey:ext];
[readers addObject:className];
}
}
if(propertiesReader && [propertiesReader respondsToSelector:@selector(mimeTypes)]) {
for(id mimeType in [propertiesReader mimeTypes]) {
NSString *mimetype = [mimeType lowercaseString];
NSMutableArray *readers;
if(![propertiesReadersByMimeType objectForKey:mimetype]) {
readers = [[NSMutableArray alloc] init];
[propertiesReadersByMimeType setObject:readers forKey:mimetype];
} else
readers = [propertiesReadersByMimeType objectForKey:mimetype];
[readers addObject:className];
}
}
}
- (void)setupSource:(NSString *)className {
Class source = NSClassFromString(className);
if(source && [source respondsToSelector:@selector(schemes)]) {
for(id scheme in [source schemes]) {
[sources setObject:className forKey:scheme];
}
}
}
static NSString *xmlEscapeString(NSString * string) {
CFStringRef textXML = CFXMLCreateStringByEscapingEntities(kCFAllocatorDefault, (CFStringRef)string, nil);
if(textXML) {
NSString *textString = (__bridge NSString *)textXML;
CFRelease(textXML);
return textString;
}
return @"";
}
- (void)printPluginInfo {
ALog(@"Sources: %@", self.sources);
ALog(@"Containers: %@", self.containers);
ALog(@"Metadata Readers: %@", self.metadataReaders);
ALog(@"Properties Readers By Extension: %@", self.propertiesReadersByExtension);
ALog(@"Properties Readers By Mime Type: %@", self.propertiesReadersByMimeType);
ALog(@"Decoders by Extension: %@", self.decodersByExtension);
ALog(@"Decoders by Mime Type: %@", self.decodersByMimeType);
#if 0
// XXX Keep in sync with Info.plist on disk!
NSString * plistHeader = @"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n\
<plist version=\"1.0\">\n\
<dict>\n\
\t<key>SUEnableInstallerLauncherService</key>\n\
\t<true/>\n\
\t<key>CFBundleDevelopmentRegion</key>\n\
\t<string>en_US</string>\n\
\t<key>CFBundleDocumentTypes</key>\n\
\t<array>\n\
\t\t<dict>\n\
\t\t\t<key>CFBundleTypeExtensions</key>\n\
\t\t\t<array>\n\
\t\t\t\t<string>*</string>\n\
\t\t\t</array>\n\
\t\t\t<key>CFBundleTypeIconFile</key>\n\
\t\t\t<string>song.icns</string>\n\
\t\t\t<key>CFBundleTypeIconSystemGenerated</key>\n\
\t\t\t<integer>1</integer>\n\
\t\t\t<key>CFBundleTypeName</key>\n\
\t\t\t<string>Folder</string>\n\
\t\t\t<key>CFBundleTypeOSTypes</key>\n\
\t\t\t<array>\n\
\t\t\t\t<string>****</string>\n\
\t\t\t\t<string>fold</string>\n\
\t\t\t\t<string>disk</string>\n\
\t\t\t</array>\n\
\t\t\t<key>CFBundleTypeRole</key>\n\
\t\t\t<string>None</string>\n\
\t\t\t<key>LSHandlerRank</key>\n\
\t\t\t<string>Default</string>\n\
\t\t</dict>\n";
NSString * plistFooter = @"\t</array>\n\
\t<key>CFBundleExecutable</key>\n\
\t<string>Cog</string>\n\
\t<key>CFBundleHelpBookName</key>\n\
\t<string>org.cogx.cog.help</string>\n\
\t<key>CFBundleIdentifier</key>\n\
\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\
\t<key>CFBundleInfoDictionaryVersion</key>\n\
\t<string>6.0</string>\n\
\t<key>CFBundleName</key>\n\
\t<string>$(PRODUCT_NAME)</string>\n\
\t<key>CFBundleDisplayName</key>\n\
\t<string>$(PRODUCT_NAME)</string>\n\
\t<key>CFBundlePackageType</key>\n\
\t<string>APPL</string>\n\
\t<key>CFBundleShortVersionString</key>\n\
\t<string>0.08</string>\n\
\t<key>CFBundleSignature</key>\n\
\t<string>????</string>\n\
\t<key>CFBundleVersion</key>\n\
\t<string>r516</string>\n\
\t<key>LSApplicationCategoryType</key>\n\
\t<string>public.app-category.music</string>\n\
\t<key>LSMinimumSystemVersion</key>\n\
\t<string>$(MACOSX_DEPLOYMENT_TARGET)</string>\n\
\t<key>NSAppTransportSecurity</key>\n\
\t<dict>\n\
\t\t<key>NSAllowsArbitraryLoads</key>\n\
\t\t<true/>\n\
\t</dict>\n\
\t<key>NSAppleScriptEnabled</key>\n\
\t<string>YES</string>\n\
\t<key>NSCalendarsUsageDescription</key>\n\
\t<string>Cog has no use for your calendar information. Why are you trying to open your Calendar with an audio player?</string>\n\
\t<key>NSCameraUsageDescription</key>\n\
\t<string>Cog is an audio player. It will never use your camera. Why is it asking for permission to use your camera?</string>\n\
\t<key>NSContactsUsageDescription</key>\n\
\t<string>Cog has no use for your contacts information. Why are you trying to open your contacts with an audio player?</string>\n\
\t<key>NSLocationUsageDescription</key>\n\
\t<string>Cog has no use for your location information. Something is obviously wrong with the application.</string>\n\
\t<key>NSMainNibFile</key>\n\
\t<string>MainMenu</string>\n\
\t<key>NSMicrophoneUsageDescription</key>\n\
\t<string>Cog is an audio player. It does not, however, record audio. Why is it asking for permission to use your microphone?</string>\n\
\t<key>NSPhotoLibraryUsageDescription</key>\n\
\t<string>Cog is an audio player. Why are you trying to access your Photos Library with an audio player?</string>\n\
\t<key>NSPrincipalClass</key>\n\
\t<string>MediaKeysApplication</string>\n\
\t<key>NSRemindersUsageDescription</key>\n\
\t<string>Cog has no use for your reminders. Why are you trying to access them with an audio player?</string>\n\
\t<key>NSDownloadsFolderUsageDescription</key>\n\
\t<string>We may request related audio files from this folder for playback purposes. We will only play back files you specifically add, unless you enable the option to add an entire folder. Granting permission either for individual files or for parent folders ensures their contents will remain playable in future sessions.</string>\n\
\t<key>NSDocumentsFolderUsageDescription</key>\n\
\t<string>We may request related audio files from this folder for playback purposes. We will only play back files you specifically add, unless you enable the option to add an entire folder. Granting permission either for individual files or for parent folders ensures their contents will remain playable in future sessions.</string>\n\
\t<key>NSDesktopFolderUsageDescription</key>\n\
\t<string>We may request related audio files from this folder for playback purposes. We will only play back files you specifically add, unless you enable the option to add an entire folder. Granting permission either for individual files or for parent folders ensures their contents will remain playable in future sessions.</string>\n\
\t<key>NSMotionUsageDescription</key>\n\
\t<string>Cog optionally supports motion tracking headphones for head tracked positional audio, using its own low latency positioning model.</string>\n\
\t<key>OSAScriptingDefinition</key>\n\
\t<string>Cog.sdef</string>\n\
\t<key>SUFeedURL</key>\n\
\t<string>https://cogcdn.cog.losno.co/mercury.xml</string>\n\
\t<key>SUPublicEDKey</key>\n\
\t<string>omxG7Rp0XK9/YEvKbVy7cd44eVAh1LJB6CmjQwjOJz4=</string>\n\
\t<key>ITSAppUsesNonExemptEncryption</key>\n\
\t<false/>\n\
</dict>\n\
</plist>\n";
NSMutableArray * decodersRegistered = [[NSMutableArray alloc] init];
NSArray * allKeys = [self.decodersByExtension allKeys];
for (NSString * ext in allKeys) {
NSArray * decoders = [self.decodersByExtension objectForKey:ext];
for (NSString * decoder in decoders) {
if (![decodersRegistered containsObject:decoder]) {
[decodersRegistered addObject:decoder];
}
}
}
NSMutableArray * stringList = [[NSMutableArray alloc] init];
[stringList addObject:plistHeader];
// These aren't handled by decoders, but as containers
NSArray * staticTypes = @[
@[@"M3U Playlist File", @"m3u.icns", @"m3u", @"m3u8"],
@[@"PLS Playlist File", @"pls.icns", @"pls"],
@[@"RAR Archive of SPC Files", @"vg.icns", @"rsn"],
@[@"7Z Archive of VGM Files", @"vg.icns", @"vgm7z"]
];
NSMutableArray * assocTypes = [[NSMutableArray alloc] init];
[assocTypes addObjectsFromArray:staticTypes];
for (NSString * decoderString in decodersRegistered) {
Class decoder = NSClassFromString(decoderString);
if (decoder && [decoder respondsToSelector:@selector(fileTypeAssociations)]) {
NSArray * types = [decoder fileTypeAssociations];
[assocTypes addObjectsFromArray:types];
}
}
for (NSArray * type in assocTypes) {
[stringList addObject:@"\t\t<dict>\n\
\t\t\t<key>CFBundleTypeExtensions</key>\n\
\t\t\t<array>\n\
"];
for (size_t i = 2; i < [type count]; ++i) {
[stringList addObject:@"\t\t\t\t<string>"];
[stringList addObject:[[type objectAtIndex:i] lowercaseString]];
[stringList addObject:@"</string>\n"];
}
[stringList addObject:@"\t\t\t</array>\n\
\t\t\t<key>CFBundleTypeIconFile</key>\n\
\t\t\t<string>"];
[stringList addObject:[type objectAtIndex:1]];
[stringList addObject:@"</string>\n\
\t\t\t<key>CFBundleTypeIconSystemGenerated</key>\n\
\t\t\t<integer>1</integer>\n\
\t\t\t<key>CFBundleTypeName</key>\n\
\t\t\t<string>"];
[stringList addObject:xmlEscapeString([type objectAtIndex:0])];
[stringList addObject:@"</string>\n\
\t\t\t<key>CFBundleTypeRole</key>\n\
\t\t\t<string>Viewer</string>\n\
\t\t\t<key>LSHandlerRank</key>\n\
\t\t\t<string>Default</string>\n\
\t\t\t<key>LSTypeIsPackage</key>\n\
\t\t\t<false/>\n\
\t\t</dict>\n"];
}
[stringList addObject:plistFooter];
NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"Cog_Info.plist"] createFile:YES];
if (!fileHandle) {
DLog(@"Error saving Info.plist!");
return;
}
[fileHandle truncateFileAtOffset:0];
[fileHandle writeData:[[stringList componentsJoinedByString:@""] dataUsingEncoding:NSUTF8StringEncoding]];
[fileHandle closeFile];
#endif
}
- (id<CogSource>)audioSourceForURL:(NSURL *)url {
NSString *scheme = [url scheme];
Class source = NSClassFromString([sources objectForKey:scheme]);
return [[source alloc] init];
}
- (NSArray *)urlsForContainerURL:(NSURL *)url {
NSString *ext = [url pathExtension];
NSArray *containerSet = [containers objectForKey:[ext lowercaseString]];
NSString *classString;
if(containerSet) {
if([containerSet count] > 1) {
return [CogContainerMulti urlsForContainerURL:url containers:containerSet];
} else {
classString = [containerSet objectAtIndex:0];
}
} else {
return nil;
}
Class container = NSClassFromString(classString);
return [container urlsForContainerURL:url];
}
- (NSArray *)dependencyUrlsForContainerURL:(NSURL *)url {
NSString *ext = [url pathExtension];
NSArray *containerSet = [containers objectForKey:[ext lowercaseString]];
NSString *classString;
if(containerSet) {
if([containerSet count] > 1) {
return [CogContainerMulti dependencyUrlsForContainerURL:url containers:containerSet];
} else {
classString = [containerSet objectAtIndex:0];
}
} else {
return nil;
}
Class container = NSClassFromString(classString);
if([container respondsToSelector:@selector(dependencyUrlsForContainerURL:)]) {
return [container dependencyUrlsForContainerURL:url];
} else {
return nil;
}
}
// Note: Source is assumed to already be opened.
- (id<CogDecoder>)audioDecoderForSource:(id<CogSource>)source skipCue:(BOOL)skip {
NSString *ext = [[source url] pathExtension];
NSArray *decoders = [decodersByExtension objectForKey:[ext lowercaseString]];
NSString *classString;
if(decoders) {
if([decoders count] > 1) {
if(skip) {
NSMutableArray *_decoders = [decoders mutableCopy];
for(int i = 0; i < [_decoders count];) {
if([[_decoders objectAtIndex:i] isEqualToString:@"CueSheetDecoder"])
[_decoders removeObjectAtIndex:i];
else
++i;
}
return [[CogDecoderMulti alloc] initWithDecoders:_decoders];
}
return [[CogDecoderMulti alloc] initWithDecoders:decoders];
} else {
classString = [decoders objectAtIndex:0];
}
} else {
decoders = [decodersByMimeType objectForKey:[[source mimeType] lowercaseString]];
if(decoders) {
if([decoders count] > 1) {
return [[CogDecoderMulti alloc] initWithDecoders:decoders];
} else {
classString = [decoders objectAtIndex:0];
}
} else {
classString = @"SilenceDecoder";
}
}
if(skip && [classString isEqualToString:@"CueSheetDecoder"]) {
classString = @"SilenceDecoder";
}
Class decoder = NSClassFromString(classString);
return [[decoder alloc] init];
}
+ (BOOL)isCoverFile:(NSString *)fileName {
for(NSString *coverFileName in [PluginController coverNames]) {
if([[[[fileName lastPathComponent] stringByDeletingPathExtension] lowercaseString] hasSuffix:coverFileName]) {
return true;
}
}
return false;
}
+ (NSArray *)coverNames {
return @[@"cover", @"folder", @"album", @"front"];
}
- (NSDictionary *)metadataForURL:(NSURL *)url skipCue:(BOOL)skip {
NSString *urlScheme = [url scheme];
if([urlScheme isEqualToString:@"http"] ||
[urlScheme isEqualToString:@"https"])
return nil;
NSDictionary *cacheData = cache_access_metadata(url);
if(cacheData) return cacheData;
do {
NSString *ext = [url pathExtension];
NSArray *readers = [metadataReaders objectForKey:[ext lowercaseString]];
NSString *classString;
if(readers) {
if([readers count] > 1) {
if(skip) {
NSMutableArray *_readers = [readers mutableCopy];
for(int i = 0; i < [_readers count];) {
if([[_readers objectAtIndex:i] isEqualToString:@"CueSheetMetadataReader"])
[_readers removeObjectAtIndex:i];
else
++i;
}
cacheData = [CogMetadataReaderMulti metadataForURL:url readers:_readers];
break;
}
cacheData = [CogMetadataReaderMulti metadataForURL:url readers:readers];
break;
} else {
classString = [readers objectAtIndex:0];
}
} else {
cacheData = nil;
break;
}
if(skip && [classString isEqualToString:@"CueSheetMetadataReader"]) {
cacheData = nil;
break;
}
Class metadataReader = NSClassFromString(classString);
cacheData = [metadataReader metadataForURL:url];
} while(0);
if(cacheData == nil) {
cacheData = [NSDictionary dictionary];
}
if(cacheData) {
NSData *image = [cacheData objectForKey:@"albumArt"];
if(nil == image) {
// Try to load image from external file
NSString *path = [[url path] stringByDeletingLastPathComponent];
// Gather list of candidate image files
NSArray *fileNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
NSArray *types = @[@"jpg", @"jpeg", @"png", @"gif", @"webp", @"avif", @"heic"];
NSArray *imageFileNames = [fileNames pathsMatchingExtensions:types];
for(NSString *fileName in imageFileNames) {
if([PluginController isCoverFile:fileName]) {
image = [NSData dataWithContentsOfFile:[path stringByAppendingPathComponent:fileName]];
break;
}
}
if(image) {
NSMutableDictionary *data = [cacheData mutableCopy];
[data setValue:image forKey:@"albumArt"];
cacheData = data;
}
}
}
cache_insert_metadata(url, cacheData);
return cacheData;
}
// If no properties reader is defined, use the decoder's properties.
- (NSDictionary *)propertiesForURL:(NSURL *)url skipCue:(BOOL)skip {
NSString *urlScheme = [url scheme];
if([urlScheme isEqualToString:@"http"] ||
[urlScheme isEqualToString:@"https"])
return nil;
NSDictionary *properties = nil;
properties = cache_access_properties(url);
if(properties) return properties;
NSString *ext = [url pathExtension];
id<CogSource> source = [self audioSourceForURL:url];
if(![source open:url])
return nil;
NSArray *readers = [propertiesReadersByExtension objectForKey:[ext lowercaseString]];
NSString *classString = nil;
if(readers) {
if([readers count] > 1) {
properties = [CogPropertiesReaderMulti propertiesForSource:source readers:readers];
if(properties != nil && [properties count]) {
cache_insert_properties(url, properties);
return properties;
}
} else {
classString = [readers objectAtIndex:0];
}
} else {
readers = [propertiesReadersByMimeType objectForKey:[[source mimeType] lowercaseString]];
if(readers) {
if([readers count] > 1) {
properties = [CogPropertiesReaderMulti propertiesForSource:source readers:readers];
if(properties != nil && [properties count]) {
cache_insert_properties(url, properties);
return properties;
}
} else {
classString = [readers objectAtIndex:0];
}
}
}
if(classString) {
Class propertiesReader = NSClassFromString(classString);
properties = [propertiesReader propertiesForSource:source];
if(properties != nil && [properties count]) {
cache_insert_properties(url, properties);
return properties;
}
}
{
id<CogDecoder> decoder = [self audioDecoderForSource:source skipCue:skip];
if(![decoder open:source]) {
return nil;
}
NSDictionary *properties = [decoder properties];
NSDictionary *metadata = [decoder metadata];
[decoder close];
NSDictionary *cacheData = [NSDictionary dictionaryByMerging:properties with:metadata];
cache_insert_properties(url, cacheData);
return cacheData;
}
}
- (int)putMetadataInURL:(NSURL *)url {
return 0;
}
@end
NSString *guess_encoding_of_string(const char *input) {
NSString *ret = @"";
if(input && *input) {
@try {
ret = [NSString stringWithUTF8String:input];
}
@catch(NSException *e) {
ret = nil;
}
if(!ret) {
// This method is incredibly slow
NSData *stringData = [NSData dataWithBytes:input length:strlen(input)];
[NSString stringEncodingForData:stringData encodingOptions:nil convertedString:&ret usedLossyConversion:nil];
if(!ret) {
ret = @"";
}
}
}
return ret;
}

View file

@ -7,12 +7,11 @@
*
*/
enum
{
kCogStatusPaused = 0,
kCogStatusStopped,
kCogStatusPlaying,
// kCogStatusEndOfFile,
// kCogStatusEndOfPlaylist,
// kCogStatusPlaybackEnded
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger, CogStatus) {
CogStatusStopped = 0,
CogStatusPaused,
CogStatusPlaying,
CogStatusStopping,
};

View file

@ -22,7 +22,7 @@
#include <AudioToolbox/AudioFile.h>
BOOL hostIsBigEndian()
static BOOL hostIsBigEndian(void)
{
#ifdef __BIG_ENDIAN__
return YES;
@ -42,22 +42,28 @@ AudioStreamBasicDescription propertiesToASBD(NSDictionary *properties)
asbd.mBitsPerChannel = [[properties objectForKey:@"bitsPerSample"] intValue];
asbd.mChannelsPerFrame = [[properties objectForKey:@"channels"] intValue];;
asbd.mBytesPerFrame = (asbd.mBitsPerChannel/8)*asbd.mChannelsPerFrame;
asbd.mBytesPerFrame = ((asbd.mBitsPerChannel+7)/8)*asbd.mChannelsPerFrame;
asbd.mFramesPerPacket = 1;
asbd.mBytesPerPacket = asbd.mBytesPerFrame * asbd.mFramesPerPacket;
asbd.mReserved = 0;
BOOL isFloat = [[properties objectForKey:@"floatingPoint"] boolValue];
if ([[properties objectForKey:@"endian"] isEqualToString:@"big"] || ([[properties objectForKey:@"endian"] isEqualToString:@"host"] && hostIsBigEndian() ))
{
asbd.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
asbd.mFormatFlags |= kLinearPCMFormatFlagIsAlignedHigh;
}
if ([[properties objectForKey:@"unsigned"] boolValue] == NO) {
if(isFloat == NO && [[properties objectForKey:@"unSigned"] boolValue] == NO) {
asbd.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
}
if (isFloat) {
asbd.mFormatFlags |= kLinearPCMFormatFlagIsFloat | kAudioFormatFlagIsPacked;
}
return asbd;
}

View file

@ -1,88 +0,0 @@
//
// VirtualRingBuffer.h
// PlayBufferedSoundFile
//
/*
Copyright (c) 2002, Kurt Revis. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Snoize nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//
// VirtualRingBuffer implements a classic ring buffer (or circular buffer), with a couple of twists.
//
// * It allows reads and writes to happen in different threads, with no explicit locking,
// so readers and writers will never block. This is useful if either thread uses the
// time-constraint scheduling policy, since it is bad for such threads to block for
// indefinite amounts of time.
//
// * It uses a virtual memory trick to allow the client to read or write using just one
// operation, even if the data involved wraps around the end of the buffer. We allocate
// our buffer normally, and then place a VM region immediately after it in the address
// space which maps back to the "real" buffer. So reads and writes into both sections
// are transparently translated into the same physical memory.
// This makes the API much simpler to use, and saves us from doing some math to
// calculate the wraparound points.
// The tradeoff is that we use twice as much address space for the buffer than we would
// otherwise. Address space is not typically constrained for most applications, though,
// so this isn't a big problem.
// The idea for this trick came from <http://phil.ipal.org/freeware/vrb/> (via sweetcode.org),
// although none of that code is used here. (We use the Mach VM API directly.)
//
// Threading note:
// It is expected that this object will be shared between exactly two threads; one will
// always read and the other will always write. In that situation, the implementation is
// thread-safe, and this object will never block or yield.
// It will also work in one thread, of course (although I don't know why you'd bother).
// However, if you have multiple reader or writer threads, all bets are off!
#import <Foundation/Foundation.h>
@interface VirtualRingBuffer : NSObject
{
void *buffer;
void *bufferEnd;
UInt32 bufferLength;
// buffer is the start of the ring buffer's address space.
// bufferEnd is the end of the "real" buffer (always buffer + bufferLength).
// Note that the "virtual" portion of the buffer extends from bufferEnd to bufferEnd+bufferLength.
void *readPointer;
void *writePointer;
}
- (id)initWithLength:(UInt32)length;
// Note: The specified length will be rounded up to an integral number of VM pages.
// Empties the buffer. It is NOT safe to do this while anyone is reading from or writing to the buffer.
- (void)empty;
// Checks if the buffer is empty or not. This is safe in any thread.
- (BOOL)isEmpty;
- (UInt32)bufferLength;
// Read operations:
// The reading thread must call this method first.
- (UInt32)lengthAvailableToReadReturningPointer:(void **)returnedReadPointer;
// Iff a value > 0 is returned, the reading thread may go on to read that much data from the returned pointer.
// Afterwards, the reading thread must call didReadLength:.
- (void)didReadLength:(UInt32)length;
// Write operations:
// The writing thread must call this method first.
- (UInt32)lengthAvailableToWriteReturningPointer:(void **)returnedWritePointer;
// Iff a value > 0 is returned, the writing thread may then write that much data into the returned pointer.
// Afterwards, the writing thread must call didWriteLength:.
- (void)didWriteLength:(UInt32)length;
@end

View file

@ -1,309 +0,0 @@
//
// VirtualRingBuffer.m
// PlayBufferedSoundFile
//
/*
Copyright (c) 2002, Kurt Revis. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Snoize nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "VirtualRingBuffer.h"
#include <mach/mach.h>
#include <mach/mach_error.h>
@implementation VirtualRingBuffer
static void *allocateVirtualBuffer(UInt32 bufferLength);
static void deallocateVirtualBuffer(void *buffer, UInt32 bufferLength);
- (id)initWithLength:(UInt32)length
{
if (![super init])
return nil;
// We need to allocate entire VM pages, so round the specified length up to the next page if necessary.
bufferLength = round_page(length);
buffer = allocateVirtualBuffer(bufferLength);
if (buffer) {
bufferEnd = buffer + bufferLength;
} else {
[self release];
return nil;
}
readPointer = NULL;
writePointer = NULL;
return self;
}
- (void)dealloc
{
if (buffer)
deallocateVirtualBuffer(buffer, bufferLength);
[super dealloc];
}
- (void)empty
{
// Assumption:
// No one is reading or writing from the buffer, in any thread, when this method is called.
readPointer = NULL;
writePointer = NULL;
}
- (BOOL)isEmpty
{
return (readPointer != NULL && writePointer != NULL);
}
- (UInt32)bufferLength
{
return bufferLength;
}
//
// Theory of operation:
//
// This class keeps a pointer to the next byte to be read (readPointer) and a pointer to the next byte to be written (writePointer).
// readPointer is only advanced in the reading thread (except for one case: when the buffer first has data written to it).
// writePointer is only advanced in the writing thread.
//
// Since loading and storing word length data is atomic, each pointer can safely be modified in one thread while the other thread
// uses it, IF each thread is careful to make a local copy of the "opposite" pointer when necessary.
//
//
// Read operations
//
- (UInt32)lengthAvailableToReadReturningPointer:(void **)returnedReadPointer
{
// Assumptions:
// returnedReadPointer != NULL
UInt32 length;
// Read this pointer exactly once, so we're safe in case it is changed in another thread
void *localWritePointer = writePointer;
// Depending on out-of-order execution and memory storage, either one of these may be NULL when the buffer is empty. So we must check both.
if (!readPointer || !localWritePointer) {
// The buffer is empty
length = 0;
} else if (localWritePointer > readPointer) {
// Write is ahead of read in the buffer
length = localWritePointer - readPointer;
} else {
// Write has wrapped around past read, OR write == read (the buffer is full)
length = bufferLength - (readPointer - localWritePointer);
}
*returnedReadPointer = readPointer;
return length;
}
- (void)didReadLength:(UInt32)length
{
// Assumptions:
// [self lengthAvailableToReadReturningPointer:] currently returns a value >= length
// length > 0
void *newReadPointer;
newReadPointer = readPointer + length;
if (newReadPointer >= bufferEnd)
newReadPointer -= bufferLength;
if (newReadPointer == writePointer) {
// We just read the last data out of the buffer, so it is now empty.
newReadPointer = NULL;
}
// Store the new read pointer. This is the only place this happens in the read thread.
readPointer = newReadPointer;
}
//
// Write operations
//
- (UInt32)lengthAvailableToWriteReturningPointer:(void **)returnedWritePointer
{
// Assumptions:
// returnedWritePointer != NULL
UInt32 length;
// Read this pointer exactly once, so we're safe in case it is changed in another thread
void *localReadPointer = readPointer;
// Either one of these may be NULL when the buffer is empty. So we must check both.
if (!localReadPointer || !writePointer) {
// The buffer is empty. Set it up to be written into.
// This is one of the two places the write pointer can change; both are in the write thread.
writePointer = buffer;
length = bufferLength;
} else if (writePointer <= localReadPointer) {
// Write is before read in the buffer, OR write == read (meaning that the buffer is full).
length = localReadPointer - writePointer;
} else {
// Write is behind read in the buffer. The available space wraps around.
length = (bufferEnd - writePointer) + (localReadPointer - buffer);
}
*returnedWritePointer = writePointer;
return length;
}
- (void)didWriteLength:(UInt32)length
{
// Assumptions:
// [self lengthAvailableToWriteReturningPointer:] currently returns a value >= length
// length > 0
void *oldWritePointer = writePointer;
void *newWritePointer;
// Advance the write pointer, wrapping around if necessary.
newWritePointer = writePointer + length;
if (newWritePointer >= bufferEnd)
newWritePointer -= bufferLength;
// This is one of the two places the write pointer can change; both are in the write thread.
writePointer = newWritePointer;
// Also, if the read pointer is NULL, then we just wrote into a previously empty buffer, so set the read pointer.
// This is the only place the read pointer is changed in the write thread.
// The read thread should never change the read pointer when it is NULL, so this is safe.
if (!readPointer)
readPointer = oldWritePointer;
}
@end
void *allocateVirtualBuffer(UInt32 bufferLength)
{
kern_return_t error;
vm_address_t originalAddress = (vm_address_t)NULL;
vm_address_t realAddress = (vm_address_t)NULL;
mach_port_t memoryEntry;
vm_size_t memoryEntryLength;
vm_address_t virtualAddress = (vm_address_t)NULL;
// We want to find where we can get 2 * bufferLength bytes of contiguous address space.
// So let's just allocate that space, remember its address, and deallocate it.
// (This doesn't actually have to touch all of that memory so it's not terribly expensive.)
error = vm_allocate(mach_task_self(), &originalAddress, 2 * bufferLength, TRUE);
if (error) {
#if DEBUG
mach_error("vm_allocate initial chunk", error);
#endif
return NULL;
}
error = vm_deallocate(mach_task_self(), originalAddress, 2 * bufferLength);
if (error) {
#if DEBUG
mach_error("vm_deallocate initial chunk", error);
#endif
return NULL;
}
// Then allocate a "real" block of memory at the same address, but with the normal bufferLength.
realAddress = originalAddress;
error = vm_allocate(mach_task_self(), &realAddress, bufferLength, FALSE);
if (error) {
#if DEBUG
mach_error("vm_allocate real chunk", error);
#endif
return NULL;
}
if (realAddress != originalAddress) {
#if DEBUG
NSLog(@"allocateVirtualBuffer: vm_allocate 2nd time didn't return same address (%p vs %p)", originalAddress, realAddress);
#endif
goto errorReturn;
}
// Then make a memory entry for the area we just allocated.
memoryEntryLength = bufferLength;
error = mach_make_memory_entry(mach_task_self(), &memoryEntryLength, realAddress, VM_PROT_READ | VM_PROT_WRITE, &memoryEntry, (vm_address_t)NULL);
if (error) {
#if DEBUG
mach_error("mach_make_memory_entry", error);
#endif
goto errorReturn;
}
if (!memoryEntry) {
#if DEBUG
NSLog(@"mach_make_memory_entry: returned memoryEntry of NULL");
#endif
goto errorReturn;
}
if (memoryEntryLength != bufferLength) {
#if DEBUG
NSLog(@"mach_make_memory_entry: size changed (from %0x to %0x)", bufferLength, memoryEntryLength);
#endif
goto errorReturn;
}
// And map the area immediately after the first block, with length bufferLength, to that memory entry.
virtualAddress = realAddress + bufferLength;
error = vm_map(mach_task_self(), &virtualAddress, bufferLength, 0, FALSE, memoryEntry, 0, FALSE, VM_PROT_READ | VM_PROT_WRITE, VM_PROT_READ | VM_PROT_WRITE, VM_INHERIT_DEFAULT);
if (error) {
#if DEBUG
mach_error("vm_map", error);
#endif
// TODO Retry from the beginning, instead of failing completely. There is a tiny (but > 0) probability that someone
// will allocate this space out from under us.
virtualAddress = (vm_address_t)NULL;
goto errorReturn;
}
if (virtualAddress != realAddress + bufferLength) {
#if DEBUG
NSLog(@"vm_map: didn't return correct address (%p vs %p)", realAddress + bufferLength, virtualAddress);
#endif
goto errorReturn;
}
// Success!
return (void *)realAddress;
errorReturn:
if (realAddress)
vm_deallocate(mach_task_self(), realAddress, bufferLength);
if (virtualAddress)
vm_deallocate(mach_task_self(), virtualAddress, bufferLength);
return NULL;
}
void deallocateVirtualBuffer(void *buffer, UInt32 bufferLength)
{
kern_return_t error;
// We can conveniently deallocate both the vm_allocated memory and
// the vm_mapped region at the same time.
error = vm_deallocate(mach_task_self(), (vm_address_t)buffer, bufferLength * 2);
if (error) {
#if DEBUG
mach_error("vm_deallocate in dealloc", error);
#endif
}
}

40
Audio/ThirdParty/deadbeef/fft.h vendored Normal file
View file

@ -0,0 +1,40 @@
/*
DeaDBeeF -- the music player
Copyright (C) 2009-2021 Alexey Yakovenko and other contributors
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef FFT_H
#define FFT_H
#ifdef __cplusplus
extern "C" {
}
#endif
void fft_calculate(const float *data, float *freq, int fft_size);
void fft_free(void);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,106 @@
/*
DeaDBeeF -- the music player
Copyright (C) 2009-2021 Alexey Yakovenko and other contributors
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "fft.h"
#include <Accelerate/Accelerate.h>
static int _fft_size;
static float *_input_real;
static float *_input_imaginary;
static float *_output_real;
static float *_output_imaginary;
static float *_hamming;
static float *_sq_mags;
static vDSP_DFT_Setup _dft_setup;
// Apparently _mm_malloc is Intel-only on newer macOS targets, so use supported posix_memalign
static void *_memalign_calloc(size_t count, size_t size, size_t align) {
size *= count;
void *ret = NULL;
if(posix_memalign(&ret, align, size) != 0) {
return NULL;
}
bzero(ret, size);
return ret;
}
static void
_init_buffers(int fft_size) {
if(fft_size != _fft_size) {
fft_free();
_input_real = _memalign_calloc(fft_size * 2, sizeof(float), 16);
_input_imaginary = _memalign_calloc(fft_size * 2, sizeof(float), 16);
_hamming = _memalign_calloc(fft_size * 2, sizeof(float), 16);
_sq_mags = _memalign_calloc(fft_size, sizeof(float), 16);
_output_real = _memalign_calloc(fft_size * 2 + 1, sizeof(float), 16);
_output_imaginary = _memalign_calloc(fft_size * 2 + 1, sizeof(float), 16);
_dft_setup = vDSP_DFT_zop_CreateSetup(NULL, fft_size * 2, FFT_FORWARD);
vDSP_hamm_window(_hamming, fft_size * 2, 0);
_fft_size = fft_size;
}
}
void fft_calculate(const float *data, float *freq, int fft_size) {
int dft_size = fft_size * 2;
_init_buffers(fft_size);
vDSP_vmul(data, 1, _hamming, 1, _input_real, 1, dft_size);
vDSP_DFT_Execute(_dft_setup, _input_real, _input_imaginary, _output_real, _output_imaginary);
DSPSplitComplex split_complex = {
.realp = _output_real,
.imagp = _output_imaginary
};
vDSP_zvmags(&split_complex, 1, _sq_mags, 1, fft_size);
int sq_count = fft_size;
vvsqrtf(_sq_mags, _sq_mags, &sq_count);
float mult = 2.f / fft_size;
vDSP_vsmul(_sq_mags, 1, &mult, freq, 1, fft_size);
}
void fft_free(void) {
free(_input_real);
free(_input_imaginary);
free(_hamming);
free(_sq_mags);
free(_output_real);
free(_output_imaginary);
if(_dft_setup != NULL) {
vDSP_DFT_DestroySetup(_dft_setup);
}
_input_real = NULL;
_input_imaginary = NULL;
_hamming = NULL;
_sq_mags = NULL;
_dft_setup = NULL;
_output_real = NULL;
_output_imaginary = NULL;
}

Some files were not shown because too many files have changed in this diff Show more