[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>
lastfm
Christopher Snowhill 2022-06-24 02:46:23 -07:00
parent 6d772562ca
commit 2e45deb8d3
9 changed files with 551 additions and 68 deletions

3
.gitmodules vendored
View File

@ -19,3 +19,6 @@
[submodule "Frameworks/libsidplayfp/sidplayfp"]
path = Frameworks/libsidplayfp/sidplayfp
url = https://github.com/kode54/libsidplayfp.git
[submodule "Audio/ThirdParty/r8brain-free-src"]
path = Audio/ThirdParty/r8brain-free-src
url = https://github.com/kode54/r8brain-free-src

View File

@ -452,10 +452,12 @@
[self notifyPlaybackStopped:nil];
return NO;
return YES;
}
return YES;
[output setEndOfStream:NO];
return NO;
}
- (void)endOfInputPlayed {
@ -465,7 +467,6 @@
// - the buffer chain for the next entry is the first item in chainQueue
[self notifyStreamChanged:[bufferChain userInfo]];
[output setEndOfStream:NO];
}
- (BOOL)chainQueueHasTracks {

View File

@ -41,6 +41,35 @@
17F94DD50B8D0F7000A34E87 /* PluginController.h in Headers */ = {isa = PBXBuildFile; fileRef = 17F94DD30B8D0F7000A34E87 /* PluginController.h */; settings = {ATTRIBUTES = (Public, ); }; };
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, ); }; };
831A4FDC2865A7DC0049CFE4 /* CDSPProcessor.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4F9D2865A7DC0049CFE4 /* CDSPProcessor.h */; };
831A4FDD2865A7DC0049CFE4 /* CDSPRealFFT.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4F9E2865A7DC0049CFE4 /* CDSPRealFFT.h */; };
831A4FDE2865A7DC0049CFE4 /* pffft_double.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4FA02865A7DC0049CFE4 /* pffft_double.h */; };
831A4FDF2865A7DC0049CFE4 /* pf_neon_double_from_avx.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4FA22865A7DC0049CFE4 /* pf_neon_double_from_avx.h */; };
831A4FE02865A7DC0049CFE4 /* pf_double.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4FA32865A7DC0049CFE4 /* pf_double.h */; };
831A4FE12865A7DC0049CFE4 /* pf_neon_double.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4FA42865A7DC0049CFE4 /* pf_neon_double.h */; };
831A4FE22865A7DC0049CFE4 /* pf_sse2_double.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4FA52865A7DC0049CFE4 /* pf_sse2_double.h */; };
831A4FE32865A7DC0049CFE4 /* pf_avx_double.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4FA62865A7DC0049CFE4 /* pf_avx_double.h */; };
831A4FE42865A7DC0049CFE4 /* pf_scalar_double.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4FA72865A7DC0049CFE4 /* pf_scalar_double.h */; };
831A4FE52865A7DC0049CFE4 /* pffft_priv_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4FA82865A7DC0049CFE4 /* pffft_priv_impl.h */; };
831A4FE62865A7DC0049CFE4 /* pffft_double.c in Sources */ = {isa = PBXBuildFile; fileRef = 831A4FA92865A7DC0049CFE4 /* pffft_double.c */; };
831A4FF22865A7DC0049CFE4 /* CDSPHBUpsampler.inc in Sources */ = {isa = PBXBuildFile; fileRef = 831A4FB72865A7DC0049CFE4 /* CDSPHBUpsampler.inc */; };
831A4FF32865A7DC0049CFE4 /* r8butil.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4FB82865A7DC0049CFE4 /* r8butil.h */; };
831A4FF52865A7DC0049CFE4 /* r8bbase.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4FBA2865A7DC0049CFE4 /* r8bbase.h */; };
831A4FFE2865A7DC0049CFE4 /* CDSPSincFilterGen.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4FC42865A7DC0049CFE4 /* CDSPSincFilterGen.h */; };
831A50072865A7DC0049CFE4 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 831A4FD02865A7DC0049CFE4 /* LICENSE */; };
831A50082865A7DC0049CFE4 /* CDSPResampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4FD12865A7DC0049CFE4 /* CDSPResampler.h */; };
831A50092865A7DC0049CFE4 /* CDSPHBUpsampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4FD22865A7DC0049CFE4 /* CDSPHBUpsampler.h */; };
831A500B2865A7DC0049CFE4 /* CDSPBlockConvolver.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4FD42865A7DC0049CFE4 /* CDSPBlockConvolver.h */; };
831A500C2865A7DC0049CFE4 /* fft4g.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4FD52865A7DC0049CFE4 /* fft4g.h */; };
831A500D2865A7DC0049CFE4 /* CDSPHBDownsampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4FD62865A7DC0049CFE4 /* CDSPHBDownsampler.h */; };
831A500E2865A7DC0049CFE4 /* r8bconf.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4FD72865A7DC0049CFE4 /* r8bconf.h */; };
831A500F2865A7DC0049CFE4 /* CDSPFracInterpolator.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4FD82865A7DC0049CFE4 /* CDSPFracInterpolator.h */; };
831A50102865A7DC0049CFE4 /* CDSPFIRFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4FD92865A7DC0049CFE4 /* CDSPFIRFilter.h */; };
831A50112865A7DC0049CFE4 /* r8bbase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 831A4FDA2865A7DC0049CFE4 /* r8bbase.cpp */; };
831A50122865A7DC0049CFE4 /* pffft.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A4FDB2865A7DC0049CFE4 /* pffft.h */; };
831A50142865A7FD0049CFE4 /* r8bstate.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 831A50132865A7FD0049CFE4 /* r8bstate.hpp */; };
831A50162865A8800049CFE4 /* r8bstate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 831A50152865A8800049CFE4 /* r8bstate.cpp */; };
831A50182865A8B30049CFE4 /* r8bstate.h in Headers */ = {isa = PBXBuildFile; fileRef = 831A50172865A8B30049CFE4 /* r8bstate.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 */; };
@ -140,6 +169,35 @@
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>"; };
831A4F9D2865A7DC0049CFE4 /* CDSPProcessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDSPProcessor.h; sourceTree = "<group>"; };
831A4F9E2865A7DC0049CFE4 /* CDSPRealFFT.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDSPRealFFT.h; sourceTree = "<group>"; };
831A4FA02865A7DC0049CFE4 /* pffft_double.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pffft_double.h; sourceTree = "<group>"; };
831A4FA22865A7DC0049CFE4 /* pf_neon_double_from_avx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pf_neon_double_from_avx.h; sourceTree = "<group>"; };
831A4FA32865A7DC0049CFE4 /* pf_double.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pf_double.h; sourceTree = "<group>"; };
831A4FA42865A7DC0049CFE4 /* pf_neon_double.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pf_neon_double.h; sourceTree = "<group>"; };
831A4FA52865A7DC0049CFE4 /* pf_sse2_double.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pf_sse2_double.h; sourceTree = "<group>"; };
831A4FA62865A7DC0049CFE4 /* pf_avx_double.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pf_avx_double.h; sourceTree = "<group>"; };
831A4FA72865A7DC0049CFE4 /* pf_scalar_double.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pf_scalar_double.h; sourceTree = "<group>"; };
831A4FA82865A7DC0049CFE4 /* pffft_priv_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pffft_priv_impl.h; sourceTree = "<group>"; };
831A4FA92865A7DC0049CFE4 /* pffft_double.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pffft_double.c; sourceTree = "<group>"; };
831A4FB72865A7DC0049CFE4 /* CDSPHBUpsampler.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = CDSPHBUpsampler.inc; sourceTree = "<group>"; };
831A4FB82865A7DC0049CFE4 /* r8butil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = r8butil.h; sourceTree = "<group>"; };
831A4FBA2865A7DC0049CFE4 /* r8bbase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = r8bbase.h; sourceTree = "<group>"; };
831A4FC42865A7DC0049CFE4 /* CDSPSincFilterGen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDSPSincFilterGen.h; sourceTree = "<group>"; };
831A4FD02865A7DC0049CFE4 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
831A4FD12865A7DC0049CFE4 /* CDSPResampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDSPResampler.h; sourceTree = "<group>"; };
831A4FD22865A7DC0049CFE4 /* CDSPHBUpsampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDSPHBUpsampler.h; sourceTree = "<group>"; };
831A4FD42865A7DC0049CFE4 /* CDSPBlockConvolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDSPBlockConvolver.h; sourceTree = "<group>"; };
831A4FD52865A7DC0049CFE4 /* fft4g.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fft4g.h; sourceTree = "<group>"; };
831A4FD62865A7DC0049CFE4 /* CDSPHBDownsampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDSPHBDownsampler.h; sourceTree = "<group>"; };
831A4FD72865A7DC0049CFE4 /* r8bconf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = r8bconf.h; sourceTree = "<group>"; };
831A4FD82865A7DC0049CFE4 /* CDSPFracInterpolator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDSPFracInterpolator.h; sourceTree = "<group>"; };
831A4FD92865A7DC0049CFE4 /* CDSPFIRFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDSPFIRFilter.h; sourceTree = "<group>"; };
831A4FDA2865A7DC0049CFE4 /* r8bbase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = r8bbase.cpp; sourceTree = "<group>"; };
831A4FDB2865A7DC0049CFE4 /* pffft.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pffft.h; sourceTree = "<group>"; };
831A50132865A7FD0049CFE4 /* r8bstate.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = r8bstate.hpp; sourceTree = "<group>"; };
831A50152865A8800049CFE4 /* r8bstate.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = r8bstate.cpp; sourceTree = "<group>"; };
831A50172865A8B30049CFE4 /* r8bstate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = r8bstate.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>"; };
@ -332,6 +390,10 @@
17D21CD80B8BE5B400D1EBDE /* ThirdParty */ = {
isa = PBXGroup;
children = (
831A50152865A8800049CFE4 /* r8bstate.cpp */,
831A50172865A8B30049CFE4 /* r8bstate.h */,
831A50132865A7FD0049CFE4 /* r8bstate.hpp */,
831A4F9C2865A7DC0049CFE4 /* r8brain-free-src */,
8377C64A27B8C51500E8BC0F /* deadbeef */,
835C88AE279811A500E28EAE /* hdcd */,
17D21DC40B8BE79700D1EBDE /* CoreAudioUtils */,
@ -377,6 +439,55 @@
name = "Other Sources";
sourceTree = "<group>";
};
831A4F9C2865A7DC0049CFE4 /* r8brain-free-src */ = {
isa = PBXGroup;
children = (
831A4F9D2865A7DC0049CFE4 /* CDSPProcessor.h */,
831A4F9E2865A7DC0049CFE4 /* CDSPRealFFT.h */,
831A4F9F2865A7DC0049CFE4 /* pffft_double */,
831A4FB72865A7DC0049CFE4 /* CDSPHBUpsampler.inc */,
831A4FB82865A7DC0049CFE4 /* r8butil.h */,
831A4FBA2865A7DC0049CFE4 /* r8bbase.h */,
831A4FC42865A7DC0049CFE4 /* CDSPSincFilterGen.h */,
831A4FD02865A7DC0049CFE4 /* LICENSE */,
831A4FD12865A7DC0049CFE4 /* CDSPResampler.h */,
831A4FD22865A7DC0049CFE4 /* CDSPHBUpsampler.h */,
831A4FD42865A7DC0049CFE4 /* CDSPBlockConvolver.h */,
831A4FD52865A7DC0049CFE4 /* fft4g.h */,
831A4FD62865A7DC0049CFE4 /* CDSPHBDownsampler.h */,
831A4FD72865A7DC0049CFE4 /* r8bconf.h */,
831A4FD82865A7DC0049CFE4 /* CDSPFracInterpolator.h */,
831A4FD92865A7DC0049CFE4 /* CDSPFIRFilter.h */,
831A4FDA2865A7DC0049CFE4 /* r8bbase.cpp */,
831A4FDB2865A7DC0049CFE4 /* pffft.h */,
);
path = "r8brain-free-src";
sourceTree = "<group>";
};
831A4F9F2865A7DC0049CFE4 /* pffft_double */ = {
isa = PBXGroup;
children = (
831A4FA02865A7DC0049CFE4 /* pffft_double.h */,
831A4FA12865A7DC0049CFE4 /* simd */,
831A4FA82865A7DC0049CFE4 /* pffft_priv_impl.h */,
831A4FA92865A7DC0049CFE4 /* pffft_double.c */,
);
path = pffft_double;
sourceTree = "<group>";
};
831A4FA12865A7DC0049CFE4 /* simd */ = {
isa = PBXGroup;
children = (
831A4FA22865A7DC0049CFE4 /* pf_neon_double_from_avx.h */,
831A4FA32865A7DC0049CFE4 /* pf_double.h */,
831A4FA42865A7DC0049CFE4 /* pf_neon_double.h */,
831A4FA52865A7DC0049CFE4 /* pf_sse2_double.h */,
831A4FA62865A7DC0049CFE4 /* pf_avx_double.h */,
831A4FA72865A7DC0049CFE4 /* pf_scalar_double.h */,
);
path = simd;
sourceTree = "<group>";
};
835C88AE279811A500E28EAE /* hdcd */ = {
isa = PBXGroup;
children = (
@ -421,30 +532,54 @@
buildActionMask = 2147483647;
files = (
17D21CA10B8BE4BA00D1EBDE /* BufferChain.h in Headers */,
831A4FE02865A7DC0049CFE4 /* pf_double.h in Headers */,
831A50142865A7FD0049CFE4 /* r8bstate.hpp in Headers */,
17D21CA50B8BE4BA00D1EBDE /* InputNode.h in Headers */,
17D21CA70B8BE4BA00D1EBDE /* Node.h in Headers */,
8399CF2C27B5D1D5008751F1 /* NSDictionary+Merge.h in Headers */,
831A4FF32865A7DC0049CFE4 /* r8butil.h in Headers */,
17D21CA90B8BE4BA00D1EBDE /* OutputNode.h in Headers */,
8328995427CB511000D7F028 /* RedundantPlaylistDataStore.h in Headers */,
831A50102865A7DC0049CFE4 /* CDSPFIRFilter.h in Headers */,
831A4FFE2865A7DC0049CFE4 /* CDSPSincFilterGen.h in Headers */,
831A4FF52865A7DC0049CFE4 /* r8bbase.h in Headers */,
831A50082865A7DC0049CFE4 /* CDSPResampler.h in Headers */,
17D21CC50B8BE4BA00D1EBDE /* OutputAVFoundation.h in Headers */,
83504165286447DA006B32CC /* Downmix.h in Headers */,
831A4FDE2865A7DC0049CFE4 /* pffft_double.h in Headers */,
831A4FE12865A7DC0049CFE4 /* pf_neon_double.h in Headers */,
17D21CC70B8BE4BA00D1EBDE /* Status.h in Headers */,
17D21CF30B8BE5EF00D1EBDE /* Semaphore.h in Headers */,
17D21DC70B8BE79700D1EBDE /* CoreAudioUtils.h in Headers */,
17D21EBD0B8BF44000D1EBDE /* AudioPlayer.h in Headers */,
831A50182865A8B30049CFE4 /* r8bstate.h in Headers */,
831A4FE52865A7DC0049CFE4 /* pffft_priv_impl.h in Headers */,
831A4FE42865A7DC0049CFE4 /* pf_scalar_double.h in Headers */,
831A500D2865A7DC0049CFE4 /* CDSPHBDownsampler.h in Headers */,
831A500C2865A7DC0049CFE4 /* fft4g.h in Headers */,
8377C65227B8CAD100E8BC0F /* VisualizationController.h in Headers */,
834FD4F027AF93680063BC83 /* ChunkList.h in Headers */,
17F94DD50B8D0F7000A34E87 /* PluginController.h in Headers */,
831A50122865A7DC0049CFE4 /* pffft.h in Headers */,
831A4FDC2865A7DC0049CFE4 /* CDSPProcessor.h in Headers */,
831A4FDD2865A7DC0049CFE4 /* CDSPRealFFT.h in Headers */,
17F94DDD0B8D101100A34E87 /* Plugin.h in Headers */,
8328995727CB51B700D7F028 /* SHA256Digest.h in Headers */,
834FD4EB27AF8F380063BC83 /* AudioChunk.h in Headers */,
17A2D3C50B8D1D37000778C4 /* AudioDecoder.h in Headers */,
831A50092865A7DC0049CFE4 /* CDSPHBUpsampler.h in Headers */,
831A500E2865A7DC0049CFE4 /* r8bconf.h in Headers */,
8347C7412796C58800FA8A7D /* NSFileHandle+CreateFile.h in Headers */,
17C940230B900909008627D6 /* AudioMetadataReader.h in Headers */,
831A500F2865A7DC0049CFE4 /* CDSPFracInterpolator.h in Headers */,
831A4FE22865A7DC0049CFE4 /* pf_sse2_double.h in Headers */,
839065F32853338700636FBB /* dsd2float.h in Headers */,
17B619300B909BC300BC003F /* AudioPropertiesReader.h in Headers */,
831A4FDF2865A7DC0049CFE4 /* pf_neon_double_from_avx.h in Headers */,
831A4FE32865A7DC0049CFE4 /* pf_avx_double.h in Headers */,
839366671815923C006DD712 /* CogPluginMulti.h in Headers */,
17ADB13C0B97926D00257CA2 /* AudioSource.h in Headers */,
831A500B2865A7DC0049CFE4 /* CDSPBlockConvolver.h in Headers */,
835C88B1279811A500E28EAE /* hdcd_decode2.h in Headers */,
8EC1225F0B993BD500C5B3AD /* ConverterNode.h in Headers */,
8384912718080FF100E7332D /* Logging.h in Headers */,
@ -516,6 +651,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
831A50072865A7DC0049CFE4 /* LICENSE in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -528,8 +664,10 @@
files = (
17D21CA20B8BE4BA00D1EBDE /* BufferChain.m in Sources */,
17D21CA60B8BE4BA00D1EBDE /* InputNode.m in Sources */,
831A50112865A7DC0049CFE4 /* r8bbase.cpp in Sources */,
83504166286447DA006B32CC /* Downmix.m in Sources */,
8399CF2D27B5D1D5008751F1 /* NSDictionary+Merge.m in Sources */,
831A50162865A8800049CFE4 /* r8bstate.cpp in Sources */,
17D21CA80B8BE4BA00D1EBDE /* Node.m in Sources */,
17D21CAA0B8BE4BA00D1EBDE /* OutputNode.m in Sources */,
8377C65327B8CAD100E8BC0F /* VisualizationController.m in Sources */,
@ -545,6 +683,8 @@
839366681815923C006DD712 /* CogPluginMulti.m in Sources */,
17D21EBE0B8BF44000D1EBDE /* AudioPlayer.m in Sources */,
17F94DD60B8D0F7000A34E87 /* PluginController.mm in Sources */,
831A4FE62865A7DC0049CFE4 /* pffft_double.c in Sources */,
831A4FF22865A7DC0049CFE4 /* CDSPHBUpsampler.inc in Sources */,
17A2D3C60B8D1D37000778C4 /* AudioDecoder.m in Sources */,
8328995827CB51B700D7F028 /* SHA256Digest.m in Sources */,
17C940240B900909008627D6 /* AudioMetadataReader.m in Sources */,
@ -578,10 +718,17 @@
GCC_PREFIX_HEADER = CogAudio_Prefix.pch;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"R8B_EXTFFT=1",
"R8B_PFFFT_DOUBLE=1",
);
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "@executable_path/../Frameworks";
LD_RUNPATH_SEARCH_PATHS = "@loader_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/ThirdParty/r8brain-free-src/DLL/Win64",
"$(PROJECT_DIR)/ThirdParty/r8brain-free-src/DLL/Win32",
);
OTHER_LDFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = org.cogx.cogaudio;
PRODUCT_NAME = CogAudio;
@ -606,10 +753,17 @@
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = CogAudio_Prefix.pch;
GCC_PREPROCESSOR_DEFINITIONS = (
"R8B_EXTFFT=1",
"R8B_PFFFT_DOUBLE=1",
);
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "@executable_path/../Frameworks";
LD_RUNPATH_SEARCH_PATHS = "@loader_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/ThirdParty/r8brain-free-src/DLL/Win64",
"$(PROJECT_DIR)/ThirdParty/r8brain-free-src/DLL/Win32",
);
OTHER_LDFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = org.cogx.cogaudio;
PRODUCT_NAME = CogAudio;

View File

@ -36,6 +36,9 @@ using std::atomic_long;
@interface OutputAVFoundation : NSObject {
OutputNode *outputController;
BOOL r8bFlushing, r8bFlushed, r8bDone;
void *r8bstate, *r8bold;
BOOL stopInvoked;
BOOL running;
BOOL stopping;
@ -64,6 +67,7 @@ using std::atomic_long;
AudioDeviceID outputDeviceID;
AudioStreamBasicDescription streamFormat; // stream format last seen in render callback
AudioStreamBasicDescription newFormat; // in case of resampler flush
AudioStreamBasicDescription visFormat; // Mono format for vis

View File

@ -17,6 +17,8 @@
#import <Accelerate/Accelerate.h>
#import "r8bstate.h"
extern void scale_by_volume(float *buffer, size_t count, float volume);
static NSString *CogPlaybackDidBeginNotficiation = @"CogPlaybackDidBeginNotficiation";
@ -84,19 +86,41 @@ static OSStatus eqRenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioA
BOOL formatClipped = NO;
BOOL isSurround = format.mChannelsPerFrame > 2;
const double maxSampleRate = isSurround ? 352800.0 : 192000.0;
double srcRate = format.mSampleRate;
double dstRate = srcRate;
if(format.mSampleRate > maxSampleRate) {
format.mSampleRate = maxSampleRate;
dstRate = maxSampleRate;
formatClipped = YES;
}
if(!streamFormatStarted || config != streamChannelConfig || memcmp(&streamFormat, &format, sizeof(format)) != 0) {
if(!streamFormatStarted || config != streamChannelConfig || memcmp(&newFormat, &format, sizeof(format)) != 0) {
if(formatClipped) {
ALog(@"Sample rate clipped to no more than %f Hz!", maxSampleRate);
if(r8bstate) {
r8bold = r8bstate;
r8bstate = NULL;
r8bFlushing = YES;
}
r8bstate = r8bstate_new(format.mChannelsPerFrame, 1024, srcRate, dstRate);
} else if(r8bstate) {
r8bold = r8bstate;
r8bstate = NULL;
r8bFlushing = YES;
}
streamFormat = format;
newFormat = format;
streamChannelConfig = config;
streamFormatStarted = YES;
[self updateStreamFormat];
visFormat = format;
visFormat.mChannelsPerFrame = 1;
visFormat.mBytesPerFrame = visFormat.mChannelsPerFrame * (visFormat.mBitsPerChannel / 8);
visFormat.mBytesPerPacket = visFormat.mBytesPerFrame * visFormat.mFramesPerPacket;
downmixerForVis = [[DownmixProcessor alloc] initWithInputFormat:format inputConfig:config andOutputFormat:visFormat outputConfig:AudioConfigMono];
if(!r8bold) {
streamFormat = format;
[self updateStreamFormat];
}
}
chunkDuration = [chunk duration];
@ -107,13 +131,24 @@ static OSStatus eqRenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioA
amount:frameCount * format.mChannelsPerFrame
location:@"pre downmix"];
#endif
// It should be fine to request up to double, we'll only get downsampled
float outputBuffer[2048 * newFormat.mChannelsPerFrame];
const float *outputPtr = (const float *)[samples bytes];
if(r8bstate) {
size_t inDone = 0;
size_t framesDone = r8bstate_resample(r8bstate, outputPtr, frameCount, &inDone, &outputBuffer[0], 2048);
if(!framesDone) return 0;
frameCount = (int)framesDone;
outputPtr = &outputBuffer[0];
chunkDuration = frameCount / newFormat.mSampleRate;
}
[downmixerForVis process:[samples bytes]
[downmixerForVis process:outputPtr
frameCount:frameCount
output:visAudio];
visTabulated += frameCount;
cblas_scopy((int)(frameCount * streamFormat.mChannelsPerFrame), (const float *)[samples bytes], 1, &inputBuffer[0], 1);
cblas_scopy((int)(frameCount * newFormat.mChannelsPerFrame), outputPtr, 1, &inputBuffer[0], 1);
amountRead = frameCount;
} else {
return 0;
@ -141,9 +176,9 @@ static OSStatus eqRenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioA
volumeScale *= eqPreamp;
}
scale_by_volume(&inputBuffer[0], amountRead * streamFormat.mChannelsPerFrame, volumeScale);
scale_by_volume(&inputBuffer[0], amountRead * newFormat.mChannelsPerFrame, volumeScale);
[visController postSampleRate:streamFormat.mSampleRate];
[visController postSampleRate:newFormat.mSampleRate];
[visController postVisPCM:visAudio amount:visTabulated];
return amountRead;
@ -222,6 +257,14 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
return ret;
}
- (BOOL)processEndOfStream {
if([outputController endOfStream] == YES && [self signalEndOfStream:secondsLatency]) {
stopping = YES;
return YES;
}
return NO;
}
- (void)threadEntry:(id)arg {
running = YES;
started = NO;
@ -258,20 +301,8 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
[audioRenderer enqueueSampleBuffer:bufferRef];
} else {
if([outputController endOfStream] == YES && ![self signalEndOfStream:secondsLatency]) {
// Wait for output to catch up
CMTime currentTime;
[currentPtsLock lock];
currentTime = currentPts;
[currentPtsLock unlock];
CMTime timeToWait = CMTimeSubtract(outputPts, currentTime);
double secondsToWait = CMTimeGetSeconds(timeToWait);
if(secondsToWait > 0) {
usleep(secondsToWait * 1000000.0);
}
stopping = YES;
}
break;
// r8b will absorb some samples first
}
}
@ -498,11 +529,6 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
}
- (void)updateStreamFormat {
visFormat = streamFormat;
visFormat.mChannelsPerFrame = 1;
visFormat.mBytesPerFrame = visFormat.mChannelsPerFrame * (visFormat.mBitsPerChannel / 8);
visFormat.mBytesPerPacket = visFormat.mBytesPerFrame * visFormat.mFramesPerPacket;
/* Set the channel layout for the audio queue */
AudioChannelLayoutTag tag = 0;
AudioChannelLayout layout = { 0 };
@ -598,62 +624,114 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
status = CMBlockBufferCreateEmpty(kCFAllocatorDefault, 0, 0, &blockListBuffer);
if(status != noErr || !blockListBuffer) return 0;
int samplesRendered = [self renderInput];
int inputRendered;
do {
inputRendered = [self renderInput];
if([self processEndOfStream]) break;
} while(!inputRendered);
if(samplesRendered) {
if(eqEnabled) {
const int channels = streamFormat.mChannelsPerFrame;
if(channels > 0) {
const size_t channelsminusone = channels - 1;
uint8_t tempBuffer[sizeof(AudioBufferList) + sizeof(AudioBuffer) * channelsminusone];
AudioBufferList *ioData = (AudioBufferList *)&tempBuffer[0];
float tempBuffer[2048 * 32];
ioData->mNumberBuffers = channels;
for(size_t i = 0; i < channels; ++i) {
ioData->mBuffers[i].mData = &eqBuffer[1024 * i];
ioData->mBuffers[i].mDataByteSize = 1024 * sizeof(float);
ioData->mBuffers[i].mNumberChannels = 1;
}
int samplesRenderedTotal = 0;
status = AudioUnitRender(_eq, NULL, &timeStamp, 0, samplesRendered, ioData);
for(size_t i = 0; i < 2;) {
float *samplePtr;
int samplesRendered;
if(status != noErr) {
return 0;
}
timeStamp.mSampleTime += ((double)samplesRendered) / streamFormat.mSampleRate;
for(int i = 0; i < channels; ++i) {
cblas_scopy(samplesRendered, &eqBuffer[1024 * i], 1, &inputBuffer[i], channels);
}
if(i == 0) {
if(!r8bold) {
++i;
continue;
}
samplesRendered = r8bstate_flush(r8bold, &tempBuffer[0], 2048);
if(!samplesRendered) {
r8bstate_delete(r8bold);
r8bold = NULL;
r8bDone = YES;
}
samplePtr = &tempBuffer[0];
} else {
samplesRendered = inputRendered;
samplePtr = &inputBuffer[0];
if(r8bDone) {
r8bDone = NO;
streamFormat = newFormat;
[self updateStreamFormat];
}
}
CMBlockBufferRef blockBuffer = nil;
size_t dataByteSize = samplesRendered * sizeof(float) * streamFormat.mChannelsPerFrame;
if(samplesRendered) {
if(eqEnabled) {
const int channels = streamFormat.mChannelsPerFrame;
if(channels > 0) {
const size_t channelsminusone = channels - 1;
uint8_t tempBuffer[sizeof(AudioBufferList) + sizeof(AudioBuffer) * channelsminusone];
AudioBufferList *ioData = (AudioBufferList *)&tempBuffer[0];
status = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, nil, dataByteSize, kCFAllocatorDefault, nil, 0, dataByteSize, kCMBlockBufferAssureMemoryNowFlag, &blockBuffer);
ioData->mNumberBuffers = channels;
for(size_t i = 0; i < channels; ++i) {
ioData->mBuffers[i].mData = &eqBuffer[1024 * i];
ioData->mBuffers[i].mDataByteSize = 1024 * sizeof(float);
ioData->mBuffers[i].mNumberChannels = 1;
}
if(status != noErr || !blockBuffer) {
return 0;
status = AudioUnitRender(_eq, NULL, &timeStamp, 0, samplesRendered, ioData);
if(status != noErr) {
return 0;
}
timeStamp.mSampleTime += ((double)samplesRendered) / streamFormat.mSampleRate;
for(int i = 0; i < channels; ++i) {
cblas_scopy(samplesRendered, &eqBuffer[1024 * i], 1, samplePtr, channels);
}
}
}
CMBlockBufferRef blockBuffer = nil;
size_t dataByteSize = samplesRendered * sizeof(float) * streamFormat.mChannelsPerFrame;
status = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, nil, dataByteSize, kCFAllocatorDefault, nil, 0, dataByteSize, kCMBlockBufferAssureMemoryNowFlag, &blockBuffer);
if(status != noErr || !blockBuffer) {
return 0;
}
status = CMBlockBufferReplaceDataBytes(samplePtr, blockBuffer, 0, dataByteSize);
if(status != noErr) {
return 0;
}
status = CMBlockBufferAppendBufferReference(blockListBuffer, blockBuffer, 0, CMBlockBufferGetDataLength(blockBuffer), 0);
if(status != noErr) {
return 0;
}
}
status = CMBlockBufferReplaceDataBytes(&inputBuffer[0], blockBuffer, 0, dataByteSize);
if(status != noErr) {
return 0;
}
status = CMBlockBufferAppendBufferReference(blockListBuffer, blockBuffer, 0, CMBlockBufferGetDataLength(blockBuffer), 0);
if(status != noErr) {
return 0;
if(i == 0) {
if(!samplesRendered) {
*blockBufferOut = blockListBuffer;
return samplesRenderedTotal + samplesRendered;
}
} else {
samplesRenderedTotal += samplesRendered;
if(!samplesRendered || samplesRenderedTotal >= 1024) {
++i;
} else {
do {
inputRendered = [self renderInput];
if([self processEndOfStream]) break;
} while(!inputRendered);
}
}
}
*blockBufferOut = blockListBuffer;
return samplesRendered;
return samplesRenderedTotal;
}
- (BOOL)setup {
@ -672,6 +750,12 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
downmixerForVis = nil;
r8bFlushing = NO;
r8bFlushed = NO;
r8bDone = NO;
r8bstate = NULL;
r8bold = NULL;
AudioComponentDescription desc;
NSError *err;
@ -907,6 +991,14 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
#endif
outputController = nil;
visController = nil;
if(r8bstate) {
r8bstate_delete(r8bstate);
r8bstate = NULL;
}
if(r8bold) {
r8bstate_delete(r8bold);
r8bold = NULL;
}
}
}

1
Audio/ThirdParty/r8brain-free-src vendored Submodule

@ -0,0 +1 @@
Subproject commit afd61e7ed76d86a9bc6cb91fd0a9f305f853fe38

31
Audio/ThirdParty/r8bstate.cpp vendored Normal file
View File

@ -0,0 +1,31 @@
//
// r8bstate.cpp
// CogAudio Framework
//
// Created by Christopher Snowhill on 6/24/22.
//
#include "r8bstate.h"
#include "r8bstate.hpp"
void *r8bstate_new(int channelCount, int bufferCapacity, double srcRate,
double dstRate) {
return (void *)new r8bstate(channelCount, bufferCapacity, srcRate, dstRate);
}
void r8bstate_delete(void *state) {
delete(r8bstate *)state;
}
double r8bstate_latency(void *state) {
return ((r8bstate *)state)->latency();
}
int r8bstate_resample(void *state, const float *input, size_t inCount, size_t *inDone,
float *output, size_t outMax) {
return ((r8bstate *)state)->resample(input, inCount, inDone, output, outMax);
}
int r8bstate_flush(void *state, float *output, size_t outMax) {
return ((r8bstate *)state)->flush(output, outMax);
}

33
Audio/ThirdParty/r8bstate.h vendored Normal file
View File

@ -0,0 +1,33 @@
//
// r8bstate.h
// CogAudio Framework
//
// Created by Christopher Snowhill on 6/24/22.
//
#include <stdint.h>
#include <stdlib.h>
#ifndef r8bstate_h
#define r8bstate_h
#ifdef __cplusplus
extern "C" {
#endif
void *r8bstate_new(int channelCount, int bufferCapacity, double srcRate,
double dstRate);
void r8bstate_delete(void *);
double r8bstate_latency(void *);
int r8bstate_resample(void *, const float *input, size_t inCount, size_t *inDone,
float *output, size_t outMax);
int r8bstate_flush(void *, float *output, size_t outMax);
#ifdef __cplusplus
}
#endif
#endif /* r8bstate_h */

164
Audio/ThirdParty/r8bstate.hpp vendored Normal file
View File

@ -0,0 +1,164 @@
//
// r8bstate.hpp
// CogAudio Framework
//
// Created by Christopher Snowhill on 3/3/22.
//
#ifndef r8bstate_hpp
#define r8bstate_hpp
#include <Accelerate/Accelerate.h>
#include "r8bbase.h"
#include "CDSPResampler.h"
struct r8bstate {
int channelCount;
int bufferCapacity;
size_t remainder;
uint64_t inProcessed;
uint64_t outProcessed;
double sampleRatio;
r8b::CFixedBuffer<double> InBuf;
r8b::CFixedBuffer<double> *OutBufs;
r8b::CDSPResampler24 **Resamps;
r8bstate(int _channelCount, int _bufferCapacity, double srcRate, double dstRate)
: channelCount(_channelCount), bufferCapacity(_bufferCapacity), inProcessed(0), outProcessed(0), remainder(0) {
InBuf.alloc(bufferCapacity);
OutBufs = new r8b::CFixedBuffer<double>[channelCount];
Resamps = new r8b::CDSPResampler24 *[channelCount];
for(int i = 0; i < channelCount; ++i) {
Resamps[i] = new r8b::CDSPResampler24(srcRate, dstRate, bufferCapacity);
}
sampleRatio = dstRate / srcRate;
}
~r8bstate() {
delete[] OutBufs;
for(int i = 0; i < channelCount; ++i) {
delete Resamps[i];
}
delete[] Resamps;
}
double latency() {
return ((double)inProcessed * sampleRatio) - (double)outProcessed;
}
int resample(const float *input, size_t inCount, size_t *inDone, float *output, size_t outMax) {
int ret = 0;
int i;
if(inDone) *inDone = 0;
while(remainder > 0) {
size_t blockCount = remainder;
if(blockCount > outMax)
blockCount = outMax;
for(i = 0; i < channelCount; ++i) {
vDSP_vdpsp(&OutBufs[i][0], 1, output + i, channelCount, blockCount);
}
remainder -= blockCount;
if(remainder > 0) {
for(i = 0; i < channelCount; ++i) {
memmove(&OutBufs[i][0], &OutBufs[i][blockCount], remainder * sizeof(double));
}
}
output += channelCount * blockCount;
outProcessed += blockCount;
outMax -= blockCount;
ret += blockCount;
if(!outMax)
return ret;
}
while(inCount > 0) {
size_t blockCount = inCount;
if(blockCount > bufferCapacity)
blockCount = bufferCapacity;
int outputDone = 0;
for(i = 0; i < channelCount; ++i) {
double *outputPointer;
vDSP_vspdp(input + i, channelCount, &InBuf[0], 1, blockCount);
outputDone = Resamps[i]->process(InBuf, (int)blockCount, outputPointer);
if(outputDone) {
if(outputDone > outMax) {
vDSP_vdpsp(outputPointer, 1, output + i, channelCount, outMax);
remainder = outputDone - outMax;
OutBufs[i].alloc((int)remainder);
memcpy(&OutBufs[i][0], outputPointer + outMax, remainder);
} else {
vDSP_vdpsp(outputPointer, 1, output + i, channelCount, outputDone);
}
}
}
size_t outputActual = outputDone - remainder;
input += channelCount * blockCount;
output += channelCount * outputActual;
inCount -= blockCount;
if(inDone) *inDone += blockCount;
inProcessed += blockCount;
outProcessed += outputActual;
outMax -= outputActual;
ret += outputActual;
if(remainder)
break;
}
return ret;
}
int flush(float *output, size_t outMax) {
int ret = 0;
int i;
if(remainder > 0) {
size_t blockCount = remainder;
if(blockCount > outMax)
blockCount = outMax;
for(i = 0; i < channelCount; ++i) {
vDSP_vdpsp(&OutBufs[i][0], 1, output + i, channelCount, blockCount);
}
remainder -= blockCount;
if(remainder > 0) {
for(i = 0; i < channelCount; ++i) {
memmove(&OutBufs[i][0], &OutBufs[i][blockCount], remainder * sizeof(double));
}
}
output += channelCount * blockCount;
outProcessed += blockCount;
outMax -= blockCount;
ret += blockCount;
if(!outMax)
return ret;
}
uint64_t outputWanted = ceil(inProcessed * sampleRatio);
memset(&InBuf[0], 0, sizeof(double) * bufferCapacity);
while(outProcessed < outputWanted) {
int outputDone = 0;
for(int i = 0; i < channelCount; ++i) {
double *outputPointer;
outputDone = Resamps[i]->process(InBuf, bufferCapacity, outputPointer);
if(outputDone) {
if(outputDone > (outputWanted - outProcessed))
outputDone = (int)(outputWanted - outProcessed);
if(outputDone > outMax) {
vDSP_vdpsp(outputPointer, 1, output + i, channelCount, outMax);
remainder = outputDone - outMax;
OutBufs[i].alloc((int)remainder);
memcpy(&OutBufs[i][0], outputPointer + outMax, remainder);
} else {
vDSP_vdpsp(outputPointer, 1, output + i, channelCount, outputDone);
}
}
}
size_t outputActual = outputDone - remainder;
outProcessed += outputActual;
output += channelCount * outputActual;
outMax -= outputActual;
ret += outputActual;
if(remainder)
break;
}
return ret;
}
};
#endif /* r8bstate_h */