[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>swiftingly
parent
cc5de69e9f
commit
ccbeaf16dc
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit afd61e7ed76d86a9bc6cb91fd0a9f305f853fe38
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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 */
|
Loading…
Reference in New Issue