mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-26 02:14:22 +00:00
New class AbstractFifo - a lock-free fifo helper class. New class AudioFormatWriter::ThreadedWriter, which helps stream an audio file to disk on a background thread. Simplified the juce demo audio recorder using this new class.
This commit is contained in:
parent
9a1fde0470
commit
0e2e4e7c3a
27 changed files with 2056 additions and 1227 deletions
|
|
@ -48,6 +48,8 @@ OBJECTS := \
|
|||
$(OBJDIR)/juce_AudioCDReader_c730f7a6.o \
|
||||
$(OBJDIR)/juce_AudioFormat_6605d0f9.o \
|
||||
$(OBJDIR)/juce_AudioFormatManager_949148fe.o \
|
||||
$(OBJDIR)/juce_AudioFormatReader_36f0295c.o \
|
||||
$(OBJDIR)/juce_AudioFormatWriter_11461d0c.o \
|
||||
$(OBJDIR)/juce_AudioSubsectionReader_65f61a0a.o \
|
||||
$(OBJDIR)/juce_AudioThumbnail_cb99b4b4.o \
|
||||
$(OBJDIR)/juce_AudioThumbnailCache_89a7c678.o \
|
||||
|
|
@ -92,6 +94,7 @@ OBJECTS := \
|
|||
$(OBJDIR)/juce_GenericAudioProcessorEditor_2e8ec30d.o \
|
||||
$(OBJDIR)/juce_Sampler_98f716a4.o \
|
||||
$(OBJDIR)/juce_Synthesiser_2bffa1dd.o \
|
||||
$(OBJDIR)/juce_AbstractFifo_dfc0bd23.o \
|
||||
$(OBJDIR)/juce_BigInteger_63589133.o \
|
||||
$(OBJDIR)/juce_DynamicObject_69d02ab3.o \
|
||||
$(OBJDIR)/juce_Expression_1e9a5aad.o \
|
||||
|
|
@ -404,6 +407,16 @@ $(OBJDIR)/juce_AudioFormatManager_949148fe.o: ../../src/audio/audio_file_formats
|
|||
@echo "Compiling juce_AudioFormatManager.cpp"
|
||||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
|
||||
|
||||
$(OBJDIR)/juce_AudioFormatReader_36f0295c.o: ../../src/audio/audio_file_formats/juce_AudioFormatReader.cpp
|
||||
-@mkdir -p $(OBJDIR)
|
||||
@echo "Compiling juce_AudioFormatReader.cpp"
|
||||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
|
||||
|
||||
$(OBJDIR)/juce_AudioFormatWriter_11461d0c.o: ../../src/audio/audio_file_formats/juce_AudioFormatWriter.cpp
|
||||
-@mkdir -p $(OBJDIR)
|
||||
@echo "Compiling juce_AudioFormatWriter.cpp"
|
||||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
|
||||
|
||||
$(OBJDIR)/juce_AudioSubsectionReader_65f61a0a.o: ../../src/audio/audio_file_formats/juce_AudioSubsectionReader.cpp
|
||||
-@mkdir -p $(OBJDIR)
|
||||
@echo "Compiling juce_AudioSubsectionReader.cpp"
|
||||
|
|
@ -624,6 +637,11 @@ $(OBJDIR)/juce_Synthesiser_2bffa1dd.o: ../../src/audio/synthesisers/juce_Synthes
|
|||
@echo "Compiling juce_Synthesiser.cpp"
|
||||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
|
||||
|
||||
$(OBJDIR)/juce_AbstractFifo_dfc0bd23.o: ../../src/containers/juce_AbstractFifo.cpp
|
||||
-@mkdir -p $(OBJDIR)
|
||||
@echo "Compiling juce_AbstractFifo.cpp"
|
||||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
|
||||
|
||||
$(OBJDIR)/juce_BigInteger_63589133.o: ../../src/containers/juce_BigInteger.cpp
|
||||
-@mkdir -p $(OBJDIR)
|
||||
@echo "Compiling juce_BigInteger.cpp"
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
983FCD60625A60993546F850 = { isa = PBXBuildFile; fileRef = 0877D5750D6F21C5231687CA; };
|
||||
416D6F00E88DC74879B4DF2B = { isa = PBXBuildFile; fileRef = 7D85530D76756C33795ECCE9; };
|
||||
9C709BC2F4F0EE60BF52FACA = { isa = PBXBuildFile; fileRef = 93006D32B18174D9FE0A5E9E; };
|
||||
992F46189ABF711A047186A4 = { isa = PBXBuildFile; fileRef = 9349E14552FEA0371553E808; };
|
||||
5C312E6678456C8293633E0F = { isa = PBXBuildFile; fileRef = 2AD64F53E12B20011B7A0DB7; };
|
||||
FB21B7E6A7CE55D3C0E3C37E = { isa = PBXBuildFile; fileRef = 59597FA0A88A08937801D198; };
|
||||
C1147D03F1F4D697CC30DD22 = { isa = PBXBuildFile; fileRef = 27C3C51DF2519B519B76E2EE; };
|
||||
C5CFF5508299C26380465290 = { isa = PBXBuildFile; fileRef = CB32D4EE59D5CA9DB12F944D; };
|
||||
|
|
@ -61,6 +63,7 @@
|
|||
D1407BB28C169F5E1CAC3CC7 = { isa = PBXBuildFile; fileRef = 096CF2243648F17E1BF5421B; };
|
||||
07E6E11A658930554FF0C56A = { isa = PBXBuildFile; fileRef = ED5966B95F865C586A3CE08F; };
|
||||
E8DFABC1603D55B97429A8E4 = { isa = PBXBuildFile; fileRef = 35668D8EEA19957C6C9AC83A; };
|
||||
1F905F44E5FA23A2D5CCDA0A = { isa = PBXBuildFile; fileRef = 4F22276689685D839BD252EA; };
|
||||
BE25871C34D79FEFFD1B94B6 = { isa = PBXBuildFile; fileRef = 895D742F49DA9F100990879C; };
|
||||
4AB5E55BDF79028F82F83D8E = { isa = PBXBuildFile; fileRef = F77C9170829579FABA5679AD; };
|
||||
25018C91F79D918FEA084630 = { isa = PBXBuildFile; fileRef = 199DFD1C5A282FE13A585FEA; };
|
||||
|
|
@ -359,7 +362,9 @@
|
|||
013E8938EE1C6B4F63016B55 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioFormat.h; path = ../../src/audio/audio_file_formats/juce_AudioFormat.h; sourceTree = SOURCE_ROOT; };
|
||||
93006D32B18174D9FE0A5E9E = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioFormatManager.cpp; path = ../../src/audio/audio_file_formats/juce_AudioFormatManager.cpp; sourceTree = SOURCE_ROOT; };
|
||||
41070806F82EC9C6D1C67689 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioFormatManager.h; path = ../../src/audio/audio_file_formats/juce_AudioFormatManager.h; sourceTree = SOURCE_ROOT; };
|
||||
9349E14552FEA0371553E808 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioFormatReader.cpp; path = ../../src/audio/audio_file_formats/juce_AudioFormatReader.cpp; sourceTree = SOURCE_ROOT; };
|
||||
27356F5E93CEA4D472D83D8E = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioFormatReader.h; path = ../../src/audio/audio_file_formats/juce_AudioFormatReader.h; sourceTree = SOURCE_ROOT; };
|
||||
2AD64F53E12B20011B7A0DB7 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioFormatWriter.cpp; path = ../../src/audio/audio_file_formats/juce_AudioFormatWriter.cpp; sourceTree = SOURCE_ROOT; };
|
||||
8BD38C2507C0F8E28930A4F8 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioFormatWriter.h; path = ../../src/audio/audio_file_formats/juce_AudioFormatWriter.h; sourceTree = SOURCE_ROOT; };
|
||||
59597FA0A88A08937801D198 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioSubsectionReader.cpp; path = ../../src/audio/audio_file_formats/juce_AudioSubsectionReader.cpp; sourceTree = SOURCE_ROOT; };
|
||||
AE7F7F0D959C2E3CF5989C88 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioSubsectionReader.h; path = ../../src/audio/audio_file_formats/juce_AudioSubsectionReader.h; sourceTree = SOURCE_ROOT; };
|
||||
|
|
@ -477,6 +482,8 @@
|
|||
6C6C1C360138D9BD4B27588B = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Sampler.h; path = ../../src/audio/synthesisers/juce_Sampler.h; sourceTree = SOURCE_ROOT; };
|
||||
35668D8EEA19957C6C9AC83A = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_Synthesiser.cpp; path = ../../src/audio/synthesisers/juce_Synthesiser.cpp; sourceTree = SOURCE_ROOT; };
|
||||
9E6C206F95245BCDE38FB2B5 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Synthesiser.h; path = ../../src/audio/synthesisers/juce_Synthesiser.h; sourceTree = SOURCE_ROOT; };
|
||||
4F22276689685D839BD252EA = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AbstractFifo.cpp; path = ../../src/containers/juce_AbstractFifo.cpp; sourceTree = SOURCE_ROOT; };
|
||||
9584B84F23A4251755D49213 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AbstractFifo.h; path = ../../src/containers/juce_AbstractFifo.h; sourceTree = SOURCE_ROOT; };
|
||||
839BE8047CF2F8EBE43ED34F = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Array.h; path = ../../src/containers/juce_Array.h; sourceTree = SOURCE_ROOT; };
|
||||
EDF52FDF87ACD33FE933142C = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ArrayAllocationBase.h; path = ../../src/containers/juce_ArrayAllocationBase.h; sourceTree = SOURCE_ROOT; };
|
||||
895D742F49DA9F100990879C = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_BigInteger.cpp; path = ../../src/containers/juce_BigInteger.cpp; sourceTree = SOURCE_ROOT; };
|
||||
|
|
@ -1048,7 +1055,9 @@
|
|||
013E8938EE1C6B4F63016B55,
|
||||
93006D32B18174D9FE0A5E9E,
|
||||
41070806F82EC9C6D1C67689,
|
||||
9349E14552FEA0371553E808,
|
||||
27356F5E93CEA4D472D83D8E,
|
||||
2AD64F53E12B20011B7A0DB7,
|
||||
8BD38C2507C0F8E28930A4F8,
|
||||
59597FA0A88A08937801D198,
|
||||
AE7F7F0D959C2E3CF5989C88,
|
||||
|
|
@ -1195,6 +1204,8 @@
|
|||
231431F8B23F01DC6ECD4214,
|
||||
DC641C77950A335A20FD4532 ); name = audio; sourceTree = "<group>"; };
|
||||
1CC2889DB696E12FC34E3F50 = { isa = PBXGroup; children = (
|
||||
4F22276689685D839BD252EA,
|
||||
9584B84F23A4251755D49213,
|
||||
839BE8047CF2F8EBE43ED34F,
|
||||
EDF52FDF87ACD33FE933142C,
|
||||
895D742F49DA9F100990879C,
|
||||
|
|
@ -1915,6 +1926,8 @@
|
|||
983FCD60625A60993546F850,
|
||||
416D6F00E88DC74879B4DF2B,
|
||||
9C709BC2F4F0EE60BF52FACA,
|
||||
992F46189ABF711A047186A4,
|
||||
5C312E6678456C8293633E0F,
|
||||
FB21B7E6A7CE55D3C0E3C37E,
|
||||
C1147D03F1F4D697CC30DD22,
|
||||
C5CFF5508299C26380465290,
|
||||
|
|
@ -1961,6 +1974,7 @@
|
|||
D1407BB28C169F5E1CAC3CC7,
|
||||
07E6E11A658930554FF0C56A,
|
||||
E8DFABC1603D55B97429A8E4,
|
||||
1F905F44E5FA23A2D5CCDA0A,
|
||||
BE25871C34D79FEFFD1B94B6,
|
||||
4AB5E55BDF79028F82F83D8E,
|
||||
25018C91F79D918FEA084630,
|
||||
|
|
|
|||
|
|
@ -124,7 +124,9 @@
|
|||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormat.h"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatManager.cpp"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatManager.h"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatReader.cpp"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatReader.h"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatWriter.cpp"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatWriter.h"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioSubsectionReader.cpp"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioSubsectionReader.h"/>
|
||||
|
|
@ -343,6 +345,8 @@
|
|||
</Filter>
|
||||
</Filter>
|
||||
<Filter Name="containers">
|
||||
<File RelativePath="..\..\src\containers\juce_AbstractFifo.cpp"/>
|
||||
<File RelativePath="..\..\src\containers\juce_AbstractFifo.h"/>
|
||||
<File RelativePath="..\..\src\containers\juce_Array.h"/>
|
||||
<File RelativePath="..\..\src\containers\juce_ArrayAllocationBase.h"/>
|
||||
<File RelativePath="..\..\src\containers\juce_BigInteger.cpp"/>
|
||||
|
|
|
|||
|
|
@ -124,7 +124,9 @@
|
|||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormat.h"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatManager.cpp"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatManager.h"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatReader.cpp"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatReader.h"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatWriter.cpp"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatWriter.h"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioSubsectionReader.cpp"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioSubsectionReader.h"/>
|
||||
|
|
@ -343,6 +345,8 @@
|
|||
</Filter>
|
||||
</Filter>
|
||||
<Filter Name="containers">
|
||||
<File RelativePath="..\..\src\containers\juce_AbstractFifo.cpp"/>
|
||||
<File RelativePath="..\..\src\containers\juce_AbstractFifo.h"/>
|
||||
<File RelativePath="..\..\src\containers\juce_Array.h"/>
|
||||
<File RelativePath="..\..\src\containers\juce_ArrayAllocationBase.h"/>
|
||||
<File RelativePath="..\..\src\containers\juce_BigInteger.cpp"/>
|
||||
|
|
|
|||
|
|
@ -126,7 +126,9 @@
|
|||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormat.h"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatManager.cpp"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatManager.h"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatReader.cpp"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatReader.h"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatWriter.cpp"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatWriter.h"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioSubsectionReader.cpp"/>
|
||||
<File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioSubsectionReader.h"/>
|
||||
|
|
@ -345,6 +347,8 @@
|
|||
</Filter>
|
||||
</Filter>
|
||||
<Filter Name="containers">
|
||||
<File RelativePath="..\..\src\containers\juce_AbstractFifo.cpp"/>
|
||||
<File RelativePath="..\..\src\containers\juce_AbstractFifo.h"/>
|
||||
<File RelativePath="..\..\src\containers\juce_Array.h"/>
|
||||
<File RelativePath="..\..\src\containers\juce_ArrayAllocationBase.h"/>
|
||||
<File RelativePath="..\..\src\containers\juce_BigInteger.cpp"/>
|
||||
|
|
|
|||
|
|
@ -131,6 +131,8 @@
|
|||
<ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioCDReader.cpp"/>
|
||||
<ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioFormat.cpp"/>
|
||||
<ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioFormatManager.cpp"/>
|
||||
<ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioFormatReader.cpp"/>
|
||||
<ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioFormatWriter.cpp"/>
|
||||
<ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioSubsectionReader.cpp"/>
|
||||
<ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioThumbnail.cpp"/>
|
||||
<ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioThumbnailCache.cpp"/>
|
||||
|
|
@ -175,6 +177,7 @@
|
|||
<ClCompile Include="..\..\src\audio\processors\juce_GenericAudioProcessorEditor.cpp"/>
|
||||
<ClCompile Include="..\..\src\audio\synthesisers\juce_Sampler.cpp"/>
|
||||
<ClCompile Include="..\..\src\audio\synthesisers\juce_Synthesiser.cpp"/>
|
||||
<ClCompile Include="..\..\src\containers\juce_AbstractFifo.cpp"/>
|
||||
<ClCompile Include="..\..\src\containers\juce_BigInteger.cpp"/>
|
||||
<ClCompile Include="..\..\src\containers\juce_DynamicObject.cpp"/>
|
||||
<ClCompile Include="..\..\src\containers\juce_Expression.cpp"/>
|
||||
|
|
@ -500,6 +503,7 @@
|
|||
<ClInclude Include="..\..\src\audio\processors\juce_GenericAudioProcessorEditor.h"/>
|
||||
<ClInclude Include="..\..\src\audio\synthesisers\juce_Sampler.h"/>
|
||||
<ClInclude Include="..\..\src\audio\synthesisers\juce_Synthesiser.h"/>
|
||||
<ClInclude Include="..\..\src\containers\juce_AbstractFifo.h"/>
|
||||
<ClInclude Include="..\..\src\containers\juce_Array.h"/>
|
||||
<ClInclude Include="..\..\src\containers\juce_ArrayAllocationBase.h"/>
|
||||
<ClInclude Include="..\..\src\containers\juce_BigInteger.h"/>
|
||||
|
|
|
|||
|
|
@ -202,6 +202,12 @@
|
|||
<ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioFormatManager.cpp">
|
||||
<Filter>Juce\Source\audio\audio_file_formats</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioFormatReader.cpp">
|
||||
<Filter>Juce\Source\audio\audio_file_formats</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioFormatWriter.cpp">
|
||||
<Filter>Juce\Source\audio\audio_file_formats</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioSubsectionReader.cpp">
|
||||
<Filter>Juce\Source\audio\audio_file_formats</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -373,6 +379,9 @@
|
|||
<ClCompile Include="..\..\src\audio\synthesisers\juce_Synthesiser.cpp">
|
||||
<Filter>Juce\Source\audio\synthesisers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\containers\juce_AbstractFifo.cpp">
|
||||
<Filter>Juce\Source\containers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\containers\juce_BigInteger.cpp">
|
||||
<Filter>Juce\Source\containers</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -1422,6 +1431,9 @@
|
|||
<ClInclude Include="..\..\src\audio\synthesisers\juce_Synthesiser.h">
|
||||
<Filter>Juce\Source\audio\synthesisers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\containers\juce_AbstractFifo.h">
|
||||
<Filter>Juce\Source\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\containers\juce_Array.h">
|
||||
<Filter>Juce\Source\containers</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
983FCD60625A60993546F850 = { isa = PBXBuildFile; fileRef = 0877D5750D6F21C5231687CA; };
|
||||
416D6F00E88DC74879B4DF2B = { isa = PBXBuildFile; fileRef = 7D85530D76756C33795ECCE9; };
|
||||
9C709BC2F4F0EE60BF52FACA = { isa = PBXBuildFile; fileRef = 93006D32B18174D9FE0A5E9E; };
|
||||
992F46189ABF711A047186A4 = { isa = PBXBuildFile; fileRef = 9349E14552FEA0371553E808; };
|
||||
5C312E6678456C8293633E0F = { isa = PBXBuildFile; fileRef = 2AD64F53E12B20011B7A0DB7; };
|
||||
FB21B7E6A7CE55D3C0E3C37E = { isa = PBXBuildFile; fileRef = 59597FA0A88A08937801D198; };
|
||||
C1147D03F1F4D697CC30DD22 = { isa = PBXBuildFile; fileRef = 27C3C51DF2519B519B76E2EE; };
|
||||
C5CFF5508299C26380465290 = { isa = PBXBuildFile; fileRef = CB32D4EE59D5CA9DB12F944D; };
|
||||
|
|
@ -61,6 +63,7 @@
|
|||
D1407BB28C169F5E1CAC3CC7 = { isa = PBXBuildFile; fileRef = 096CF2243648F17E1BF5421B; };
|
||||
07E6E11A658930554FF0C56A = { isa = PBXBuildFile; fileRef = ED5966B95F865C586A3CE08F; };
|
||||
E8DFABC1603D55B97429A8E4 = { isa = PBXBuildFile; fileRef = 35668D8EEA19957C6C9AC83A; };
|
||||
1F905F44E5FA23A2D5CCDA0A = { isa = PBXBuildFile; fileRef = 4F22276689685D839BD252EA; };
|
||||
BE25871C34D79FEFFD1B94B6 = { isa = PBXBuildFile; fileRef = 895D742F49DA9F100990879C; };
|
||||
4AB5E55BDF79028F82F83D8E = { isa = PBXBuildFile; fileRef = F77C9170829579FABA5679AD; };
|
||||
25018C91F79D918FEA084630 = { isa = PBXBuildFile; fileRef = 199DFD1C5A282FE13A585FEA; };
|
||||
|
|
@ -359,7 +362,9 @@
|
|||
013E8938EE1C6B4F63016B55 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioFormat.h; path = ../../src/audio/audio_file_formats/juce_AudioFormat.h; sourceTree = SOURCE_ROOT; };
|
||||
93006D32B18174D9FE0A5E9E = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioFormatManager.cpp; path = ../../src/audio/audio_file_formats/juce_AudioFormatManager.cpp; sourceTree = SOURCE_ROOT; };
|
||||
41070806F82EC9C6D1C67689 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioFormatManager.h; path = ../../src/audio/audio_file_formats/juce_AudioFormatManager.h; sourceTree = SOURCE_ROOT; };
|
||||
9349E14552FEA0371553E808 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioFormatReader.cpp; path = ../../src/audio/audio_file_formats/juce_AudioFormatReader.cpp; sourceTree = SOURCE_ROOT; };
|
||||
27356F5E93CEA4D472D83D8E = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioFormatReader.h; path = ../../src/audio/audio_file_formats/juce_AudioFormatReader.h; sourceTree = SOURCE_ROOT; };
|
||||
2AD64F53E12B20011B7A0DB7 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioFormatWriter.cpp; path = ../../src/audio/audio_file_formats/juce_AudioFormatWriter.cpp; sourceTree = SOURCE_ROOT; };
|
||||
8BD38C2507C0F8E28930A4F8 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioFormatWriter.h; path = ../../src/audio/audio_file_formats/juce_AudioFormatWriter.h; sourceTree = SOURCE_ROOT; };
|
||||
59597FA0A88A08937801D198 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioSubsectionReader.cpp; path = ../../src/audio/audio_file_formats/juce_AudioSubsectionReader.cpp; sourceTree = SOURCE_ROOT; };
|
||||
AE7F7F0D959C2E3CF5989C88 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioSubsectionReader.h; path = ../../src/audio/audio_file_formats/juce_AudioSubsectionReader.h; sourceTree = SOURCE_ROOT; };
|
||||
|
|
@ -477,6 +482,8 @@
|
|||
6C6C1C360138D9BD4B27588B = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Sampler.h; path = ../../src/audio/synthesisers/juce_Sampler.h; sourceTree = SOURCE_ROOT; };
|
||||
35668D8EEA19957C6C9AC83A = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_Synthesiser.cpp; path = ../../src/audio/synthesisers/juce_Synthesiser.cpp; sourceTree = SOURCE_ROOT; };
|
||||
9E6C206F95245BCDE38FB2B5 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Synthesiser.h; path = ../../src/audio/synthesisers/juce_Synthesiser.h; sourceTree = SOURCE_ROOT; };
|
||||
4F22276689685D839BD252EA = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AbstractFifo.cpp; path = ../../src/containers/juce_AbstractFifo.cpp; sourceTree = SOURCE_ROOT; };
|
||||
9584B84F23A4251755D49213 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AbstractFifo.h; path = ../../src/containers/juce_AbstractFifo.h; sourceTree = SOURCE_ROOT; };
|
||||
839BE8047CF2F8EBE43ED34F = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Array.h; path = ../../src/containers/juce_Array.h; sourceTree = SOURCE_ROOT; };
|
||||
EDF52FDF87ACD33FE933142C = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ArrayAllocationBase.h; path = ../../src/containers/juce_ArrayAllocationBase.h; sourceTree = SOURCE_ROOT; };
|
||||
895D742F49DA9F100990879C = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_BigInteger.cpp; path = ../../src/containers/juce_BigInteger.cpp; sourceTree = SOURCE_ROOT; };
|
||||
|
|
@ -1048,7 +1055,9 @@
|
|||
013E8938EE1C6B4F63016B55,
|
||||
93006D32B18174D9FE0A5E9E,
|
||||
41070806F82EC9C6D1C67689,
|
||||
9349E14552FEA0371553E808,
|
||||
27356F5E93CEA4D472D83D8E,
|
||||
2AD64F53E12B20011B7A0DB7,
|
||||
8BD38C2507C0F8E28930A4F8,
|
||||
59597FA0A88A08937801D198,
|
||||
AE7F7F0D959C2E3CF5989C88,
|
||||
|
|
@ -1195,6 +1204,8 @@
|
|||
231431F8B23F01DC6ECD4214,
|
||||
DC641C77950A335A20FD4532 ); name = audio; sourceTree = "<group>"; };
|
||||
1CC2889DB696E12FC34E3F50 = { isa = PBXGroup; children = (
|
||||
4F22276689685D839BD252EA,
|
||||
9584B84F23A4251755D49213,
|
||||
839BE8047CF2F8EBE43ED34F,
|
||||
EDF52FDF87ACD33FE933142C,
|
||||
895D742F49DA9F100990879C,
|
||||
|
|
@ -1915,6 +1926,8 @@
|
|||
983FCD60625A60993546F850,
|
||||
416D6F00E88DC74879B4DF2B,
|
||||
9C709BC2F4F0EE60BF52FACA,
|
||||
992F46189ABF711A047186A4,
|
||||
5C312E6678456C8293633E0F,
|
||||
FB21B7E6A7CE55D3C0E3C37E,
|
||||
C1147D03F1F4D697CC30DD22,
|
||||
C5CFF5508299C26380465290,
|
||||
|
|
@ -1961,6 +1974,7 @@
|
|||
D1407BB28C169F5E1CAC3CC7,
|
||||
07E6E11A658930554FF0C56A,
|
||||
E8DFABC1603D55B97429A8E4,
|
||||
1F905F44E5FA23A2D5CCDA0A,
|
||||
BE25871C34D79FEFFD1B94B6,
|
||||
4AB5E55BDF79028F82F83D8E,
|
||||
25018C91F79D918FEA084630,
|
||||
|
|
|
|||
|
|
@ -81,8 +81,12 @@
|
|||
resource="0" file="src/audio/audio_file_formats/juce_AudioFormatManager.cpp"/>
|
||||
<FILE id="cz5oBf3fx" name="juce_AudioFormatManager.h" compile="0" resource="0"
|
||||
file="src/audio/audio_file_formats/juce_AudioFormatManager.h"/>
|
||||
<FILE id="0TiI3po" name="juce_AudioFormatReader.cpp" compile="1" resource="0"
|
||||
file="src/audio/audio_file_formats/juce_AudioFormatReader.cpp"/>
|
||||
<FILE id="x3bpEuQrJ" name="juce_AudioFormatReader.h" compile="0" resource="0"
|
||||
file="src/audio/audio_file_formats/juce_AudioFormatReader.h"/>
|
||||
<FILE id="G8yVpHF" name="juce_AudioFormatWriter.cpp" compile="1" resource="0"
|
||||
file="src/audio/audio_file_formats/juce_AudioFormatWriter.cpp"/>
|
||||
<FILE id="eCeRZdLR" name="juce_AudioFormatWriter.h" compile="0" resource="0"
|
||||
file="src/audio/audio_file_formats/juce_AudioFormatWriter.h"/>
|
||||
<FILE id="Fo4wJzEFh" name="juce_AudioSubsectionReader.cpp" compile="1"
|
||||
|
|
@ -346,6 +350,10 @@
|
|||
</GROUP>
|
||||
</GROUP>
|
||||
<GROUP id="jDNvJtXHE" name="containers">
|
||||
<FILE id="ChnNms" name="juce_AbstractFifo.cpp" compile="1" resource="0"
|
||||
file="src/containers/juce_AbstractFifo.cpp"/>
|
||||
<FILE id="llcRKU5" name="juce_AbstractFifo.h" compile="0" resource="0"
|
||||
file="src/containers/juce_AbstractFifo.h"/>
|
||||
<FILE id="MMVvnl2oo" name="juce_Array.h" compile="0" resource="0" file="src/containers/juce_Array.h"/>
|
||||
<FILE id="I2LILZNlU" name="juce_ArrayAllocationBase.h" compile="0"
|
||||
resource="0" file="src/containers/juce_ArrayAllocationBase.h"/>
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@
|
|||
#include "../src/core/juce_SystemStats.cpp"
|
||||
#include "../src/core/juce_Time.cpp"
|
||||
#include "../src/core/juce_Initialisation.cpp"
|
||||
#include "../src/containers/juce_AbstractFifo.cpp"
|
||||
#include "../src/containers/juce_BigInteger.cpp"
|
||||
#include "../src/containers/juce_MemoryBlock.cpp"
|
||||
#include "../src/containers/juce_PropertySet.cpp"
|
||||
|
|
@ -164,6 +165,8 @@
|
|||
#include "../src/utilities/juce_UndoManager.cpp"
|
||||
#include "../src/audio/audio_file_formats/juce_AiffAudioFormat.cpp"
|
||||
#include "../src/audio/audio_file_formats/juce_AudioFormat.cpp"
|
||||
#include "../src/audio/audio_file_formats/juce_AudioFormatReader.cpp"
|
||||
#include "../src/audio/audio_file_formats/juce_AudioFormatWriter.cpp"
|
||||
#include "../src/audio/audio_file_formats/juce_AudioFormatManager.cpp"
|
||||
#include "../src/audio/audio_file_formats/juce_AudioSubsectionReader.cpp"
|
||||
#include "../src/audio/audio_file_formats/juce_AudioThumbnail.cpp"
|
||||
|
|
|
|||
|
|
@ -505,7 +505,7 @@ private:
|
|||
s.add ("ZERO_LINK = NO");
|
||||
|
||||
if (! isRTAS()) // (dwarf seems to be incompatible with the RTAS libs)
|
||||
s.add ("DEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\"");
|
||||
s.add ("DEBUG_INFORMATION_FORMAT = \"dwarf\"");
|
||||
|
||||
s.add ("PRODUCT_NAME = \"" + config.getTargetBinaryName().toString() + "\"");
|
||||
return s;
|
||||
|
|
|
|||
|
|
@ -27,112 +27,19 @@
|
|||
|
||||
//[MiscUserDefs] You can add your own user definitions and misc code here...
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/* This is a rough-and-ready circular buffer, used to allow the audio thread to
|
||||
push data quickly into a queue, allowing a background thread to come along and
|
||||
write it to disk later.
|
||||
/** A simple class that acts as an AudioIODeviceCallback and writes the
|
||||
incoming audio data to a WAV file.
|
||||
*/
|
||||
class CircularAudioBuffer
|
||||
{
|
||||
public:
|
||||
CircularAudioBuffer (const int numChannels, const int numSamples)
|
||||
: buffer (numChannels, numSamples)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
~CircularAudioBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
buffer.clear();
|
||||
|
||||
const ScopedLock sl (bufferLock);
|
||||
bufferValidStart = bufferValidEnd = 0;
|
||||
}
|
||||
|
||||
void addSamplesToBuffer (const AudioSampleBuffer& sourceBuffer, int numSamples)
|
||||
{
|
||||
const int bufferSize = buffer.getNumSamples();
|
||||
|
||||
bufferLock.enter();
|
||||
int newDataStart = bufferValidEnd;
|
||||
int newDataEnd = newDataStart + numSamples;
|
||||
const int actualNewDataEnd = newDataEnd;
|
||||
bufferValidStart = jmax (bufferValidStart, newDataEnd - bufferSize);
|
||||
bufferLock.exit();
|
||||
|
||||
newDataStart %= bufferSize;
|
||||
newDataEnd %= bufferSize;
|
||||
|
||||
if (newDataEnd < newDataStart)
|
||||
{
|
||||
for (int i = jmin (buffer.getNumChannels(), sourceBuffer.getNumChannels()); --i >= 0;)
|
||||
{
|
||||
buffer.copyFrom (i, newDataStart, sourceBuffer, i, 0, bufferSize - newDataStart);
|
||||
buffer.copyFrom (i, 0, sourceBuffer, i, bufferSize - newDataStart, newDataEnd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = jmin (buffer.getNumChannels(), sourceBuffer.getNumChannels()); --i >= 0;)
|
||||
buffer.copyFrom (i, newDataStart, sourceBuffer, i, 0, newDataEnd - newDataStart);
|
||||
}
|
||||
|
||||
const ScopedLock sl (bufferLock);
|
||||
bufferValidEnd = actualNewDataEnd;
|
||||
}
|
||||
|
||||
int readSamplesFromBuffer (AudioSampleBuffer& destBuffer, int numSamples)
|
||||
{
|
||||
const int bufferSize = buffer.getNumSamples();
|
||||
|
||||
bufferLock.enter();
|
||||
int availableDataStart = bufferValidStart;
|
||||
const int numSamplesDone = jmin (numSamples, bufferValidEnd - availableDataStart);
|
||||
int availableDataEnd = availableDataStart + numSamplesDone;
|
||||
bufferValidStart = availableDataEnd;
|
||||
bufferLock.exit();
|
||||
|
||||
availableDataStart %= bufferSize;
|
||||
availableDataEnd %= bufferSize;
|
||||
|
||||
if (availableDataEnd < availableDataStart)
|
||||
{
|
||||
for (int i = jmin (buffer.getNumChannels(), destBuffer.getNumChannels()); --i >= 0;)
|
||||
{
|
||||
destBuffer.copyFrom (i, 0, buffer, i, availableDataStart, bufferSize - availableDataStart);
|
||||
destBuffer.copyFrom (i, bufferSize - availableDataStart, buffer, i, 0, availableDataEnd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = jmin (buffer.getNumChannels(), destBuffer.getNumChannels()); --i >= 0;)
|
||||
destBuffer.copyFrom (i, 0, buffer, i, availableDataStart, numSamplesDone);
|
||||
}
|
||||
|
||||
return numSamplesDone;
|
||||
}
|
||||
|
||||
private:
|
||||
CriticalSection bufferLock;
|
||||
AudioSampleBuffer buffer;
|
||||
int bufferValidStart, bufferValidEnd;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class AudioRecorder : public AudioIODeviceCallback,
|
||||
public Thread
|
||||
class AudioRecorder : public AudioIODeviceCallback
|
||||
{
|
||||
public:
|
||||
AudioRecorder()
|
||||
: Thread ("audio recorder"),
|
||||
circularBuffer (2, 48000),
|
||||
recording (false),
|
||||
sampleRate (0)
|
||||
: backgroundThread ("Audio Recorder Thread"),
|
||||
sampleRate (0), activeWriter (0)
|
||||
{
|
||||
backgroundThread.startThread();
|
||||
}
|
||||
|
||||
~AudioRecorder()
|
||||
|
|
@ -147,24 +54,49 @@ public:
|
|||
|
||||
if (sampleRate > 0)
|
||||
{
|
||||
fileToRecord = file;
|
||||
startThread();
|
||||
// Create an OutputStream to write to our destination file...
|
||||
file.deleteFile();
|
||||
ScopedPointer<FileOutputStream> fileStream (file.createOutputStream());
|
||||
|
||||
circularBuffer.clear();
|
||||
recording = true;
|
||||
if (fileStream != 0)
|
||||
{
|
||||
// Now create a WAV writer object that writes to our output stream...
|
||||
WavAudioFormat wavFormat;
|
||||
AudioFormatWriter* writer = wavFormat.createWriterFor (fileStream, sampleRate, 1, 16, StringPairArray(), 0);
|
||||
|
||||
if (writer != 0)
|
||||
{
|
||||
fileStream.release(); // (passes responsibility for deleting the stream to the writer object that is now using it)
|
||||
|
||||
// Now we'll create one of these helper objects which will act as a FIFO buffer, and will
|
||||
// write the data to disk on our background thread.
|
||||
threadedWriter = new AudioFormatWriter::ThreadedWriter (writer, backgroundThread, 32768);
|
||||
|
||||
// And now, swap over our active writer pointer so that the audio callback will start using it..
|
||||
const ScopedLock sl (writerLock);
|
||||
activeWriter = threadedWriter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
recording = false;
|
||||
// First, clear this pointer to stop the audio callback from using our writer object..
|
||||
{
|
||||
const ScopedLock sl (writerLock);
|
||||
activeWriter = 0;
|
||||
}
|
||||
|
||||
stopThread (5000);
|
||||
// Now we can delete the writer object. It's done in this order because the deletion could
|
||||
// take a little time while remaining data gets flushed to disk, so it's best to avoid blocking
|
||||
// the audio callback while this happens.
|
||||
threadedWriter = 0;
|
||||
}
|
||||
|
||||
bool isRecording() const
|
||||
{
|
||||
return isThreadRunning() && recording;
|
||||
return activeWriter != 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -182,11 +114,10 @@ public:
|
|||
float** outputChannelData, int numOutputChannels,
|
||||
int numSamples)
|
||||
{
|
||||
if (recording)
|
||||
{
|
||||
const AudioSampleBuffer incomingData ((float**) inputChannelData, numInputChannels, numSamples);
|
||||
circularBuffer.addSamplesToBuffer (incomingData, numSamples);
|
||||
}
|
||||
const ScopedLock sl (writerLock);
|
||||
|
||||
if (activeWriter != 0)
|
||||
activeWriter->write (inputChannelData, numSamples);
|
||||
|
||||
// We need to clear the output buffers, in case they're full of junk..
|
||||
for (int i = 0; i < numOutputChannels; ++i)
|
||||
|
|
@ -194,44 +125,13 @@ public:
|
|||
zeromem (outputChannelData[i], sizeof (float) * numSamples);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void run()
|
||||
{
|
||||
fileToRecord.deleteFile();
|
||||
|
||||
OutputStream* outStream = fileToRecord.createOutputStream();
|
||||
if (outStream == 0)
|
||||
return;
|
||||
|
||||
WavAudioFormat wavFormat;
|
||||
AudioFormatWriter* writer = wavFormat.createWriterFor (outStream, sampleRate, 1, 16, StringPairArray(), 0);
|
||||
|
||||
if (writer == 0)
|
||||
{
|
||||
delete outStream;
|
||||
return;
|
||||
}
|
||||
|
||||
AudioSampleBuffer tempBuffer (2, 8192);
|
||||
|
||||
while (! threadShouldExit())
|
||||
{
|
||||
int numSamplesReady = circularBuffer.readSamplesFromBuffer (tempBuffer, tempBuffer.getNumSamples());
|
||||
|
||||
if (numSamplesReady > 0)
|
||||
tempBuffer.writeToAudioWriter (writer, 0, numSamplesReady);
|
||||
|
||||
Thread::sleep (1);
|
||||
}
|
||||
|
||||
delete writer;
|
||||
}
|
||||
|
||||
File fileToRecord;
|
||||
private:
|
||||
TimeSliceThread backgroundThread; // the thread that will write our audio data to disk
|
||||
ScopedPointer<AudioFormatWriter::ThreadedWriter> threadedWriter; // the FIFO used to buffer the incoming data
|
||||
double sampleRate;
|
||||
bool recording;
|
||||
|
||||
CircularAudioBuffer circularBuffer;
|
||||
CriticalSection writerLock;
|
||||
AudioFormatWriter::ThreadedWriter* volatile activeWriter;
|
||||
};
|
||||
|
||||
//[/MiscUserDefs]
|
||||
|
|
@ -275,10 +175,9 @@ AudioDemoRecordPage::AudioDemoRecordPage (AudioDeviceManager& deviceManager_)
|
|||
AudioDemoRecordPage::~AudioDemoRecordPage()
|
||||
{
|
||||
//[Destructor_pre]. You can add your own custom destruction code here..
|
||||
recorder->stop();
|
||||
deviceManager.removeAudioCallback (recorder);
|
||||
delete recorder;
|
||||
deviceManager.removeAudioCallback (liveAudioDisplayComp);
|
||||
recorder = 0;
|
||||
//[/Destructor_pre]
|
||||
|
||||
deleteAndZero (liveAudioDisplayComp);
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ public:
|
|||
private:
|
||||
//[UserVariables] -- You can add your own custom variables in this section.
|
||||
AudioDeviceManager& deviceManager;
|
||||
AudioRecorder* recorder;
|
||||
ScopedPointer<AudioRecorder> recorder;
|
||||
//[/UserVariables]
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -2407,6 +2407,100 @@ END_JUCE_NAMESPACE
|
|||
/*** End of inlined file: juce_Initialisation.cpp ***/
|
||||
|
||||
|
||||
/*** Start of inlined file: juce_AbstractFifo.cpp ***/
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
AbstractFifo::AbstractFifo (const int capacity) throw()
|
||||
: bufferSize (capacity)
|
||||
{
|
||||
jassert (bufferSize > 0);
|
||||
}
|
||||
|
||||
AbstractFifo::~AbstractFifo() {}
|
||||
|
||||
int AbstractFifo::getTotalSize() const throw() { return bufferSize; }
|
||||
int AbstractFifo::getFreeSpace() const throw() { return bufferSize - getNumReady(); }
|
||||
int AbstractFifo::getNumReady() const throw() { return validEnd.get() - validStart.get(); }
|
||||
|
||||
void AbstractFifo::reset() throw()
|
||||
{
|
||||
validEnd = 0;
|
||||
validStart = 0;
|
||||
}
|
||||
|
||||
void AbstractFifo::setTotalSize (int newSize) throw()
|
||||
{
|
||||
jassert (newSize > 0);
|
||||
reset();
|
||||
bufferSize = newSize;
|
||||
}
|
||||
|
||||
void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) throw()
|
||||
{
|
||||
const int vs = validStart.get();
|
||||
const int ve = validEnd.get();
|
||||
|
||||
const int freeSpace = bufferSize - (ve - vs);
|
||||
numToWrite = jmin (numToWrite, freeSpace);
|
||||
|
||||
if (numToWrite <= 0)
|
||||
{
|
||||
startIndex1 = 0;
|
||||
startIndex2 = 0;
|
||||
blockSize1 = 0;
|
||||
blockSize2 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
startIndex1 = (int) (ve % bufferSize);
|
||||
startIndex2 = 0;
|
||||
blockSize1 = jmin (bufferSize - startIndex1, numToWrite);
|
||||
numToWrite -= blockSize1;
|
||||
blockSize2 = numToWrite <= 0 ? 0 : jmin (numToWrite, (int) (vs % bufferSize));
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractFifo::finishedWrite (int numWritten) throw()
|
||||
{
|
||||
jassert (numWritten >= 0 && numWritten < bufferSize);
|
||||
validEnd += numWritten;
|
||||
}
|
||||
|
||||
void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) throw()
|
||||
{
|
||||
const int vs = validStart.get();
|
||||
const int ve = validEnd.get();
|
||||
|
||||
const int numReady = ve - vs;
|
||||
numWanted = jmin (numWanted, numReady);
|
||||
|
||||
if (numWanted <= 0)
|
||||
{
|
||||
startIndex1 = 0;
|
||||
startIndex2 = 0;
|
||||
blockSize1 = 0;
|
||||
blockSize2 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
startIndex1 = (int) (vs % bufferSize);
|
||||
startIndex2 = 0;
|
||||
blockSize1 = jmin (bufferSize - startIndex1, numWanted);
|
||||
numWanted -= blockSize1;
|
||||
blockSize2 = numWanted <= 0 ? 0 : jmin (numWanted, (int) (ve % bufferSize));
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractFifo::finishedRead (int numRead) throw()
|
||||
{
|
||||
jassert (numRead >= 0 && numRead < bufferSize);
|
||||
validStart += numRead;
|
||||
}
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
/*** End of inlined file: juce_AbstractFifo.cpp ***/
|
||||
|
||||
|
||||
/*** Start of inlined file: juce_BigInteger.cpp ***/
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
|
|
@ -20755,7 +20849,7 @@ public:
|
|||
{
|
||||
switch (bitsPerSample)
|
||||
{
|
||||
case 8: ReadHelper<AudioData::Int32, AudioData::Int8, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 8: ReadHelper<AudioData::Int32, AudioData::Int8, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 16: ReadHelper<AudioData::Int32, AudioData::Int16, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 24: ReadHelper<AudioData::Int32, AudioData::Int24, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 32: ReadHelper<AudioData::Int32, AudioData::Int32, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
|
|
@ -20766,7 +20860,7 @@ public:
|
|||
{
|
||||
switch (bitsPerSample)
|
||||
{
|
||||
case 8: ReadHelper<AudioData::Int32, AudioData::Int8, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 8: ReadHelper<AudioData::Int32, AudioData::Int8, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 16: ReadHelper<AudioData::Int32, AudioData::Int16, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 24: ReadHelper<AudioData::Int32, AudioData::Int24, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 32: ReadHelper<AudioData::Int32, AudioData::Int32, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
|
|
@ -21007,6 +21101,37 @@ END_JUCE_NAMESPACE
|
|||
/*** Start of inlined file: juce_AudioFormat.cpp ***/
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
AudioFormat::AudioFormat (const String& name, const StringArray& extensions)
|
||||
: formatName (name),
|
||||
fileExtensions (extensions)
|
||||
{
|
||||
}
|
||||
|
||||
AudioFormat::~AudioFormat()
|
||||
{
|
||||
}
|
||||
|
||||
bool AudioFormat::canHandleFile (const File& f)
|
||||
{
|
||||
for (int i = 0; i < fileExtensions.size(); ++i)
|
||||
if (f.hasFileExtension (fileExtensions[i]))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const String& AudioFormat::getFormatName() const { return formatName; }
|
||||
const StringArray& AudioFormat::getFileExtensions() const { return fileExtensions; }
|
||||
bool AudioFormat::isCompressed() { return false; }
|
||||
const StringArray AudioFormat::getQualityOptions() { return StringArray(); }
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
/*** End of inlined file: juce_AudioFormat.cpp ***/
|
||||
|
||||
|
||||
/*** Start of inlined file: juce_AudioFormatReader.cpp ***/
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
AudioFormatReader::AudioFormatReader (InputStream* const in,
|
||||
const String& formatName_)
|
||||
: sampleRate (0),
|
||||
|
|
@ -21338,6 +21463,13 @@ int64 AudioFormatReader::searchForLevel (int64 startSample,
|
|||
return -1;
|
||||
}
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
/*** End of inlined file: juce_AudioFormatReader.cpp ***/
|
||||
|
||||
|
||||
/*** Start of inlined file: juce_AudioFormatWriter.cpp ***/
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
AudioFormatWriter::AudioFormatWriter (OutputStream* const out,
|
||||
const String& formatName_,
|
||||
const double rate,
|
||||
|
|
@ -21424,16 +21556,9 @@ bool AudioFormatWriter::writeFromAudioReader (AudioFormatReader& reader,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool AudioFormatWriter::writeFromAudioSource (AudioSource& source,
|
||||
int numSamplesToRead,
|
||||
const int samplesPerBlock)
|
||||
bool AudioFormatWriter::writeFromAudioSource (AudioSource& source, int numSamplesToRead, const int samplesPerBlock)
|
||||
{
|
||||
AudioSampleBuffer tempBuffer (getNumChannels(), samplesPerBlock);
|
||||
int* buffers [128];
|
||||
zerostruct (buffers);
|
||||
|
||||
for (int i = tempBuffer.getNumChannels(); --i >= 0;)
|
||||
buffers[i] = reinterpret_cast<int*> (tempBuffer.getSampleData (i, 0));
|
||||
|
||||
while (numSamplesToRead > 0)
|
||||
{
|
||||
|
|
@ -21447,30 +21572,7 @@ bool AudioFormatWriter::writeFromAudioSource (AudioSource& source,
|
|||
|
||||
source.getNextAudioBlock (info);
|
||||
|
||||
if (! isFloatingPoint())
|
||||
{
|
||||
int** bufferChan = buffers;
|
||||
|
||||
while (*bufferChan != 0)
|
||||
{
|
||||
int* b = *bufferChan++;
|
||||
|
||||
// float -> int
|
||||
for (int j = numToDo; --j >= 0;)
|
||||
{
|
||||
const double samp = *(const float*) b;
|
||||
|
||||
if (samp <= -1.0)
|
||||
*b++ = std::numeric_limits<int>::min();
|
||||
else if (samp >= 1.0)
|
||||
*b++ = std::numeric_limits<int>::max();
|
||||
else
|
||||
*b++ = roundToInt (std::numeric_limits<int>::max() * samp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! write ((const int**) buffers, numToDo))
|
||||
if (! writeFromAudioSampleBuffer (tempBuffer, 0, numToDo))
|
||||
return false;
|
||||
|
||||
numSamplesToRead -= numToDo;
|
||||
|
|
@ -21479,48 +21581,131 @@ bool AudioFormatWriter::writeFromAudioSource (AudioSource& source,
|
|||
return true;
|
||||
}
|
||||
|
||||
AudioFormat::AudioFormat (const String& name,
|
||||
const StringArray& extensions)
|
||||
: formatName (name),
|
||||
fileExtensions (extensions)
|
||||
bool AudioFormatWriter::writeFromAudioSampleBuffer (const AudioSampleBuffer& source, int startSample, int numSamples)
|
||||
{
|
||||
jassert (startSample >= 0 && startSample + numSamples <= source.getNumSamples() && source.getNumChannels() > 0);
|
||||
|
||||
if (numSamples <= 0)
|
||||
return true;
|
||||
|
||||
HeapBlock<int> tempBuffer;
|
||||
HeapBlock<int*> chans (numChannels + 1);
|
||||
chans [numChannels] = 0;
|
||||
|
||||
if (isFloatingPoint())
|
||||
{
|
||||
for (int i = numChannels; --i >= 0;)
|
||||
chans[i] = reinterpret_cast<int*> (source.getSampleData (i, startSample));
|
||||
}
|
||||
else
|
||||
{
|
||||
tempBuffer.malloc (numSamples * numChannels);
|
||||
|
||||
for (unsigned int i = 0; i < numChannels; ++i)
|
||||
{
|
||||
typedef AudioData::Pointer <AudioData::Int32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> DestSampleType;
|
||||
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> SourceSampleType;
|
||||
|
||||
DestSampleType destData (chans[i] = tempBuffer + i * numSamples);
|
||||
SourceSampleType sourceData (source.getSampleData (i, startSample));
|
||||
destData.convertSamples (sourceData, numSamples);
|
||||
}
|
||||
}
|
||||
|
||||
return write ((const int**) chans.getData(), numSamples);
|
||||
}
|
||||
|
||||
AudioFormat::~AudioFormat()
|
||||
class AudioFormatWriter::ThreadedWriter::Buffer : public TimeSliceClient,
|
||||
public AbstractFifo
|
||||
{
|
||||
}
|
||||
public:
|
||||
Buffer (TimeSliceThread& timeSliceThread_, AudioFormatWriter* writer_, int numChannels, int bufferSize)
|
||||
: AbstractFifo (bufferSize),
|
||||
buffer (numChannels, bufferSize),
|
||||
timeSliceThread (timeSliceThread_),
|
||||
writer (writer_), isRunning (true)
|
||||
{
|
||||
timeSliceThread.addTimeSliceClient (this);
|
||||
}
|
||||
|
||||
const String& AudioFormat::getFormatName() const
|
||||
{
|
||||
return formatName;
|
||||
}
|
||||
~Buffer()
|
||||
{
|
||||
isRunning = false;
|
||||
timeSliceThread.removeTimeSliceClient (this);
|
||||
|
||||
const StringArray& AudioFormat::getFileExtensions() const
|
||||
{
|
||||
return fileExtensions;
|
||||
}
|
||||
while (useTimeSlice())
|
||||
{}
|
||||
}
|
||||
|
||||
bool AudioFormat::canHandleFile (const File& f)
|
||||
{
|
||||
for (int i = 0; i < fileExtensions.size(); ++i)
|
||||
if (f.hasFileExtension (fileExtensions[i]))
|
||||
bool write (const float** data, int numSamples)
|
||||
{
|
||||
if (numSamples <= 0 || ! isRunning)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
jassert (timeSliceThread.isThreadRunning()); // you need to get your thread running before pumping data into this!
|
||||
|
||||
int start1, size1, start2, size2;
|
||||
prepareToWrite (numSamples, start1, size1, start2, size2);
|
||||
|
||||
if (size1 + size2 < numSamples)
|
||||
return false;
|
||||
|
||||
for (int i = buffer.getNumChannels(); --i >= 0;)
|
||||
{
|
||||
buffer.copyFrom (i, start1, data[i], size1);
|
||||
buffer.copyFrom (i, start2, data[i] + size1, size2);
|
||||
}
|
||||
|
||||
finishedWrite (size1 + size2);
|
||||
timeSliceThread.notify();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool useTimeSlice()
|
||||
{
|
||||
const int numToDo = getTotalSize() / 4;
|
||||
|
||||
int start1, size1, start2, size2;
|
||||
prepareToRead (numToDo, start1, size1, start2, size2);
|
||||
|
||||
if (size1 <= 0)
|
||||
return false;
|
||||
|
||||
writer->writeFromAudioSampleBuffer (buffer, start1, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
writer->writeFromAudioSampleBuffer (buffer, start2, size2);
|
||||
|
||||
finishedRead (size1 + size2);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
AudioSampleBuffer buffer;
|
||||
TimeSliceThread& timeSliceThread;
|
||||
ScopedPointer<AudioFormatWriter> writer;
|
||||
volatile bool isRunning;
|
||||
|
||||
Buffer (const Buffer&);
|
||||
Buffer& operator= (const Buffer&);
|
||||
};
|
||||
|
||||
AudioFormatWriter::ThreadedWriter::ThreadedWriter (AudioFormatWriter* writer, TimeSliceThread& backgroundThread, int numSamplesToBuffer)
|
||||
: buffer (new AudioFormatWriter::ThreadedWriter::Buffer (backgroundThread, writer, writer->numChannels, numSamplesToBuffer))
|
||||
{
|
||||
}
|
||||
|
||||
bool AudioFormat::isCompressed()
|
||||
AudioFormatWriter::ThreadedWriter::~ThreadedWriter()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const StringArray AudioFormat::getQualityOptions()
|
||||
bool AudioFormatWriter::ThreadedWriter::write (const float** data, int numSamples)
|
||||
{
|
||||
return StringArray();
|
||||
return buffer->write (data, numSamples);
|
||||
}
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
/*** End of inlined file: juce_AudioFormat.cpp ***/
|
||||
/*** End of inlined file: juce_AudioFormatWriter.cpp ***/
|
||||
|
||||
|
||||
/*** Start of inlined file: juce_AudioFormatManager.cpp ***/
|
||||
|
|
@ -22668,25 +22853,11 @@ QuickTimeAudioFormat::~QuickTimeAudioFormat()
|
|||
{
|
||||
}
|
||||
|
||||
const Array <int> QuickTimeAudioFormat::getPossibleSampleRates()
|
||||
{
|
||||
return Array<int>();
|
||||
}
|
||||
const Array <int> QuickTimeAudioFormat::getPossibleSampleRates() { return Array<int>(); }
|
||||
const Array <int> QuickTimeAudioFormat::getPossibleBitDepths() { return Array<int>(); }
|
||||
|
||||
const Array <int> QuickTimeAudioFormat::getPossibleBitDepths()
|
||||
{
|
||||
return Array<int>();
|
||||
}
|
||||
|
||||
bool QuickTimeAudioFormat::canDoStereo()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QuickTimeAudioFormat::canDoMono()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool QuickTimeAudioFormat::canDoStereo() { return true; }
|
||||
bool QuickTimeAudioFormat::canDoMono() { return true; }
|
||||
|
||||
AudioFormatReader* QuickTimeAudioFormat::createReaderFor (InputStream* sourceStream,
|
||||
const bool deleteStreamIfOpeningFails)
|
||||
|
|
@ -27314,45 +27485,8 @@ void AudioSampleBuffer::writeToAudioWriter (AudioFormatWriter* writer,
|
|||
const int startSample,
|
||||
const int numSamples) const
|
||||
{
|
||||
jassert (startSample >= 0 && startSample + numSamples <= size && numChannels > 0);
|
||||
|
||||
if (numSamples > 0)
|
||||
{
|
||||
HeapBlock<int> tempBuffer;
|
||||
HeapBlock<int*> chans (numChannels + 1);
|
||||
chans [numChannels] = 0;
|
||||
|
||||
if (writer->isFloatingPoint())
|
||||
{
|
||||
for (int i = numChannels; --i >= 0;)
|
||||
chans[i] = reinterpret_cast<int*> (channels[i] + startSample);
|
||||
}
|
||||
else
|
||||
{
|
||||
tempBuffer.malloc (numSamples * numChannels);
|
||||
|
||||
for (int j = 0; j < numChannels; ++j)
|
||||
{
|
||||
int* const dest = tempBuffer + j * numSamples;
|
||||
const float* const src = channels[j] + startSample;
|
||||
chans[j] = dest;
|
||||
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
const double samp = src[i];
|
||||
|
||||
if (samp <= -1.0)
|
||||
dest[i] = std::numeric_limits<int>::min();
|
||||
else if (samp >= 1.0)
|
||||
dest[i] = std::numeric_limits<int>::max();
|
||||
else
|
||||
dest[i] = roundToInt (std::numeric_limits<int>::max() * samp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writer->write ((const int**) chans.getData(), numSamples);
|
||||
}
|
||||
jassert (writer != 0);
|
||||
writer->writeFromAudioSampleBuffer (*this, startSample, numSamples);
|
||||
}
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
@ -69046,8 +69180,6 @@ public:
|
|||
menuCreationTime = lastFocused = lastScroll = Time::getMillisecondCounter();
|
||||
setWantsKeyboardFocus (true);
|
||||
setMouseClickGrabsKeyboardFocus (false);
|
||||
|
||||
setOpaque (true);
|
||||
setAlwaysOnTop (true);
|
||||
|
||||
Desktop::getInstance().addGlobalMouseListener (this);
|
||||
|
|
@ -69086,6 +69218,7 @@ public:
|
|||
ScopedPointer <Window> mw (new Window());
|
||||
mw->setLookAndFeel (menu.lookAndFeel);
|
||||
mw->setWantsKeyboardFocus (false);
|
||||
mw->setOpaque (mw->getLookAndFeel().findColour (PopupMenu::backgroundColourId).isOpaque() || ! Desktop::canUseSemiTransparentWindows());
|
||||
mw->minimumWidth = minimumWidth;
|
||||
mw->maximumNumColumns = maximumNumColumns;
|
||||
mw->standardItemHeight = standardItemHeight;
|
||||
|
|
@ -69131,6 +69264,9 @@ public:
|
|||
|
||||
void paint (Graphics& g)
|
||||
{
|
||||
if (isOpaque())
|
||||
g.fillAll (Colours::white);
|
||||
|
||||
getLookAndFeel().drawPopupMenuBackground (g, getWidth(), getHeight());
|
||||
}
|
||||
|
||||
|
|
@ -128589,18 +128725,17 @@ class FlacWriter : public AudioFormatWriter
|
|||
{
|
||||
public:
|
||||
|
||||
FlacWriter (OutputStream* const out,
|
||||
const double sampleRate_,
|
||||
const int numChannels_,
|
||||
const int bitsPerSample_)
|
||||
FlacWriter (OutputStream* const out, double sampleRate_,
|
||||
int numChannels_, int bitsPerSample_, int qualityOptionIndex)
|
||||
: AudioFormatWriter (out, TRANS (flacFormatName),
|
||||
sampleRate_,
|
||||
numChannels_,
|
||||
bitsPerSample_)
|
||||
sampleRate_, numChannels_, bitsPerSample_)
|
||||
{
|
||||
using namespace FlacNamespace;
|
||||
encoder = FLAC__stream_encoder_new();
|
||||
|
||||
if (qualityOptionIndex > 0)
|
||||
FLAC__stream_encoder_set_compression_level (encoder, jmin (8, qualityOptionIndex));
|
||||
|
||||
FLAC__stream_encoder_set_do_mid_side_stereo (encoder, numChannels == 2);
|
||||
FLAC__stream_encoder_set_loose_mid_side_stereo (encoder, numChannels == 2);
|
||||
FLAC__stream_encoder_set_channels (encoder, numChannels);
|
||||
|
|
@ -128780,20 +128915,9 @@ const Array <int> FlacAudioFormat::getPossibleBitDepths()
|
|||
return Array <int> (depths);
|
||||
}
|
||||
|
||||
bool FlacAudioFormat::canDoStereo()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FlacAudioFormat::canDoMono()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FlacAudioFormat::isCompressed()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool FlacAudioFormat::canDoStereo() { return true; }
|
||||
bool FlacAudioFormat::canDoMono() { return true; }
|
||||
bool FlacAudioFormat::isCompressed() { return true; }
|
||||
|
||||
AudioFormatReader* FlacAudioFormat::createReaderFor (InputStream* in,
|
||||
const bool deleteStreamIfOpeningFails)
|
||||
|
|
@ -128814,11 +128938,11 @@ AudioFormatWriter* FlacAudioFormat::createWriterFor (OutputStream* out,
|
|||
unsigned int numberOfChannels,
|
||||
int bitsPerSample,
|
||||
const StringPairArray& /*metadataValues*/,
|
||||
int /*qualityOptionIndex*/)
|
||||
int qualityOptionIndex)
|
||||
{
|
||||
if (getPossibleBitDepths().contains (bitsPerSample))
|
||||
{
|
||||
ScopedPointer<FlacWriter> w (new FlacWriter (out, sampleRate, numberOfChannels, bitsPerSample));
|
||||
ScopedPointer<FlacWriter> w (new FlacWriter (out, sampleRate, numberOfChannels, bitsPerSample, qualityOptionIndex));
|
||||
|
||||
if (w->ok)
|
||||
return w.release();
|
||||
|
|
@ -187791,20 +187915,13 @@ const Array <int> OggVorbisAudioFormat::getPossibleSampleRates()
|
|||
|
||||
const Array <int> OggVorbisAudioFormat::getPossibleBitDepths()
|
||||
{
|
||||
Array <int> depths;
|
||||
depths.add (32);
|
||||
return depths;
|
||||
const int depths[] = { 32, 0 };
|
||||
return Array <int> (depths);
|
||||
}
|
||||
|
||||
bool OggVorbisAudioFormat::canDoStereo()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OggVorbisAudioFormat::canDoMono()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool OggVorbisAudioFormat::canDoStereo() { return true; }
|
||||
bool OggVorbisAudioFormat::canDoMono() { return true; }
|
||||
bool OggVorbisAudioFormat::isCompressed() { return true; }
|
||||
|
||||
AudioFormatReader* OggVorbisAudioFormat::createReaderFor (InputStream* in,
|
||||
const bool deleteStreamIfOpeningFails)
|
||||
|
|
@ -187836,11 +187953,6 @@ AudioFormatWriter* OggVorbisAudioFormat::createWriterFor (OutputStream* out,
|
|||
return w->ok ? w.release() : 0;
|
||||
}
|
||||
|
||||
bool OggVorbisAudioFormat::isCompressed()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const StringArray OggVorbisAudioFormat::getQualityOptions()
|
||||
{
|
||||
StringArray s;
|
||||
|
|
@ -242900,6 +243012,7 @@ private:
|
|||
return 0;
|
||||
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
doMouseEvent (getCurrentMousePos());
|
||||
handleMovedOrResized();
|
||||
|
||||
if (dontRepaint)
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@
|
|||
*/
|
||||
#define JUCE_MAJOR_VERSION 1
|
||||
#define JUCE_MINOR_VERSION 52
|
||||
#define JUCE_BUILDNUMBER 70
|
||||
#define JUCE_BUILDNUMBER 71
|
||||
|
||||
/** Current Juce version number.
|
||||
|
||||
|
|
@ -2761,6 +2761,534 @@ BEGIN_JUCE_NAMESPACE
|
|||
#ifndef __JUCE_JUCE_CORE_INCLUDES_INCLUDEFILES__
|
||||
#define __JUCE_JUCE_CORE_INCLUDES_INCLUDEFILES__
|
||||
|
||||
#ifndef __JUCE_ABSTRACTFIFO_JUCEHEADER__
|
||||
|
||||
/*** Start of inlined file: juce_AbstractFifo.h ***/
|
||||
#ifndef __JUCE_ABSTRACTFIFO_JUCEHEADER__
|
||||
#define __JUCE_ABSTRACTFIFO_JUCEHEADER__
|
||||
|
||||
|
||||
/*** Start of inlined file: juce_Atomic.h ***/
|
||||
#ifndef __JUCE_ATOMIC_JUCEHEADER__
|
||||
#define __JUCE_ATOMIC_JUCEHEADER__
|
||||
|
||||
/**
|
||||
Simple class to hold a primitive value and perform atomic operations on it.
|
||||
|
||||
The type used must be a 32 or 64 bit primitive, like an int, pointer, etc.
|
||||
There are methods to perform most of the basic atomic operations.
|
||||
*/
|
||||
template <typename Type>
|
||||
class Atomic
|
||||
{
|
||||
public:
|
||||
/** Creates a new value, initialised to zero. */
|
||||
inline Atomic() throw()
|
||||
: value (0)
|
||||
{
|
||||
}
|
||||
|
||||
/** Creates a new value, with a given initial value. */
|
||||
inline Atomic (const Type initialValue) throw()
|
||||
: value (initialValue)
|
||||
{
|
||||
}
|
||||
|
||||
/** Copies another value (atomically). */
|
||||
inline Atomic (const Atomic& other) throw()
|
||||
: value (other.get())
|
||||
{
|
||||
}
|
||||
|
||||
/** Destructor. */
|
||||
inline ~Atomic() throw()
|
||||
{
|
||||
// This class can only be used for types which are 32 or 64 bits in size.
|
||||
static_jassert (sizeof (Type) == 4 || sizeof (Type) == 8);
|
||||
}
|
||||
|
||||
/** Atomically reads and returns the current value. */
|
||||
Type get() const throw();
|
||||
|
||||
/** Copies another value onto this one (atomically). */
|
||||
inline Atomic& operator= (const Atomic& other) throw() { exchange (other.get()); return *this; }
|
||||
|
||||
/** Copies another value onto this one (atomically). */
|
||||
inline Atomic& operator= (const Type newValue) throw() { exchange (newValue); return *this; }
|
||||
|
||||
/** Atomically sets the current value. */
|
||||
void set (Type newValue) throw() { exchange (newValue); }
|
||||
|
||||
/** Atomically sets the current value, returning the value that was replaced. */
|
||||
Type exchange (Type value) throw();
|
||||
|
||||
/** Atomically adds a number to this value, returning the new value. */
|
||||
Type operator+= (Type amountToAdd) throw();
|
||||
|
||||
/** Atomically subtracts a number from this value, returning the new value. */
|
||||
Type operator-= (Type amountToSubtract) throw();
|
||||
|
||||
/** Atomically increments this value, returning the new value. */
|
||||
Type operator++() throw();
|
||||
|
||||
/** Atomically decrements this value, returning the new value. */
|
||||
Type operator--() throw();
|
||||
|
||||
/** Atomically compares this value with a target value, and if it is equal, sets
|
||||
this to be equal to a new value.
|
||||
|
||||
This operation is the atomic equivalent of doing this:
|
||||
@code
|
||||
bool compareAndSetBool (Type newValue, Type valueToCompare)
|
||||
{
|
||||
if (get() == valueToCompare)
|
||||
{
|
||||
set (newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@endcode
|
||||
|
||||
@returns true if the comparison was true and the value was replaced; false if
|
||||
the comparison failed and the value was left unchanged.
|
||||
@see compareAndSetValue
|
||||
*/
|
||||
bool compareAndSetBool (Type newValue, Type valueToCompare) throw();
|
||||
|
||||
/** Atomically compares this value with a target value, and if it is equal, sets
|
||||
this to be equal to a new value.
|
||||
|
||||
This operation is the atomic equivalent of doing this:
|
||||
@code
|
||||
Type compareAndSetValue (Type newValue, Type valueToCompare)
|
||||
{
|
||||
Type oldValue = get();
|
||||
if (oldValue == valueToCompare)
|
||||
set (newValue);
|
||||
|
||||
return oldValue;
|
||||
}
|
||||
@endcode
|
||||
|
||||
@returns the old value before it was changed.
|
||||
@see compareAndSetBool
|
||||
*/
|
||||
Type compareAndSetValue (Type newValue, Type valueToCompare) throw();
|
||||
|
||||
/** Implements a memory read/write barrier. */
|
||||
static void memoryBarrier() throw();
|
||||
|
||||
JUCE_ALIGN(8)
|
||||
|
||||
/** The raw value that this class operates on.
|
||||
This is exposed publically in case you need to manipulate it directly
|
||||
for performance reasons.
|
||||
*/
|
||||
volatile Type value;
|
||||
|
||||
private:
|
||||
static inline Type castFrom32Bit (int32 value) throw() { return *(Type*) &value; }
|
||||
static inline Type castFrom64Bit (int64 value) throw() { return *(Type*) &value; }
|
||||
static inline int32 castTo32Bit (Type value) throw() { return *(int32*) &value; }
|
||||
static inline int64 castTo64Bit (Type value) throw() { return *(int64*) &value; }
|
||||
};
|
||||
|
||||
/*
|
||||
The following code is in the header so that the atomics can be inlined where possible...
|
||||
*/
|
||||
#if (JUCE_IOS && (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_3_2 || ! defined (__IPHONE_3_2))) \
|
||||
|| (JUCE_MAC && (JUCE_PPC || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)))
|
||||
#define JUCE_ATOMICS_MAC 1 // Older OSX builds using gcc4.1 or earlier
|
||||
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
|
||||
#define JUCE_MAC_ATOMICS_VOLATILE
|
||||
#else
|
||||
#define JUCE_MAC_ATOMICS_VOLATILE volatile
|
||||
#endif
|
||||
|
||||
#if JUCE_PPC || JUCE_IOS
|
||||
// None of these atomics are available for PPC or for iPhoneOS 3.1 or earlier!!
|
||||
template <typename Type> static Type OSAtomicAdd64Barrier (Type b, JUCE_MAC_ATOMICS_VOLATILE Type* a) throw() { jassertfalse; return *a += b; }
|
||||
template <typename Type> static Type OSAtomicIncrement64Barrier (JUCE_MAC_ATOMICS_VOLATILE Type* a) throw() { jassertfalse; return ++*a; }
|
||||
template <typename Type> static Type OSAtomicDecrement64Barrier (JUCE_MAC_ATOMICS_VOLATILE Type* a) throw() { jassertfalse; return --*a; }
|
||||
template <typename Type> static bool OSAtomicCompareAndSwap64Barrier (Type old, Type newValue, JUCE_MAC_ATOMICS_VOLATILE Type* value) throw()
|
||||
{ jassertfalse; if (old == *value) { *value = newValue; return true; } return false; }
|
||||
#define JUCE_64BIT_ATOMICS_UNAVAILABLE 1
|
||||
#endif
|
||||
|
||||
#elif JUCE_GCC
|
||||
#define JUCE_ATOMICS_GCC 1 // GCC with intrinsics
|
||||
|
||||
#if JUCE_IOS
|
||||
#define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 // (on the iphone, the 64-bit ops will compile but not link)
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define JUCE_ATOMICS_WINDOWS 1 // Windows with intrinsics
|
||||
|
||||
#if JUCE_USE_INTRINSICS || JUCE_64BIT
|
||||
#pragma intrinsic (_InterlockedExchange, _InterlockedIncrement, _InterlockedDecrement, _InterlockedCompareExchange, \
|
||||
_InterlockedCompareExchange64, _InterlockedExchangeAdd, _ReadWriteBarrier)
|
||||
#define juce_InterlockedExchange(a, b) _InterlockedExchange(a, b)
|
||||
#define juce_InterlockedIncrement(a) _InterlockedIncrement(a)
|
||||
#define juce_InterlockedDecrement(a) _InterlockedDecrement(a)
|
||||
#define juce_InterlockedExchangeAdd(a, b) _InterlockedExchangeAdd(a, b)
|
||||
#define juce_InterlockedCompareExchange(a, b, c) _InterlockedCompareExchange(a, b, c)
|
||||
#define juce_InterlockedCompareExchange64(a, b, c) _InterlockedCompareExchange64(a, b, c)
|
||||
#define juce_MemoryBarrier _ReadWriteBarrier
|
||||
#else
|
||||
// (these are defined in juce_win32_Threads.cpp)
|
||||
long juce_InterlockedExchange (volatile long* a, long b) throw();
|
||||
long juce_InterlockedIncrement (volatile long* a) throw();
|
||||
long juce_InterlockedDecrement (volatile long* a) throw();
|
||||
long juce_InterlockedExchangeAdd (volatile long* a, long b) throw();
|
||||
long juce_InterlockedCompareExchange (volatile long* a, long b, long c) throw();
|
||||
__int64 juce_InterlockedCompareExchange64 (volatile __int64* a, __int64 b, __int64 c) throw();
|
||||
void juce_MemoryBarrier() throw() { long x = 0; juce_InterlockedIncrement (&x); }
|
||||
#endif
|
||||
|
||||
#if JUCE_64BIT
|
||||
#pragma intrinsic (_InterlockedExchangeAdd64, _InterlockedExchange64, _InterlockedIncrement64, _InterlockedDecrement64)
|
||||
#define juce_InterlockedExchangeAdd64(a, b) _InterlockedExchangeAdd64(a, b)
|
||||
#define juce_InterlockedExchange64(a, b) _InterlockedExchange64(a, b)
|
||||
#define juce_InterlockedIncrement64(a) _InterlockedIncrement64(a)
|
||||
#define juce_InterlockedDecrement64(a) _InterlockedDecrement64(a)
|
||||
#else
|
||||
// None of these atomics are available in a 32-bit Windows build!!
|
||||
template <typename Type> static Type juce_InterlockedExchangeAdd64 (volatile Type* a, Type b) throw() { jassertfalse; Type old = *a; *a += b; return old; }
|
||||
template <typename Type> static Type juce_InterlockedExchange64 (volatile Type* a, Type b) throw() { jassertfalse; Type old = *a; *a = b; return old; }
|
||||
template <typename Type> static Type juce_InterlockedIncrement64 (volatile Type* a) throw() { jassertfalse; return ++*a; }
|
||||
template <typename Type> static Type juce_InterlockedDecrement64 (volatile Type* a) throw() { jassertfalse; return --*a; }
|
||||
#define JUCE_64BIT_ATOMICS_UNAVAILABLE 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if JUCE_MSVC
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4311) // (truncation warning)
|
||||
#endif
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::get() const throw()
|
||||
{
|
||||
#if JUCE_ATOMICS_MAC
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((int32) OSAtomicAdd32Barrier ((int32_t) 0, (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value))
|
||||
: castFrom64Bit ((int64) OSAtomicAdd64Barrier ((int64_t) 0, (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value));
|
||||
#elif JUCE_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedExchangeAdd ((volatile long*) &value, (long) 0))
|
||||
: castFrom64Bit ((int64) juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) 0));
|
||||
#elif JUCE_ATOMICS_GCC
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_add_and_fetch ((volatile int32*) &value, 0))
|
||||
: castFrom64Bit ((int64) __sync_add_and_fetch ((volatile int64*) &value, 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::exchange (const Type newValue) throw()
|
||||
{
|
||||
#if JUCE_ATOMICS_MAC || JUCE_ATOMICS_GCC
|
||||
Type currentVal = value;
|
||||
while (! compareAndSetBool (newValue, currentVal)) { currentVal = value; }
|
||||
return currentVal;
|
||||
#elif JUCE_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedExchange ((volatile long*) &value, (long) castTo32Bit (newValue)))
|
||||
: castFrom64Bit ((int64) juce_InterlockedExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::operator+= (const Type amountToAdd) throw()
|
||||
{
|
||||
#if JUCE_ATOMICS_MAC
|
||||
return sizeof (Type) == 4 ? (Type) OSAtomicAdd32Barrier ((int32_t) castTo32Bit (amountToAdd), (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||
: (Type) OSAtomicAdd64Barrier ((int64_t) amountToAdd, (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||
#elif JUCE_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? (Type) (juce_InterlockedExchangeAdd ((volatile long*) &value, (long) amountToAdd) + (long) amountToAdd)
|
||||
: (Type) (juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) amountToAdd) + (__int64) amountToAdd);
|
||||
#elif JUCE_ATOMICS_GCC
|
||||
return (Type) __sync_add_and_fetch (&value, amountToAdd);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::operator-= (const Type amountToSubtract) throw()
|
||||
{
|
||||
return operator+= (juce_negate (amountToSubtract));
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::operator++() throw()
|
||||
{
|
||||
#if JUCE_ATOMICS_MAC
|
||||
return sizeof (Type) == 4 ? (Type) OSAtomicIncrement32Barrier ((JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||
: (Type) OSAtomicIncrement64Barrier ((JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||
#elif JUCE_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? (Type) juce_InterlockedIncrement ((volatile long*) &value)
|
||||
: (Type) juce_InterlockedIncrement64 ((volatile __int64*) &value);
|
||||
#elif JUCE_ATOMICS_GCC
|
||||
return (Type) __sync_add_and_fetch (&value, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::operator--() throw()
|
||||
{
|
||||
#if JUCE_ATOMICS_MAC
|
||||
return sizeof (Type) == 4 ? (Type) OSAtomicDecrement32Barrier ((JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||
: (Type) OSAtomicDecrement64Barrier ((JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||
#elif JUCE_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? (Type) juce_InterlockedDecrement ((volatile long*) &value)
|
||||
: (Type) juce_InterlockedDecrement64 ((volatile __int64*) &value);
|
||||
#elif JUCE_ATOMICS_GCC
|
||||
return (Type) __sync_add_and_fetch (&value, -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline bool Atomic<Type>::compareAndSetBool (const Type newValue, const Type valueToCompare) throw()
|
||||
{
|
||||
#if JUCE_ATOMICS_MAC
|
||||
return sizeof (Type) == 4 ? OSAtomicCompareAndSwap32Barrier ((int32_t) castTo32Bit (valueToCompare), (int32_t) castTo32Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||
: OSAtomicCompareAndSwap64Barrier ((int64_t) castTo64Bit (valueToCompare), (int64_t) castTo64Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||
#elif JUCE_ATOMICS_WINDOWS
|
||||
return compareAndSetValue (newValue, valueToCompare) == valueToCompare;
|
||||
#elif JUCE_ATOMICS_GCC
|
||||
return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))
|
||||
: __sync_bool_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::compareAndSetValue (const Type newValue, const Type valueToCompare) throw()
|
||||
{
|
||||
#if JUCE_ATOMICS_MAC
|
||||
for (;;) // Annoying workaround for OSX only having a bool CAS operation..
|
||||
{
|
||||
if (compareAndSetBool (newValue, valueToCompare))
|
||||
return valueToCompare;
|
||||
|
||||
const Type result = value;
|
||||
if (result != valueToCompare)
|
||||
return result;
|
||||
}
|
||||
|
||||
#elif JUCE_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedCompareExchange ((volatile long*) &value, (long) castTo32Bit (newValue), (long) castTo32Bit (valueToCompare)))
|
||||
: castFrom64Bit ((int64) juce_InterlockedCompareExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue), (__int64) castTo64Bit (valueToCompare)));
|
||||
#elif JUCE_ATOMICS_GCC
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_val_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue)))
|
||||
: castFrom64Bit ((int64) __sync_val_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline void Atomic<Type>::memoryBarrier() throw()
|
||||
{
|
||||
#if JUCE_ATOMICS_MAC
|
||||
OSMemoryBarrier();
|
||||
#elif JUCE_ATOMICS_GCC
|
||||
__sync_synchronize();
|
||||
#elif JUCE_ATOMICS_WINDOWS
|
||||
juce_MemoryBarrier();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if JUCE_MSVC
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // __JUCE_ATOMIC_JUCEHEADER__
|
||||
/*** End of inlined file: juce_Atomic.h ***/
|
||||
|
||||
/**
|
||||
Encapsulates the logic required to implement a lock-free FIFO.
|
||||
|
||||
This class handles the logic needed when building a single-reader, single-writer FIFO.
|
||||
|
||||
It doesn't actually hold any data itself, but your FIFO class can use one of these to manage
|
||||
its position and status when reading or writing to it.
|
||||
|
||||
To use it, you can call prepareToWrite() to determine the position within your own buffer that
|
||||
an incoming block of data should be stored, and prepareToRead() to find out when the next
|
||||
outgoing block should be read from.
|
||||
|
||||
e.g.
|
||||
@code
|
||||
class MyFifo
|
||||
{
|
||||
public:
|
||||
MyFifo() : abstractFifo (1024)
|
||||
{
|
||||
}
|
||||
|
||||
void addToFifo (const int* someData, int numItems)
|
||||
{
|
||||
int start1, size1, start2, size2;
|
||||
prepareToWrite (numItems, start1, size1, start2, size2);
|
||||
|
||||
if (size1 > 0)
|
||||
copySomeData (myBuffer + start1, someData, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (myBuffer + start2, someData + size1, size2);
|
||||
|
||||
finishedWrite (size1 + size2);
|
||||
}
|
||||
|
||||
void readFromFifo (int* someData, int numItems)
|
||||
{
|
||||
int start1, size1, start2, size2;
|
||||
prepareToRead (numSamples, start1, size1, start2, size2);
|
||||
|
||||
if (size1 > 0)
|
||||
copySomeData (someData, myBuffer + start1, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (someData + size1, myBuffer + start2, size2);
|
||||
|
||||
finishedRead (size1 + size2);
|
||||
}
|
||||
|
||||
private:
|
||||
AbstractFifo abstractFifo;
|
||||
int myBuffer [1024];
|
||||
};
|
||||
@endcode
|
||||
*/
|
||||
class JUCE_API AbstractFifo
|
||||
{
|
||||
public:
|
||||
|
||||
/** Creates a FIFO to manage a buffer with the specified capacity. */
|
||||
AbstractFifo (int capacity) throw();
|
||||
|
||||
/** Destructor */
|
||||
~AbstractFifo();
|
||||
|
||||
/** Returns the total size of the buffer being managed. */
|
||||
int getTotalSize() const throw();
|
||||
|
||||
/** Returns the number of items that can currently be added to the buffer without it overflowing. */
|
||||
int getFreeSpace() const throw();
|
||||
|
||||
/** Returns the number of items that can currently be read from the buffer. */
|
||||
int getNumReady() const throw();
|
||||
|
||||
/** Clears the buffer positions, so that it appears empty. */
|
||||
void reset() throw();
|
||||
|
||||
/** Changes the buffer's total size.
|
||||
Note that this isn't thread-safe, so don't call it if there's any danger that it
|
||||
might overlap with a call to any other method in this class!
|
||||
*/
|
||||
void setTotalSize (int newSize) throw();
|
||||
|
||||
/** Returns the location within the buffer at which an incoming block of data should be written.
|
||||
|
||||
Because the section of data that you want to add to the buffer may overlap the end
|
||||
and wrap around to the start, two blocks within your buffer are returned, and you
|
||||
should copy your data into the first one, with any remaining data spilling over into
|
||||
the second.
|
||||
|
||||
If the number of items you ask for is too large to fit within the buffer's free space, then
|
||||
blockSize1 + blockSize2 may add up to a lower value than numToWrite.
|
||||
|
||||
After calling this method, and writing your data, you must call finishedWrite() to tell the
|
||||
FIFO how much data you actually added.
|
||||
|
||||
e.g.
|
||||
@code
|
||||
void addToFifo (const int* someData, int numItems)
|
||||
{
|
||||
int start1, size1, start2, size2;
|
||||
prepareToWrite (numItems, start1, size1, start2, size2);
|
||||
|
||||
if (size1 > 0)
|
||||
copySomeData (myBuffer + start1, someData, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (myBuffer + start2, someData + size1, size2);
|
||||
|
||||
finishedWrite (size1 + size2);
|
||||
}
|
||||
@endcode
|
||||
|
||||
@param numToWrite indicates how many items you'd like to add to the buffer
|
||||
@param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
|
||||
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
|
||||
@param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
|
||||
the first block should be written
|
||||
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex2
|
||||
@see finishedWrite
|
||||
*/
|
||||
void prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) throw();
|
||||
|
||||
/** Called after reading from the FIFO, to indicate that this many items have been added.
|
||||
@see prepareToWrite
|
||||
*/
|
||||
void finishedWrite (int numWritten) throw();
|
||||
|
||||
/** Returns the location within the buffer from which the next block of data should be read.
|
||||
|
||||
Because the section of data that you want to read from the buffer may overlap the end
|
||||
and wrap around to the start, two blocks within your buffer are returned, and you
|
||||
should read from both of them.
|
||||
|
||||
If the number of items you ask for is greater than the amount of data available, then
|
||||
blockSize1 + blockSize2 may add up to a lower value than numWanted.
|
||||
|
||||
After calling this method, and reading the data, you must call finishedRead() to tell the
|
||||
FIFO how much data you have consumed.
|
||||
|
||||
e.g.
|
||||
@code
|
||||
void readFromFifo (int* someData, int numItems)
|
||||
{
|
||||
int start1, size1, start2, size2;
|
||||
prepareToRead (numSamples, start1, size1, start2, size2);
|
||||
|
||||
if (size1 > 0)
|
||||
copySomeData (someData, myBuffer + start1, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (someData + size1, myBuffer + start2, size2);
|
||||
|
||||
finishedRead (size1 + size2);
|
||||
}
|
||||
@endcode
|
||||
|
||||
@param numToWrite indicates how many items you'd like to add to the buffer
|
||||
@param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
|
||||
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
|
||||
@param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
|
||||
the first block should be written
|
||||
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex2
|
||||
@see finishedRead
|
||||
*/
|
||||
void prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) throw();
|
||||
|
||||
/** Called after reading from the FIFO, to indicate that this many items have now been consumed.
|
||||
@see prepareToRead
|
||||
*/
|
||||
void finishedRead (int numRead) throw();
|
||||
|
||||
juce_UseDebuggingNewOperator
|
||||
|
||||
private:
|
||||
int bufferSize;
|
||||
Atomic <int> validStart, validEnd;
|
||||
|
||||
AbstractFifo (const AbstractFifo&);
|
||||
AbstractFifo& operator= (const AbstractFifo&);
|
||||
};
|
||||
|
||||
#endif // __JUCE_ABSTRACTFIFO_JUCEHEADER__
|
||||
/*** End of inlined file: juce_AbstractFifo.h ***/
|
||||
|
||||
|
||||
#endif
|
||||
#ifndef __JUCE_ARRAY_JUCEHEADER__
|
||||
|
||||
/*** Start of inlined file: juce_Array.h ***/
|
||||
|
|
@ -3471,15 +3999,15 @@ private:
|
|||
/*** End of inlined file: juce_CriticalSection.h ***/
|
||||
|
||||
/**
|
||||
Holds a list of simple objects, such as ints, doubles, or pointers.
|
||||
Holds a resizable array of primitive or copy-by-value objects.
|
||||
|
||||
Examples of arrays are: Array<int>, Array<Rectangle> or Array<MyClass*>
|
||||
|
||||
The array can be used to hold simple, non-polymorphic objects as well as primitive types - to
|
||||
The Array class can be used to hold simple, non-polymorphic objects as well as primitive types - to
|
||||
do so, the class must fulfil these requirements:
|
||||
- it must have a copy constructor and operator=
|
||||
- it must be able to be relocated in memory by a memcpy without this causing a problem - so no
|
||||
objects whose functionality relies on pointers or references to themselves can be used.
|
||||
- it must have a copy constructor and assignment operator
|
||||
- it must be able to be relocated in memory by a memcpy without this causing any problems - so
|
||||
objects whose functionality relies on external pointers or references to themselves can be used.
|
||||
|
||||
You can of course have an array of pointers to any kind of object, e.g. Array <MyClass*>, but if
|
||||
you do this, the array doesn't take any ownership of the objects - see the OwnedArray class or the
|
||||
|
|
@ -5757,341 +6285,6 @@ private:
|
|||
#ifndef __JUCE_REFERENCECOUNTEDOBJECT_JUCEHEADER__
|
||||
#define __JUCE_REFERENCECOUNTEDOBJECT_JUCEHEADER__
|
||||
|
||||
|
||||
/*** Start of inlined file: juce_Atomic.h ***/
|
||||
#ifndef __JUCE_ATOMIC_JUCEHEADER__
|
||||
#define __JUCE_ATOMIC_JUCEHEADER__
|
||||
|
||||
/**
|
||||
Simple class to hold a primitive value and perform atomic operations on it.
|
||||
|
||||
The type used must be a 32 or 64 bit primitive, like an int, pointer, etc.
|
||||
There are methods to perform most of the basic atomic operations.
|
||||
*/
|
||||
template <typename Type>
|
||||
class Atomic
|
||||
{
|
||||
public:
|
||||
/** Creates a new value, initialised to zero. */
|
||||
inline Atomic() throw()
|
||||
: value (0)
|
||||
{
|
||||
}
|
||||
|
||||
/** Creates a new value, with a given initial value. */
|
||||
inline Atomic (const Type initialValue) throw()
|
||||
: value (initialValue)
|
||||
{
|
||||
}
|
||||
|
||||
/** Copies another value (atomically). */
|
||||
inline Atomic (const Atomic& other) throw()
|
||||
: value (other.get())
|
||||
{
|
||||
}
|
||||
|
||||
/** Destructor. */
|
||||
inline ~Atomic() throw()
|
||||
{
|
||||
// This class can only be used for types which are 32 or 64 bits in size.
|
||||
static_jassert (sizeof (Type) == 4 || sizeof (Type) == 8);
|
||||
}
|
||||
|
||||
/** Atomically reads and returns the current value. */
|
||||
Type get() const throw();
|
||||
|
||||
/** Copies another value onto this one (atomically). */
|
||||
inline Atomic& operator= (const Atomic& other) throw() { exchange (other.get()); return *this; }
|
||||
|
||||
/** Copies another value onto this one (atomically). */
|
||||
inline Atomic& operator= (const Type newValue) throw() { exchange (newValue); return *this; }
|
||||
|
||||
/** Atomically sets the current value. */
|
||||
void set (Type newValue) throw() { exchange (newValue); }
|
||||
|
||||
/** Atomically sets the current value, returning the value that was replaced. */
|
||||
Type exchange (Type value) throw();
|
||||
|
||||
/** Atomically adds a number to this value, returning the new value. */
|
||||
Type operator+= (Type amountToAdd) throw();
|
||||
|
||||
/** Atomically subtracts a number from this value, returning the new value. */
|
||||
Type operator-= (Type amountToSubtract) throw();
|
||||
|
||||
/** Atomically increments this value, returning the new value. */
|
||||
Type operator++() throw();
|
||||
|
||||
/** Atomically decrements this value, returning the new value. */
|
||||
Type operator--() throw();
|
||||
|
||||
/** Atomically compares this value with a target value, and if it is equal, sets
|
||||
this to be equal to a new value.
|
||||
|
||||
This operation is the atomic equivalent of doing this:
|
||||
@code
|
||||
bool compareAndSetBool (Type newValue, Type valueToCompare)
|
||||
{
|
||||
if (get() == valueToCompare)
|
||||
{
|
||||
set (newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@endcode
|
||||
|
||||
@returns true if the comparison was true and the value was replaced; false if
|
||||
the comparison failed and the value was left unchanged.
|
||||
@see compareAndSetValue
|
||||
*/
|
||||
bool compareAndSetBool (Type newValue, Type valueToCompare) throw();
|
||||
|
||||
/** Atomically compares this value with a target value, and if it is equal, sets
|
||||
this to be equal to a new value.
|
||||
|
||||
This operation is the atomic equivalent of doing this:
|
||||
@code
|
||||
Type compareAndSetValue (Type newValue, Type valueToCompare)
|
||||
{
|
||||
Type oldValue = get();
|
||||
if (oldValue == valueToCompare)
|
||||
set (newValue);
|
||||
|
||||
return oldValue;
|
||||
}
|
||||
@endcode
|
||||
|
||||
@returns the old value before it was changed.
|
||||
@see compareAndSetBool
|
||||
*/
|
||||
Type compareAndSetValue (Type newValue, Type valueToCompare) throw();
|
||||
|
||||
/** Implements a memory read/write barrier. */
|
||||
static void memoryBarrier() throw();
|
||||
|
||||
JUCE_ALIGN(8)
|
||||
|
||||
/** The raw value that this class operates on.
|
||||
This is exposed publically in case you need to manipulate it directly
|
||||
for performance reasons.
|
||||
*/
|
||||
volatile Type value;
|
||||
|
||||
private:
|
||||
static inline Type castFrom32Bit (int32 value) throw() { return *(Type*) &value; }
|
||||
static inline Type castFrom64Bit (int64 value) throw() { return *(Type*) &value; }
|
||||
static inline int32 castTo32Bit (Type value) throw() { return *(int32*) &value; }
|
||||
static inline int64 castTo64Bit (Type value) throw() { return *(int64*) &value; }
|
||||
};
|
||||
|
||||
/*
|
||||
The following code is in the header so that the atomics can be inlined where possible...
|
||||
*/
|
||||
#if (JUCE_IOS && (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_3_2 || ! defined (__IPHONE_3_2))) \
|
||||
|| (JUCE_MAC && (JUCE_PPC || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)))
|
||||
#define JUCE_ATOMICS_MAC 1 // Older OSX builds using gcc4.1 or earlier
|
||||
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
|
||||
#define JUCE_MAC_ATOMICS_VOLATILE
|
||||
#else
|
||||
#define JUCE_MAC_ATOMICS_VOLATILE volatile
|
||||
#endif
|
||||
|
||||
#if JUCE_PPC || JUCE_IOS
|
||||
// None of these atomics are available for PPC or for iPhoneOS 3.1 or earlier!!
|
||||
template <typename Type> static Type OSAtomicAdd64Barrier (Type b, JUCE_MAC_ATOMICS_VOLATILE Type* a) throw() { jassertfalse; return *a += b; }
|
||||
template <typename Type> static Type OSAtomicIncrement64Barrier (JUCE_MAC_ATOMICS_VOLATILE Type* a) throw() { jassertfalse; return ++*a; }
|
||||
template <typename Type> static Type OSAtomicDecrement64Barrier (JUCE_MAC_ATOMICS_VOLATILE Type* a) throw() { jassertfalse; return --*a; }
|
||||
template <typename Type> static bool OSAtomicCompareAndSwap64Barrier (Type old, Type newValue, JUCE_MAC_ATOMICS_VOLATILE Type* value) throw()
|
||||
{ jassertfalse; if (old == *value) { *value = newValue; return true; } return false; }
|
||||
#define JUCE_64BIT_ATOMICS_UNAVAILABLE 1
|
||||
#endif
|
||||
|
||||
#elif JUCE_GCC
|
||||
#define JUCE_ATOMICS_GCC 1 // GCC with intrinsics
|
||||
|
||||
#if JUCE_IOS
|
||||
#define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 // (on the iphone, the 64-bit ops will compile but not link)
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define JUCE_ATOMICS_WINDOWS 1 // Windows with intrinsics
|
||||
|
||||
#if JUCE_USE_INTRINSICS || JUCE_64BIT
|
||||
#pragma intrinsic (_InterlockedExchange, _InterlockedIncrement, _InterlockedDecrement, _InterlockedCompareExchange, \
|
||||
_InterlockedCompareExchange64, _InterlockedExchangeAdd, _ReadWriteBarrier)
|
||||
#define juce_InterlockedExchange(a, b) _InterlockedExchange(a, b)
|
||||
#define juce_InterlockedIncrement(a) _InterlockedIncrement(a)
|
||||
#define juce_InterlockedDecrement(a) _InterlockedDecrement(a)
|
||||
#define juce_InterlockedExchangeAdd(a, b) _InterlockedExchangeAdd(a, b)
|
||||
#define juce_InterlockedCompareExchange(a, b, c) _InterlockedCompareExchange(a, b, c)
|
||||
#define juce_InterlockedCompareExchange64(a, b, c) _InterlockedCompareExchange64(a, b, c)
|
||||
#define juce_MemoryBarrier _ReadWriteBarrier
|
||||
#else
|
||||
// (these are defined in juce_win32_Threads.cpp)
|
||||
long juce_InterlockedExchange (volatile long* a, long b) throw();
|
||||
long juce_InterlockedIncrement (volatile long* a) throw();
|
||||
long juce_InterlockedDecrement (volatile long* a) throw();
|
||||
long juce_InterlockedExchangeAdd (volatile long* a, long b) throw();
|
||||
long juce_InterlockedCompareExchange (volatile long* a, long b, long c) throw();
|
||||
__int64 juce_InterlockedCompareExchange64 (volatile __int64* a, __int64 b, __int64 c) throw();
|
||||
void juce_MemoryBarrier() throw() { long x = 0; juce_InterlockedIncrement (&x); }
|
||||
#endif
|
||||
|
||||
#if JUCE_64BIT
|
||||
#pragma intrinsic (_InterlockedExchangeAdd64, _InterlockedExchange64, _InterlockedIncrement64, _InterlockedDecrement64)
|
||||
#define juce_InterlockedExchangeAdd64(a, b) _InterlockedExchangeAdd64(a, b)
|
||||
#define juce_InterlockedExchange64(a, b) _InterlockedExchange64(a, b)
|
||||
#define juce_InterlockedIncrement64(a) _InterlockedIncrement64(a)
|
||||
#define juce_InterlockedDecrement64(a) _InterlockedDecrement64(a)
|
||||
#else
|
||||
// None of these atomics are available in a 32-bit Windows build!!
|
||||
template <typename Type> static Type juce_InterlockedExchangeAdd64 (volatile Type* a, Type b) throw() { jassertfalse; Type old = *a; *a += b; return old; }
|
||||
template <typename Type> static Type juce_InterlockedExchange64 (volatile Type* a, Type b) throw() { jassertfalse; Type old = *a; *a = b; return old; }
|
||||
template <typename Type> static Type juce_InterlockedIncrement64 (volatile Type* a) throw() { jassertfalse; return ++*a; }
|
||||
template <typename Type> static Type juce_InterlockedDecrement64 (volatile Type* a) throw() { jassertfalse; return --*a; }
|
||||
#define JUCE_64BIT_ATOMICS_UNAVAILABLE 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if JUCE_MSVC
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4311) // (truncation warning)
|
||||
#endif
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::get() const throw()
|
||||
{
|
||||
#if JUCE_ATOMICS_MAC
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((int32) OSAtomicAdd32Barrier ((int32_t) 0, (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value))
|
||||
: castFrom64Bit ((int64) OSAtomicAdd64Barrier ((int64_t) 0, (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value));
|
||||
#elif JUCE_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedExchangeAdd ((volatile long*) &value, (long) 0))
|
||||
: castFrom64Bit ((int64) juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) 0));
|
||||
#elif JUCE_ATOMICS_GCC
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_add_and_fetch ((volatile int32*) &value, 0))
|
||||
: castFrom64Bit ((int64) __sync_add_and_fetch ((volatile int64*) &value, 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::exchange (const Type newValue) throw()
|
||||
{
|
||||
#if JUCE_ATOMICS_MAC || JUCE_ATOMICS_GCC
|
||||
Type currentVal = value;
|
||||
while (! compareAndSetBool (newValue, currentVal)) { currentVal = value; }
|
||||
return currentVal;
|
||||
#elif JUCE_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedExchange ((volatile long*) &value, (long) castTo32Bit (newValue)))
|
||||
: castFrom64Bit ((int64) juce_InterlockedExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::operator+= (const Type amountToAdd) throw()
|
||||
{
|
||||
#if JUCE_ATOMICS_MAC
|
||||
return sizeof (Type) == 4 ? (Type) OSAtomicAdd32Barrier ((int32_t) castTo32Bit (amountToAdd), (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||
: (Type) OSAtomicAdd64Barrier ((int64_t) amountToAdd, (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||
#elif JUCE_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? (Type) (juce_InterlockedExchangeAdd ((volatile long*) &value, (long) amountToAdd) + (long) amountToAdd)
|
||||
: (Type) (juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) amountToAdd) + (__int64) amountToAdd);
|
||||
#elif JUCE_ATOMICS_GCC
|
||||
return (Type) __sync_add_and_fetch (&value, amountToAdd);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::operator-= (const Type amountToSubtract) throw()
|
||||
{
|
||||
return operator+= (juce_negate (amountToSubtract));
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::operator++() throw()
|
||||
{
|
||||
#if JUCE_ATOMICS_MAC
|
||||
return sizeof (Type) == 4 ? (Type) OSAtomicIncrement32Barrier ((JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||
: (Type) OSAtomicIncrement64Barrier ((JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||
#elif JUCE_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? (Type) juce_InterlockedIncrement ((volatile long*) &value)
|
||||
: (Type) juce_InterlockedIncrement64 ((volatile __int64*) &value);
|
||||
#elif JUCE_ATOMICS_GCC
|
||||
return (Type) __sync_add_and_fetch (&value, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::operator--() throw()
|
||||
{
|
||||
#if JUCE_ATOMICS_MAC
|
||||
return sizeof (Type) == 4 ? (Type) OSAtomicDecrement32Barrier ((JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||
: (Type) OSAtomicDecrement64Barrier ((JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||
#elif JUCE_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? (Type) juce_InterlockedDecrement ((volatile long*) &value)
|
||||
: (Type) juce_InterlockedDecrement64 ((volatile __int64*) &value);
|
||||
#elif JUCE_ATOMICS_GCC
|
||||
return (Type) __sync_add_and_fetch (&value, -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline bool Atomic<Type>::compareAndSetBool (const Type newValue, const Type valueToCompare) throw()
|
||||
{
|
||||
#if JUCE_ATOMICS_MAC
|
||||
return sizeof (Type) == 4 ? OSAtomicCompareAndSwap32Barrier ((int32_t) castTo32Bit (valueToCompare), (int32_t) castTo32Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||
: OSAtomicCompareAndSwap64Barrier ((int64_t) castTo64Bit (valueToCompare), (int64_t) castTo64Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||
#elif JUCE_ATOMICS_WINDOWS
|
||||
return compareAndSetValue (newValue, valueToCompare) == valueToCompare;
|
||||
#elif JUCE_ATOMICS_GCC
|
||||
return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))
|
||||
: __sync_bool_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::compareAndSetValue (const Type newValue, const Type valueToCompare) throw()
|
||||
{
|
||||
#if JUCE_ATOMICS_MAC
|
||||
for (;;) // Annoying workaround for OSX only having a bool CAS operation..
|
||||
{
|
||||
if (compareAndSetBool (newValue, valueToCompare))
|
||||
return valueToCompare;
|
||||
|
||||
const Type result = value;
|
||||
if (result != valueToCompare)
|
||||
return result;
|
||||
}
|
||||
|
||||
#elif JUCE_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedCompareExchange ((volatile long*) &value, (long) castTo32Bit (newValue), (long) castTo32Bit (valueToCompare)))
|
||||
: castFrom64Bit ((int64) juce_InterlockedCompareExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue), (__int64) castTo64Bit (valueToCompare)));
|
||||
#elif JUCE_ATOMICS_GCC
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_val_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue)))
|
||||
: castFrom64Bit ((int64) __sync_val_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline void Atomic<Type>::memoryBarrier() throw()
|
||||
{
|
||||
#if JUCE_ATOMICS_MAC
|
||||
OSMemoryBarrier();
|
||||
#elif JUCE_ATOMICS_GCC
|
||||
__sync_synchronize();
|
||||
#elif JUCE_ATOMICS_WINDOWS
|
||||
juce_MemoryBarrier();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if JUCE_MSVC
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // __JUCE_ATOMIC_JUCEHEADER__
|
||||
/*** End of inlined file: juce_Atomic.h ***/
|
||||
|
||||
/**
|
||||
Adds reference-counting to an object.
|
||||
|
||||
|
|
@ -31015,6 +31208,12 @@ public:
|
|||
int numSamplesToRead,
|
||||
int samplesPerBlock = 2048);
|
||||
|
||||
/** Writes some samples from an AudioSampleBuffer.
|
||||
|
||||
*/
|
||||
bool writeFromAudioSampleBuffer (const AudioSampleBuffer& source,
|
||||
int startSample, int numSamples);
|
||||
|
||||
/** Returns the sample rate being used. */
|
||||
double getSampleRate() const throw() { return sampleRate; }
|
||||
|
||||
|
|
@ -31027,6 +31226,47 @@ public:
|
|||
/** Returns true if it's a floating-point format, false if it's fixed-point. */
|
||||
bool isFloatingPoint() const throw() { return usesFloatingPointData; }
|
||||
|
||||
/**
|
||||
Provides a FIFO for an AudioFormatWriter, allowing you to push incoming
|
||||
data into a buffer which will be flushed to disk by a background thread.
|
||||
*/
|
||||
class ThreadedWriter
|
||||
{
|
||||
public:
|
||||
/** Creates a ThreadedWriter for a given writer and a thread.
|
||||
|
||||
The writer object which is passed in here will be owned and deleted by
|
||||
the ThreadedWriter when it is no longer needed.
|
||||
|
||||
To stop the writer and flush the buffer to disk, simply delete this object.
|
||||
*/
|
||||
ThreadedWriter (AudioFormatWriter* writer,
|
||||
TimeSliceThread& backgroundThread,
|
||||
int numSamplesToBuffer);
|
||||
|
||||
/** Destructor. */
|
||||
~ThreadedWriter();
|
||||
|
||||
/** Pushes some incoming audio data into the FIFO.
|
||||
|
||||
If there's enough free space in the buffer, this will add the data to it,
|
||||
|
||||
If the FIFO is too full to accept this many samples, the method will return
|
||||
false - then you could either wait until the background thread has had time to
|
||||
consume some of the buffered data and try again, or you can give up
|
||||
and lost this block.
|
||||
|
||||
The data must be an array containing the same number of channels as the
|
||||
AudioFormatWriter object is using. None of these channels can be null.
|
||||
*/
|
||||
bool write (const float** data, int numSamples);
|
||||
|
||||
private:
|
||||
class Buffer;
|
||||
friend class ScopedPointer<Buffer>;
|
||||
ScopedPointer<Buffer> buffer;
|
||||
};
|
||||
|
||||
juce_UseDebuggingNewOperator
|
||||
|
||||
protected:
|
||||
|
|
@ -31057,10 +31297,16 @@ protected:
|
|||
for (int i = 0; i < numDestChannels; ++i)
|
||||
{
|
||||
const DestType dest (addBytesToPointer (destData, i * DestType::getBytesPerSample()), numDestChannels);
|
||||
dest.convertSamples (SourceType (*source), numSamples);
|
||||
|
||||
if (source[1] != 0)
|
||||
if (*source != 0)
|
||||
{
|
||||
dest.convertSamples (SourceType (*source), numSamples);
|
||||
++source;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest.clearSamples (numSamples);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ public:
|
|||
{
|
||||
switch (bitsPerSample)
|
||||
{
|
||||
case 8: ReadHelper<AudioData::Int32, AudioData::Int8, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 8: ReadHelper<AudioData::Int32, AudioData::Int8, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 16: ReadHelper<AudioData::Int32, AudioData::Int16, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 24: ReadHelper<AudioData::Int32, AudioData::Int24, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 32: ReadHelper<AudioData::Int32, AudioData::Int32, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
|
|
@ -199,7 +199,7 @@ public:
|
|||
{
|
||||
switch (bitsPerSample)
|
||||
{
|
||||
case 8: ReadHelper<AudioData::Int32, AudioData::Int8, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 8: ReadHelper<AudioData::Int32, AudioData::Int8, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 16: ReadHelper<AudioData::Int32, AudioData::Int16, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 24: ReadHelper<AudioData::Int32, AudioData::Int24, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
case 32: ReadHelper<AudioData::Int32, AudioData::Int32, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break;
|
||||
|
|
|
|||
|
|
@ -28,486 +28,10 @@
|
|||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "juce_AudioFormat.h"
|
||||
#include "../dsp/juce_AudioSampleBuffer.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
AudioFormatReader::AudioFormatReader (InputStream* const in,
|
||||
const String& formatName_)
|
||||
: sampleRate (0),
|
||||
bitsPerSample (0),
|
||||
lengthInSamples (0),
|
||||
numChannels (0),
|
||||
usesFloatingPointData (false),
|
||||
input (in),
|
||||
formatName (formatName_)
|
||||
{
|
||||
}
|
||||
|
||||
AudioFormatReader::~AudioFormatReader()
|
||||
{
|
||||
delete input;
|
||||
}
|
||||
|
||||
bool AudioFormatReader::read (int* const* destSamples,
|
||||
int numDestChannels,
|
||||
int64 startSampleInSource,
|
||||
int numSamplesToRead,
|
||||
const bool fillLeftoverChannelsWithCopies)
|
||||
{
|
||||
jassert (numDestChannels > 0); // you have to actually give this some channels to work with!
|
||||
|
||||
int startOffsetInDestBuffer = 0;
|
||||
|
||||
if (startSampleInSource < 0)
|
||||
{
|
||||
const int silence = (int) jmin (-startSampleInSource, (int64) numSamplesToRead);
|
||||
|
||||
for (int i = numDestChannels; --i >= 0;)
|
||||
if (destSamples[i] != 0)
|
||||
zeromem (destSamples[i], sizeof (int) * silence);
|
||||
|
||||
startOffsetInDestBuffer += silence;
|
||||
numSamplesToRead -= silence;
|
||||
startSampleInSource = 0;
|
||||
}
|
||||
|
||||
if (numSamplesToRead <= 0)
|
||||
return true;
|
||||
|
||||
if (! readSamples (const_cast<int**> (destSamples),
|
||||
jmin ((int) numChannels, numDestChannels), startOffsetInDestBuffer,
|
||||
startSampleInSource, numSamplesToRead))
|
||||
return false;
|
||||
|
||||
if (numDestChannels > (int) numChannels)
|
||||
{
|
||||
if (fillLeftoverChannelsWithCopies)
|
||||
{
|
||||
int* lastFullChannel = destSamples[0];
|
||||
|
||||
for (int i = (int) numChannels; --i > 0;)
|
||||
{
|
||||
if (destSamples[i] != 0)
|
||||
{
|
||||
lastFullChannel = destSamples[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastFullChannel != 0)
|
||||
for (int i = numChannels; i < numDestChannels; ++i)
|
||||
if (destSamples[i] != 0)
|
||||
memcpy (destSamples[i], lastFullChannel, sizeof (int) * numSamplesToRead);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numChannels; i < numDestChannels; ++i)
|
||||
if (destSamples[i] != 0)
|
||||
zeromem (destSamples[i], sizeof (int) * numSamplesToRead);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void findAudioBufferMaxMin (const float* const buffer, const int num, float& maxVal, float& minVal) throw()
|
||||
{
|
||||
float mn = buffer[0];
|
||||
float mx = mn;
|
||||
|
||||
for (int i = 1; i < num; ++i)
|
||||
{
|
||||
const float s = buffer[i];
|
||||
if (s > mx) mx = s;
|
||||
if (s < mn) mn = s;
|
||||
}
|
||||
|
||||
maxVal = mx;
|
||||
minVal = mn;
|
||||
}
|
||||
|
||||
void AudioFormatReader::readMaxLevels (int64 startSampleInFile,
|
||||
int64 numSamples,
|
||||
float& lowestLeft, float& highestLeft,
|
||||
float& lowestRight, float& highestRight)
|
||||
{
|
||||
if (numSamples <= 0)
|
||||
{
|
||||
lowestLeft = 0;
|
||||
lowestRight = 0;
|
||||
highestLeft = 0;
|
||||
highestRight = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const int bufferSize = (int) jmin (numSamples, (int64) 4096);
|
||||
HeapBlock<int> tempSpace (bufferSize * 2 + 64);
|
||||
|
||||
int* tempBuffer[3];
|
||||
tempBuffer[0] = tempSpace.getData();
|
||||
tempBuffer[1] = tempSpace.getData() + bufferSize;
|
||||
tempBuffer[2] = 0;
|
||||
|
||||
if (usesFloatingPointData)
|
||||
{
|
||||
float lmin = 1.0e6f;
|
||||
float lmax = -lmin;
|
||||
float rmin = lmin;
|
||||
float rmax = lmax;
|
||||
|
||||
while (numSamples > 0)
|
||||
{
|
||||
const int numToDo = (int) jmin (numSamples, (int64) bufferSize);
|
||||
read (tempBuffer, 2, startSampleInFile, numToDo, false);
|
||||
|
||||
numSamples -= numToDo;
|
||||
startSampleInFile += numToDo;
|
||||
|
||||
float bufmin, bufmax;
|
||||
findAudioBufferMaxMin (reinterpret_cast<float*> (tempBuffer[0]), numToDo, bufmax, bufmin);
|
||||
lmin = jmin (lmin, bufmin);
|
||||
lmax = jmax (lmax, bufmax);
|
||||
|
||||
if (numChannels > 1)
|
||||
{
|
||||
findAudioBufferMaxMin (reinterpret_cast<float*> (tempBuffer[1]), numToDo, bufmax, bufmin);
|
||||
rmin = jmin (rmin, bufmin);
|
||||
rmax = jmax (rmax, bufmax);
|
||||
}
|
||||
}
|
||||
|
||||
if (numChannels <= 1)
|
||||
{
|
||||
rmax = lmax;
|
||||
rmin = lmin;
|
||||
}
|
||||
|
||||
lowestLeft = lmin;
|
||||
highestLeft = lmax;
|
||||
lowestRight = rmin;
|
||||
highestRight = rmax;
|
||||
}
|
||||
else
|
||||
{
|
||||
int lmax = std::numeric_limits<int>::min();
|
||||
int lmin = std::numeric_limits<int>::max();
|
||||
int rmax = std::numeric_limits<int>::min();
|
||||
int rmin = std::numeric_limits<int>::max();
|
||||
|
||||
while (numSamples > 0)
|
||||
{
|
||||
const int numToDo = (int) jmin (numSamples, (int64) bufferSize);
|
||||
read (tempBuffer, 2, startSampleInFile, numToDo, false);
|
||||
|
||||
numSamples -= numToDo;
|
||||
startSampleInFile += numToDo;
|
||||
|
||||
for (int j = numChannels; --j >= 0;)
|
||||
{
|
||||
int bufMax = std::numeric_limits<int>::min();
|
||||
int bufMin = std::numeric_limits<int>::max();
|
||||
|
||||
const int* const b = tempBuffer[j];
|
||||
|
||||
for (int i = 0; i < numToDo; ++i)
|
||||
{
|
||||
const int samp = b[i];
|
||||
|
||||
if (samp < bufMin)
|
||||
bufMin = samp;
|
||||
|
||||
if (samp > bufMax)
|
||||
bufMax = samp;
|
||||
}
|
||||
|
||||
if (j == 0)
|
||||
{
|
||||
lmax = jmax (lmax, bufMax);
|
||||
lmin = jmin (lmin, bufMin);
|
||||
}
|
||||
else
|
||||
{
|
||||
rmax = jmax (rmax, bufMax);
|
||||
rmin = jmin (rmin, bufMin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numChannels <= 1)
|
||||
{
|
||||
rmax = lmax;
|
||||
rmin = lmin;
|
||||
}
|
||||
|
||||
lowestLeft = lmin / (float) std::numeric_limits<int>::max();
|
||||
highestLeft = lmax / (float) std::numeric_limits<int>::max();
|
||||
lowestRight = rmin / (float) std::numeric_limits<int>::max();
|
||||
highestRight = rmax / (float) std::numeric_limits<int>::max();
|
||||
}
|
||||
}
|
||||
|
||||
int64 AudioFormatReader::searchForLevel (int64 startSample,
|
||||
int64 numSamplesToSearch,
|
||||
const double magnitudeRangeMinimum,
|
||||
const double magnitudeRangeMaximum,
|
||||
const int minimumConsecutiveSamples)
|
||||
{
|
||||
if (numSamplesToSearch == 0)
|
||||
return -1;
|
||||
|
||||
const int bufferSize = 4096;
|
||||
HeapBlock<int> tempSpace (bufferSize * 2 + 64);
|
||||
|
||||
int* tempBuffer[3];
|
||||
tempBuffer[0] = tempSpace.getData();
|
||||
tempBuffer[1] = tempSpace.getData() + bufferSize;
|
||||
tempBuffer[2] = 0;
|
||||
|
||||
int consecutive = 0;
|
||||
int64 firstMatchPos = -1;
|
||||
|
||||
jassert (magnitudeRangeMaximum > magnitudeRangeMinimum);
|
||||
|
||||
const double doubleMin = jlimit (0.0, (double) std::numeric_limits<int>::max(), magnitudeRangeMinimum * std::numeric_limits<int>::max());
|
||||
const double doubleMax = jlimit (doubleMin, (double) std::numeric_limits<int>::max(), magnitudeRangeMaximum * std::numeric_limits<int>::max());
|
||||
const int intMagnitudeRangeMinimum = roundToInt (doubleMin);
|
||||
const int intMagnitudeRangeMaximum = roundToInt (doubleMax);
|
||||
|
||||
while (numSamplesToSearch != 0)
|
||||
{
|
||||
const int numThisTime = (int) jmin (abs64 (numSamplesToSearch), (int64) bufferSize);
|
||||
int64 bufferStart = startSample;
|
||||
|
||||
if (numSamplesToSearch < 0)
|
||||
bufferStart -= numThisTime;
|
||||
|
||||
if (bufferStart >= (int) lengthInSamples)
|
||||
break;
|
||||
|
||||
read (tempBuffer, 2, bufferStart, numThisTime, false);
|
||||
|
||||
int num = numThisTime;
|
||||
while (--num >= 0)
|
||||
{
|
||||
if (numSamplesToSearch < 0)
|
||||
--startSample;
|
||||
|
||||
bool matches = false;
|
||||
const int index = (int) (startSample - bufferStart);
|
||||
|
||||
if (usesFloatingPointData)
|
||||
{
|
||||
const float sample1 = std::abs (((float*) tempBuffer[0]) [index]);
|
||||
|
||||
if (sample1 >= magnitudeRangeMinimum
|
||||
&& sample1 <= magnitudeRangeMaximum)
|
||||
{
|
||||
matches = true;
|
||||
}
|
||||
else if (numChannels > 1)
|
||||
{
|
||||
const float sample2 = std::abs (((float*) tempBuffer[1]) [index]);
|
||||
|
||||
matches = (sample2 >= magnitudeRangeMinimum
|
||||
&& sample2 <= magnitudeRangeMaximum);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const int sample1 = abs (tempBuffer[0] [index]);
|
||||
|
||||
if (sample1 >= intMagnitudeRangeMinimum
|
||||
&& sample1 <= intMagnitudeRangeMaximum)
|
||||
{
|
||||
matches = true;
|
||||
}
|
||||
else if (numChannels > 1)
|
||||
{
|
||||
const int sample2 = abs (tempBuffer[1][index]);
|
||||
|
||||
matches = (sample2 >= intMagnitudeRangeMinimum
|
||||
&& sample2 <= intMagnitudeRangeMaximum);
|
||||
}
|
||||
}
|
||||
|
||||
if (matches)
|
||||
{
|
||||
if (firstMatchPos < 0)
|
||||
firstMatchPos = startSample;
|
||||
|
||||
if (++consecutive >= minimumConsecutiveSamples)
|
||||
{
|
||||
if (firstMatchPos < 0 || firstMatchPos >= lengthInSamples)
|
||||
return -1;
|
||||
|
||||
return firstMatchPos;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
consecutive = 0;
|
||||
firstMatchPos = -1;
|
||||
}
|
||||
|
||||
if (numSamplesToSearch > 0)
|
||||
++startSample;
|
||||
}
|
||||
|
||||
if (numSamplesToSearch > 0)
|
||||
numSamplesToSearch -= numThisTime;
|
||||
else
|
||||
numSamplesToSearch += numThisTime;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
AudioFormatWriter::AudioFormatWriter (OutputStream* const out,
|
||||
const String& formatName_,
|
||||
const double rate,
|
||||
const unsigned int numChannels_,
|
||||
const unsigned int bitsPerSample_)
|
||||
: sampleRate (rate),
|
||||
numChannels (numChannels_),
|
||||
bitsPerSample (bitsPerSample_),
|
||||
usesFloatingPointData (false),
|
||||
output (out),
|
||||
formatName (formatName_)
|
||||
{
|
||||
}
|
||||
|
||||
AudioFormatWriter::~AudioFormatWriter()
|
||||
{
|
||||
delete output;
|
||||
}
|
||||
|
||||
bool AudioFormatWriter::writeFromAudioReader (AudioFormatReader& reader,
|
||||
int64 startSample,
|
||||
int64 numSamplesToRead)
|
||||
{
|
||||
const int bufferSize = 16384;
|
||||
AudioSampleBuffer tempBuffer (numChannels, bufferSize);
|
||||
|
||||
int* buffers [128];
|
||||
zerostruct (buffers);
|
||||
|
||||
for (int i = tempBuffer.getNumChannels(); --i >= 0;)
|
||||
buffers[i] = reinterpret_cast<int*> (tempBuffer.getSampleData (i, 0));
|
||||
|
||||
if (numSamplesToRead < 0)
|
||||
numSamplesToRead = reader.lengthInSamples;
|
||||
|
||||
while (numSamplesToRead > 0)
|
||||
{
|
||||
const int numToDo = (int) jmin (numSamplesToRead, (int64) bufferSize);
|
||||
|
||||
if (! reader.read (buffers, numChannels, startSample, numToDo, false))
|
||||
return false;
|
||||
|
||||
if (reader.usesFloatingPointData != isFloatingPoint())
|
||||
{
|
||||
int** bufferChan = buffers;
|
||||
|
||||
while (*bufferChan != 0)
|
||||
{
|
||||
int* b = *bufferChan++;
|
||||
|
||||
if (isFloatingPoint())
|
||||
{
|
||||
// int -> float
|
||||
const double factor = 1.0 / std::numeric_limits<int>::max();
|
||||
|
||||
for (int i = 0; i < numToDo; ++i)
|
||||
((float*) b)[i] = (float) (factor * b[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// float -> int
|
||||
for (int i = 0; i < numToDo; ++i)
|
||||
{
|
||||
const double samp = *(const float*) b;
|
||||
|
||||
if (samp <= -1.0)
|
||||
*b++ = std::numeric_limits<int>::min();
|
||||
else if (samp >= 1.0)
|
||||
*b++ = std::numeric_limits<int>::max();
|
||||
else
|
||||
*b++ = roundToInt (std::numeric_limits<int>::max() * samp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! write (const_cast<const int**> (buffers), numToDo))
|
||||
return false;
|
||||
|
||||
numSamplesToRead -= numToDo;
|
||||
startSample += numToDo;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioFormatWriter::writeFromAudioSource (AudioSource& source,
|
||||
int numSamplesToRead,
|
||||
const int samplesPerBlock)
|
||||
{
|
||||
AudioSampleBuffer tempBuffer (getNumChannels(), samplesPerBlock);
|
||||
int* buffers [128];
|
||||
zerostruct (buffers);
|
||||
|
||||
for (int i = tempBuffer.getNumChannels(); --i >= 0;)
|
||||
buffers[i] = reinterpret_cast<int*> (tempBuffer.getSampleData (i, 0));
|
||||
|
||||
while (numSamplesToRead > 0)
|
||||
{
|
||||
const int numToDo = jmin (numSamplesToRead, samplesPerBlock);
|
||||
|
||||
AudioSourceChannelInfo info;
|
||||
info.buffer = &tempBuffer;
|
||||
info.startSample = 0;
|
||||
info.numSamples = numToDo;
|
||||
info.clearActiveBufferRegion();
|
||||
|
||||
source.getNextAudioBlock (info);
|
||||
|
||||
if (! isFloatingPoint())
|
||||
{
|
||||
int** bufferChan = buffers;
|
||||
|
||||
while (*bufferChan != 0)
|
||||
{
|
||||
int* b = *bufferChan++;
|
||||
|
||||
// float -> int
|
||||
for (int j = numToDo; --j >= 0;)
|
||||
{
|
||||
const double samp = *(const float*) b;
|
||||
|
||||
if (samp <= -1.0)
|
||||
*b++ = std::numeric_limits<int>::min();
|
||||
else if (samp >= 1.0)
|
||||
*b++ = std::numeric_limits<int>::max();
|
||||
else
|
||||
*b++ = roundToInt (std::numeric_limits<int>::max() * samp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! write ((const int**) buffers, numToDo))
|
||||
return false;
|
||||
|
||||
numSamplesToRead -= numToDo;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
AudioFormat::AudioFormat (const String& name,
|
||||
const StringArray& extensions)
|
||||
AudioFormat::AudioFormat (const String& name, const StringArray& extensions)
|
||||
: formatName (name),
|
||||
fileExtensions (extensions)
|
||||
{
|
||||
|
|
@ -518,16 +42,6 @@ AudioFormat::~AudioFormat()
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
const String& AudioFormat::getFormatName() const
|
||||
{
|
||||
return formatName;
|
||||
}
|
||||
|
||||
const StringArray& AudioFormat::getFileExtensions() const
|
||||
{
|
||||
return fileExtensions;
|
||||
}
|
||||
|
||||
bool AudioFormat::canHandleFile (const File& f)
|
||||
{
|
||||
for (int i = 0; i < fileExtensions.size(); ++i)
|
||||
|
|
@ -537,15 +51,10 @@ bool AudioFormat::canHandleFile (const File& f)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool AudioFormat::isCompressed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const StringArray AudioFormat::getQualityOptions()
|
||||
{
|
||||
return StringArray();
|
||||
}
|
||||
const String& AudioFormat::getFormatName() const { return formatName; }
|
||||
const StringArray& AudioFormat::getFileExtensions() const { return fileExtensions; }
|
||||
bool AudioFormat::isCompressed() { return false; }
|
||||
const StringArray AudioFormat::getQualityOptions() { return StringArray(); }
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
|
|||
367
src/audio/audio_file_formats/juce_AudioFormatReader.cpp
Normal file
367
src/audio/audio_file_formats/juce_AudioFormatReader.cpp
Normal file
|
|
@ -0,0 +1,367 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-10 by Raw Material Software Ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified under the terms of the GNU General
|
||||
Public License (Version 2), as published by the Free Software Foundation.
|
||||
A copy of the license is included in the JUCE distribution, or can be found
|
||||
online at www.gnu.org/licenses.
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.rawmaterialsoftware.com/juce for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../core/juce_StandardHeader.h"
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "juce_AudioFormat.h"
|
||||
#include "../dsp/juce_AudioSampleBuffer.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
AudioFormatReader::AudioFormatReader (InputStream* const in,
|
||||
const String& formatName_)
|
||||
: sampleRate (0),
|
||||
bitsPerSample (0),
|
||||
lengthInSamples (0),
|
||||
numChannels (0),
|
||||
usesFloatingPointData (false),
|
||||
input (in),
|
||||
formatName (formatName_)
|
||||
{
|
||||
}
|
||||
|
||||
AudioFormatReader::~AudioFormatReader()
|
||||
{
|
||||
delete input;
|
||||
}
|
||||
|
||||
bool AudioFormatReader::read (int* const* destSamples,
|
||||
int numDestChannels,
|
||||
int64 startSampleInSource,
|
||||
int numSamplesToRead,
|
||||
const bool fillLeftoverChannelsWithCopies)
|
||||
{
|
||||
jassert (numDestChannels > 0); // you have to actually give this some channels to work with!
|
||||
|
||||
int startOffsetInDestBuffer = 0;
|
||||
|
||||
if (startSampleInSource < 0)
|
||||
{
|
||||
const int silence = (int) jmin (-startSampleInSource, (int64) numSamplesToRead);
|
||||
|
||||
for (int i = numDestChannels; --i >= 0;)
|
||||
if (destSamples[i] != 0)
|
||||
zeromem (destSamples[i], sizeof (int) * silence);
|
||||
|
||||
startOffsetInDestBuffer += silence;
|
||||
numSamplesToRead -= silence;
|
||||
startSampleInSource = 0;
|
||||
}
|
||||
|
||||
if (numSamplesToRead <= 0)
|
||||
return true;
|
||||
|
||||
if (! readSamples (const_cast<int**> (destSamples),
|
||||
jmin ((int) numChannels, numDestChannels), startOffsetInDestBuffer,
|
||||
startSampleInSource, numSamplesToRead))
|
||||
return false;
|
||||
|
||||
if (numDestChannels > (int) numChannels)
|
||||
{
|
||||
if (fillLeftoverChannelsWithCopies)
|
||||
{
|
||||
int* lastFullChannel = destSamples[0];
|
||||
|
||||
for (int i = (int) numChannels; --i > 0;)
|
||||
{
|
||||
if (destSamples[i] != 0)
|
||||
{
|
||||
lastFullChannel = destSamples[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastFullChannel != 0)
|
||||
for (int i = numChannels; i < numDestChannels; ++i)
|
||||
if (destSamples[i] != 0)
|
||||
memcpy (destSamples[i], lastFullChannel, sizeof (int) * numSamplesToRead);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = numChannels; i < numDestChannels; ++i)
|
||||
if (destSamples[i] != 0)
|
||||
zeromem (destSamples[i], sizeof (int) * numSamplesToRead);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void findAudioBufferMaxMin (const float* const buffer, const int num, float& maxVal, float& minVal) throw()
|
||||
{
|
||||
float mn = buffer[0];
|
||||
float mx = mn;
|
||||
|
||||
for (int i = 1; i < num; ++i)
|
||||
{
|
||||
const float s = buffer[i];
|
||||
if (s > mx) mx = s;
|
||||
if (s < mn) mn = s;
|
||||
}
|
||||
|
||||
maxVal = mx;
|
||||
minVal = mn;
|
||||
}
|
||||
|
||||
void AudioFormatReader::readMaxLevels (int64 startSampleInFile,
|
||||
int64 numSamples,
|
||||
float& lowestLeft, float& highestLeft,
|
||||
float& lowestRight, float& highestRight)
|
||||
{
|
||||
if (numSamples <= 0)
|
||||
{
|
||||
lowestLeft = 0;
|
||||
lowestRight = 0;
|
||||
highestLeft = 0;
|
||||
highestRight = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const int bufferSize = (int) jmin (numSamples, (int64) 4096);
|
||||
HeapBlock<int> tempSpace (bufferSize * 2 + 64);
|
||||
|
||||
int* tempBuffer[3];
|
||||
tempBuffer[0] = tempSpace.getData();
|
||||
tempBuffer[1] = tempSpace.getData() + bufferSize;
|
||||
tempBuffer[2] = 0;
|
||||
|
||||
if (usesFloatingPointData)
|
||||
{
|
||||
float lmin = 1.0e6f;
|
||||
float lmax = -lmin;
|
||||
float rmin = lmin;
|
||||
float rmax = lmax;
|
||||
|
||||
while (numSamples > 0)
|
||||
{
|
||||
const int numToDo = (int) jmin (numSamples, (int64) bufferSize);
|
||||
read (tempBuffer, 2, startSampleInFile, numToDo, false);
|
||||
|
||||
numSamples -= numToDo;
|
||||
startSampleInFile += numToDo;
|
||||
|
||||
float bufmin, bufmax;
|
||||
findAudioBufferMaxMin (reinterpret_cast<float*> (tempBuffer[0]), numToDo, bufmax, bufmin);
|
||||
lmin = jmin (lmin, bufmin);
|
||||
lmax = jmax (lmax, bufmax);
|
||||
|
||||
if (numChannels > 1)
|
||||
{
|
||||
findAudioBufferMaxMin (reinterpret_cast<float*> (tempBuffer[1]), numToDo, bufmax, bufmin);
|
||||
rmin = jmin (rmin, bufmin);
|
||||
rmax = jmax (rmax, bufmax);
|
||||
}
|
||||
}
|
||||
|
||||
if (numChannels <= 1)
|
||||
{
|
||||
rmax = lmax;
|
||||
rmin = lmin;
|
||||
}
|
||||
|
||||
lowestLeft = lmin;
|
||||
highestLeft = lmax;
|
||||
lowestRight = rmin;
|
||||
highestRight = rmax;
|
||||
}
|
||||
else
|
||||
{
|
||||
int lmax = std::numeric_limits<int>::min();
|
||||
int lmin = std::numeric_limits<int>::max();
|
||||
int rmax = std::numeric_limits<int>::min();
|
||||
int rmin = std::numeric_limits<int>::max();
|
||||
|
||||
while (numSamples > 0)
|
||||
{
|
||||
const int numToDo = (int) jmin (numSamples, (int64) bufferSize);
|
||||
read (tempBuffer, 2, startSampleInFile, numToDo, false);
|
||||
|
||||
numSamples -= numToDo;
|
||||
startSampleInFile += numToDo;
|
||||
|
||||
for (int j = numChannels; --j >= 0;)
|
||||
{
|
||||
int bufMax = std::numeric_limits<int>::min();
|
||||
int bufMin = std::numeric_limits<int>::max();
|
||||
|
||||
const int* const b = tempBuffer[j];
|
||||
|
||||
for (int i = 0; i < numToDo; ++i)
|
||||
{
|
||||
const int samp = b[i];
|
||||
|
||||
if (samp < bufMin)
|
||||
bufMin = samp;
|
||||
|
||||
if (samp > bufMax)
|
||||
bufMax = samp;
|
||||
}
|
||||
|
||||
if (j == 0)
|
||||
{
|
||||
lmax = jmax (lmax, bufMax);
|
||||
lmin = jmin (lmin, bufMin);
|
||||
}
|
||||
else
|
||||
{
|
||||
rmax = jmax (rmax, bufMax);
|
||||
rmin = jmin (rmin, bufMin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numChannels <= 1)
|
||||
{
|
||||
rmax = lmax;
|
||||
rmin = lmin;
|
||||
}
|
||||
|
||||
lowestLeft = lmin / (float) std::numeric_limits<int>::max();
|
||||
highestLeft = lmax / (float) std::numeric_limits<int>::max();
|
||||
lowestRight = rmin / (float) std::numeric_limits<int>::max();
|
||||
highestRight = rmax / (float) std::numeric_limits<int>::max();
|
||||
}
|
||||
}
|
||||
|
||||
int64 AudioFormatReader::searchForLevel (int64 startSample,
|
||||
int64 numSamplesToSearch,
|
||||
const double magnitudeRangeMinimum,
|
||||
const double magnitudeRangeMaximum,
|
||||
const int minimumConsecutiveSamples)
|
||||
{
|
||||
if (numSamplesToSearch == 0)
|
||||
return -1;
|
||||
|
||||
const int bufferSize = 4096;
|
||||
HeapBlock<int> tempSpace (bufferSize * 2 + 64);
|
||||
|
||||
int* tempBuffer[3];
|
||||
tempBuffer[0] = tempSpace.getData();
|
||||
tempBuffer[1] = tempSpace.getData() + bufferSize;
|
||||
tempBuffer[2] = 0;
|
||||
|
||||
int consecutive = 0;
|
||||
int64 firstMatchPos = -1;
|
||||
|
||||
jassert (magnitudeRangeMaximum > magnitudeRangeMinimum);
|
||||
|
||||
const double doubleMin = jlimit (0.0, (double) std::numeric_limits<int>::max(), magnitudeRangeMinimum * std::numeric_limits<int>::max());
|
||||
const double doubleMax = jlimit (doubleMin, (double) std::numeric_limits<int>::max(), magnitudeRangeMaximum * std::numeric_limits<int>::max());
|
||||
const int intMagnitudeRangeMinimum = roundToInt (doubleMin);
|
||||
const int intMagnitudeRangeMaximum = roundToInt (doubleMax);
|
||||
|
||||
while (numSamplesToSearch != 0)
|
||||
{
|
||||
const int numThisTime = (int) jmin (abs64 (numSamplesToSearch), (int64) bufferSize);
|
||||
int64 bufferStart = startSample;
|
||||
|
||||
if (numSamplesToSearch < 0)
|
||||
bufferStart -= numThisTime;
|
||||
|
||||
if (bufferStart >= (int) lengthInSamples)
|
||||
break;
|
||||
|
||||
read (tempBuffer, 2, bufferStart, numThisTime, false);
|
||||
|
||||
int num = numThisTime;
|
||||
while (--num >= 0)
|
||||
{
|
||||
if (numSamplesToSearch < 0)
|
||||
--startSample;
|
||||
|
||||
bool matches = false;
|
||||
const int index = (int) (startSample - bufferStart);
|
||||
|
||||
if (usesFloatingPointData)
|
||||
{
|
||||
const float sample1 = std::abs (((float*) tempBuffer[0]) [index]);
|
||||
|
||||
if (sample1 >= magnitudeRangeMinimum
|
||||
&& sample1 <= magnitudeRangeMaximum)
|
||||
{
|
||||
matches = true;
|
||||
}
|
||||
else if (numChannels > 1)
|
||||
{
|
||||
const float sample2 = std::abs (((float*) tempBuffer[1]) [index]);
|
||||
|
||||
matches = (sample2 >= magnitudeRangeMinimum
|
||||
&& sample2 <= magnitudeRangeMaximum);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const int sample1 = abs (tempBuffer[0] [index]);
|
||||
|
||||
if (sample1 >= intMagnitudeRangeMinimum
|
||||
&& sample1 <= intMagnitudeRangeMaximum)
|
||||
{
|
||||
matches = true;
|
||||
}
|
||||
else if (numChannels > 1)
|
||||
{
|
||||
const int sample2 = abs (tempBuffer[1][index]);
|
||||
|
||||
matches = (sample2 >= intMagnitudeRangeMinimum
|
||||
&& sample2 <= intMagnitudeRangeMaximum);
|
||||
}
|
||||
}
|
||||
|
||||
if (matches)
|
||||
{
|
||||
if (firstMatchPos < 0)
|
||||
firstMatchPos = startSample;
|
||||
|
||||
if (++consecutive >= minimumConsecutiveSamples)
|
||||
{
|
||||
if (firstMatchPos < 0 || firstMatchPos >= lengthInSamples)
|
||||
return -1;
|
||||
|
||||
return firstMatchPos;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
consecutive = 0;
|
||||
firstMatchPos = -1;
|
||||
}
|
||||
|
||||
if (numSamplesToSearch > 0)
|
||||
++startSample;
|
||||
}
|
||||
|
||||
if (numSamplesToSearch > 0)
|
||||
numSamplesToSearch -= numThisTime;
|
||||
else
|
||||
numSamplesToSearch += numThisTime;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
272
src/audio/audio_file_formats/juce_AudioFormatWriter.cpp
Normal file
272
src/audio/audio_file_formats/juce_AudioFormatWriter.cpp
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-10 by Raw Material Software Ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified under the terms of the GNU General
|
||||
Public License (Version 2), as published by the Free Software Foundation.
|
||||
A copy of the license is included in the JUCE distribution, or can be found
|
||||
online at www.gnu.org/licenses.
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.rawmaterialsoftware.com/juce for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../core/juce_StandardHeader.h"
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "juce_AudioFormat.h"
|
||||
#include "../dsp/juce_AudioSampleBuffer.h"
|
||||
#include "../../containers/juce_AbstractFifo.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
AudioFormatWriter::AudioFormatWriter (OutputStream* const out,
|
||||
const String& formatName_,
|
||||
const double rate,
|
||||
const unsigned int numChannels_,
|
||||
const unsigned int bitsPerSample_)
|
||||
: sampleRate (rate),
|
||||
numChannels (numChannels_),
|
||||
bitsPerSample (bitsPerSample_),
|
||||
usesFloatingPointData (false),
|
||||
output (out),
|
||||
formatName (formatName_)
|
||||
{
|
||||
}
|
||||
|
||||
AudioFormatWriter::~AudioFormatWriter()
|
||||
{
|
||||
delete output;
|
||||
}
|
||||
|
||||
bool AudioFormatWriter::writeFromAudioReader (AudioFormatReader& reader,
|
||||
int64 startSample,
|
||||
int64 numSamplesToRead)
|
||||
{
|
||||
const int bufferSize = 16384;
|
||||
AudioSampleBuffer tempBuffer (numChannels, bufferSize);
|
||||
|
||||
int* buffers [128];
|
||||
zerostruct (buffers);
|
||||
|
||||
for (int i = tempBuffer.getNumChannels(); --i >= 0;)
|
||||
buffers[i] = reinterpret_cast<int*> (tempBuffer.getSampleData (i, 0));
|
||||
|
||||
if (numSamplesToRead < 0)
|
||||
numSamplesToRead = reader.lengthInSamples;
|
||||
|
||||
while (numSamplesToRead > 0)
|
||||
{
|
||||
const int numToDo = (int) jmin (numSamplesToRead, (int64) bufferSize);
|
||||
|
||||
if (! reader.read (buffers, numChannels, startSample, numToDo, false))
|
||||
return false;
|
||||
|
||||
if (reader.usesFloatingPointData != isFloatingPoint())
|
||||
{
|
||||
int** bufferChan = buffers;
|
||||
|
||||
while (*bufferChan != 0)
|
||||
{
|
||||
int* b = *bufferChan++;
|
||||
|
||||
if (isFloatingPoint())
|
||||
{
|
||||
// int -> float
|
||||
const double factor = 1.0 / std::numeric_limits<int>::max();
|
||||
|
||||
for (int i = 0; i < numToDo; ++i)
|
||||
((float*) b)[i] = (float) (factor * b[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// float -> int
|
||||
for (int i = 0; i < numToDo; ++i)
|
||||
{
|
||||
const double samp = *(const float*) b;
|
||||
|
||||
if (samp <= -1.0)
|
||||
*b++ = std::numeric_limits<int>::min();
|
||||
else if (samp >= 1.0)
|
||||
*b++ = std::numeric_limits<int>::max();
|
||||
else
|
||||
*b++ = roundToInt (std::numeric_limits<int>::max() * samp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! write (const_cast<const int**> (buffers), numToDo))
|
||||
return false;
|
||||
|
||||
numSamplesToRead -= numToDo;
|
||||
startSample += numToDo;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioFormatWriter::writeFromAudioSource (AudioSource& source, int numSamplesToRead, const int samplesPerBlock)
|
||||
{
|
||||
AudioSampleBuffer tempBuffer (getNumChannels(), samplesPerBlock);
|
||||
|
||||
while (numSamplesToRead > 0)
|
||||
{
|
||||
const int numToDo = jmin (numSamplesToRead, samplesPerBlock);
|
||||
|
||||
AudioSourceChannelInfo info;
|
||||
info.buffer = &tempBuffer;
|
||||
info.startSample = 0;
|
||||
info.numSamples = numToDo;
|
||||
info.clearActiveBufferRegion();
|
||||
|
||||
source.getNextAudioBlock (info);
|
||||
|
||||
if (! writeFromAudioSampleBuffer (tempBuffer, 0, numToDo))
|
||||
return false;
|
||||
|
||||
numSamplesToRead -= numToDo;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioFormatWriter::writeFromAudioSampleBuffer (const AudioSampleBuffer& source, int startSample, int numSamples)
|
||||
{
|
||||
jassert (startSample >= 0 && startSample + numSamples <= source.getNumSamples() && source.getNumChannels() > 0);
|
||||
|
||||
if (numSamples <= 0)
|
||||
return true;
|
||||
|
||||
HeapBlock<int> tempBuffer;
|
||||
HeapBlock<int*> chans (numChannels + 1);
|
||||
chans [numChannels] = 0;
|
||||
|
||||
if (isFloatingPoint())
|
||||
{
|
||||
for (int i = numChannels; --i >= 0;)
|
||||
chans[i] = reinterpret_cast<int*> (source.getSampleData (i, startSample));
|
||||
}
|
||||
else
|
||||
{
|
||||
tempBuffer.malloc (numSamples * numChannels);
|
||||
|
||||
for (unsigned int i = 0; i < numChannels; ++i)
|
||||
{
|
||||
typedef AudioData::Pointer <AudioData::Int32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> DestSampleType;
|
||||
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> SourceSampleType;
|
||||
|
||||
DestSampleType destData (chans[i] = tempBuffer + i * numSamples);
|
||||
SourceSampleType sourceData (source.getSampleData (i, startSample));
|
||||
destData.convertSamples (sourceData, numSamples);
|
||||
}
|
||||
}
|
||||
|
||||
return write ((const int**) chans.getData(), numSamples);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class AudioFormatWriter::ThreadedWriter::Buffer : public TimeSliceClient,
|
||||
public AbstractFifo
|
||||
{
|
||||
public:
|
||||
Buffer (TimeSliceThread& timeSliceThread_, AudioFormatWriter* writer_, int numChannels, int bufferSize)
|
||||
: AbstractFifo (bufferSize),
|
||||
buffer (numChannels, bufferSize),
|
||||
timeSliceThread (timeSliceThread_),
|
||||
writer (writer_), isRunning (true)
|
||||
{
|
||||
timeSliceThread.addTimeSliceClient (this);
|
||||
}
|
||||
|
||||
~Buffer()
|
||||
{
|
||||
isRunning = false;
|
||||
timeSliceThread.removeTimeSliceClient (this);
|
||||
|
||||
while (useTimeSlice())
|
||||
{}
|
||||
}
|
||||
|
||||
bool write (const float** data, int numSamples)
|
||||
{
|
||||
if (numSamples <= 0 || ! isRunning)
|
||||
return true;
|
||||
|
||||
jassert (timeSliceThread.isThreadRunning()); // you need to get your thread running before pumping data into this!
|
||||
|
||||
int start1, size1, start2, size2;
|
||||
prepareToWrite (numSamples, start1, size1, start2, size2);
|
||||
|
||||
if (size1 + size2 < numSamples)
|
||||
return false;
|
||||
|
||||
for (int i = buffer.getNumChannels(); --i >= 0;)
|
||||
{
|
||||
buffer.copyFrom (i, start1, data[i], size1);
|
||||
buffer.copyFrom (i, start2, data[i] + size1, size2);
|
||||
}
|
||||
|
||||
finishedWrite (size1 + size2);
|
||||
timeSliceThread.notify();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool useTimeSlice()
|
||||
{
|
||||
const int numToDo = getTotalSize() / 4;
|
||||
|
||||
int start1, size1, start2, size2;
|
||||
prepareToRead (numToDo, start1, size1, start2, size2);
|
||||
|
||||
if (size1 <= 0)
|
||||
return false;
|
||||
|
||||
writer->writeFromAudioSampleBuffer (buffer, start1, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
writer->writeFromAudioSampleBuffer (buffer, start2, size2);
|
||||
|
||||
finishedRead (size1 + size2);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
AudioSampleBuffer buffer;
|
||||
TimeSliceThread& timeSliceThread;
|
||||
ScopedPointer<AudioFormatWriter> writer;
|
||||
volatile bool isRunning;
|
||||
|
||||
Buffer (const Buffer&);
|
||||
Buffer& operator= (const Buffer&);
|
||||
};
|
||||
|
||||
AudioFormatWriter::ThreadedWriter::ThreadedWriter (AudioFormatWriter* writer, TimeSliceThread& backgroundThread, int numSamplesToBuffer)
|
||||
: buffer (new AudioFormatWriter::ThreadedWriter::Buffer (backgroundThread, writer, writer->numChannels, numSamplesToBuffer))
|
||||
{
|
||||
}
|
||||
|
||||
AudioFormatWriter::ThreadedWriter::~ThreadedWriter()
|
||||
{
|
||||
}
|
||||
|
||||
bool AudioFormatWriter::ThreadedWriter::write (const float** data, int numSamples)
|
||||
{
|
||||
return buffer->write (data, numSamples);
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
#include "../../io/files/juce_FileOutputStream.h"
|
||||
#include "juce_AudioFormatReader.h"
|
||||
#include "../audio_sources/juce_AudioSource.h"
|
||||
#include "../../threads/juce_TimeSliceThread.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -127,6 +128,13 @@ public:
|
|||
int numSamplesToRead,
|
||||
int samplesPerBlock = 2048);
|
||||
|
||||
|
||||
/** Writes some samples from an AudioSampleBuffer.
|
||||
|
||||
*/
|
||||
bool writeFromAudioSampleBuffer (const AudioSampleBuffer& source,
|
||||
int startSample, int numSamples);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the sample rate being used. */
|
||||
double getSampleRate() const throw() { return sampleRate; }
|
||||
|
|
@ -140,6 +148,47 @@ public:
|
|||
/** Returns true if it's a floating-point format, false if it's fixed-point. */
|
||||
bool isFloatingPoint() const throw() { return usesFloatingPointData; }
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Provides a FIFO for an AudioFormatWriter, allowing you to push incoming
|
||||
data into a buffer which will be flushed to disk by a background thread.
|
||||
*/
|
||||
class ThreadedWriter
|
||||
{
|
||||
public:
|
||||
/** Creates a ThreadedWriter for a given writer and a thread.
|
||||
|
||||
The writer object which is passed in here will be owned and deleted by
|
||||
the ThreadedWriter when it is no longer needed.
|
||||
|
||||
To stop the writer and flush the buffer to disk, simply delete this object.
|
||||
*/
|
||||
ThreadedWriter (AudioFormatWriter* writer,
|
||||
TimeSliceThread& backgroundThread,
|
||||
int numSamplesToBuffer);
|
||||
|
||||
/** Destructor. */
|
||||
~ThreadedWriter();
|
||||
|
||||
/** Pushes some incoming audio data into the FIFO.
|
||||
|
||||
If there's enough free space in the buffer, this will add the data to it,
|
||||
|
||||
If the FIFO is too full to accept this many samples, the method will return
|
||||
false - then you could either wait until the background thread has had time to
|
||||
consume some of the buffered data and try again, or you can give up
|
||||
and lost this block.
|
||||
|
||||
The data must be an array containing the same number of channels as the
|
||||
AudioFormatWriter object is using. None of these channels can be null.
|
||||
*/
|
||||
bool write (const float** data, int numSamples);
|
||||
|
||||
private:
|
||||
class Buffer;
|
||||
friend class ScopedPointer<Buffer>;
|
||||
ScopedPointer<Buffer> buffer;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
juce_UseDebuggingNewOperator
|
||||
|
|
@ -172,10 +221,16 @@ protected:
|
|||
for (int i = 0; i < numDestChannels; ++i)
|
||||
{
|
||||
const DestType dest (addBytesToPointer (destData, i * DestType::getBytesPerSample()), numDestChannels);
|
||||
dest.convertSamples (SourceType (*source), numSamples);
|
||||
|
||||
if (source[1] != 0)
|
||||
if (*source != 0)
|
||||
{
|
||||
dest.convertSamples (SourceType (*source), numSamples);
|
||||
++source;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest.clearSamples (numSamples);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -411,20 +411,13 @@ const Array <int> OggVorbisAudioFormat::getPossibleSampleRates()
|
|||
|
||||
const Array <int> OggVorbisAudioFormat::getPossibleBitDepths()
|
||||
{
|
||||
Array <int> depths;
|
||||
depths.add (32);
|
||||
return depths;
|
||||
const int depths[] = { 32, 0 };
|
||||
return Array <int> (depths);
|
||||
}
|
||||
|
||||
bool OggVorbisAudioFormat::canDoStereo()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OggVorbisAudioFormat::canDoMono()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool OggVorbisAudioFormat::canDoStereo() { return true; }
|
||||
bool OggVorbisAudioFormat::canDoMono() { return true; }
|
||||
bool OggVorbisAudioFormat::isCompressed() { return true; }
|
||||
|
||||
AudioFormatReader* OggVorbisAudioFormat::createReaderFor (InputStream* in,
|
||||
const bool deleteStreamIfOpeningFails)
|
||||
|
|
@ -456,11 +449,6 @@ AudioFormatWriter* OggVorbisAudioFormat::createWriterFor (OutputStream* out,
|
|||
return w->ok ? w.release() : 0;
|
||||
}
|
||||
|
||||
bool OggVorbisAudioFormat::isCompressed()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const StringArray OggVorbisAudioFormat::getQualityOptions()
|
||||
{
|
||||
StringArray s;
|
||||
|
|
|
|||
|
|
@ -342,25 +342,11 @@ QuickTimeAudioFormat::~QuickTimeAudioFormat()
|
|||
{
|
||||
}
|
||||
|
||||
const Array <int> QuickTimeAudioFormat::getPossibleSampleRates()
|
||||
{
|
||||
return Array<int>();
|
||||
}
|
||||
const Array <int> QuickTimeAudioFormat::getPossibleSampleRates() { return Array<int>(); }
|
||||
const Array <int> QuickTimeAudioFormat::getPossibleBitDepths() { return Array<int>(); }
|
||||
|
||||
const Array <int> QuickTimeAudioFormat::getPossibleBitDepths()
|
||||
{
|
||||
return Array<int>();
|
||||
}
|
||||
|
||||
bool QuickTimeAudioFormat::canDoStereo()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QuickTimeAudioFormat::canDoMono()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool QuickTimeAudioFormat::canDoStereo() { return true; }
|
||||
bool QuickTimeAudioFormat::canDoMono() { return true; }
|
||||
|
||||
//==============================================================================
|
||||
AudioFormatReader* QuickTimeAudioFormat::createReaderFor (InputStream* sourceStream,
|
||||
|
|
|
|||
|
|
@ -633,45 +633,8 @@ void AudioSampleBuffer::writeToAudioWriter (AudioFormatWriter* writer,
|
|||
const int startSample,
|
||||
const int numSamples) const
|
||||
{
|
||||
jassert (startSample >= 0 && startSample + numSamples <= size && numChannels > 0);
|
||||
|
||||
if (numSamples > 0)
|
||||
{
|
||||
HeapBlock<int> tempBuffer;
|
||||
HeapBlock<int*> chans (numChannels + 1);
|
||||
chans [numChannels] = 0;
|
||||
|
||||
if (writer->isFloatingPoint())
|
||||
{
|
||||
for (int i = numChannels; --i >= 0;)
|
||||
chans[i] = reinterpret_cast<int*> (channels[i] + startSample);
|
||||
}
|
||||
else
|
||||
{
|
||||
tempBuffer.malloc (numSamples * numChannels);
|
||||
|
||||
for (int j = 0; j < numChannels; ++j)
|
||||
{
|
||||
int* const dest = tempBuffer + j * numSamples;
|
||||
const float* const src = channels[j] + startSample;
|
||||
chans[j] = dest;
|
||||
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
const double samp = src[i];
|
||||
|
||||
if (samp <= -1.0)
|
||||
dest[i] = std::numeric_limits<int>::min();
|
||||
else if (samp >= 1.0)
|
||||
dest[i] = std::numeric_limits<int>::max();
|
||||
else
|
||||
dest[i] = roundToInt (std::numeric_limits<int>::max() * samp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writer->write ((const int**) chans.getData(), numSamples);
|
||||
}
|
||||
jassert (writer != 0);
|
||||
writer->writeFromAudioSampleBuffer (*this, startSample, numSamples);
|
||||
}
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
|
|||
123
src/containers/juce_AbstractFifo.cpp
Normal file
123
src/containers/juce_AbstractFifo.cpp
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-10 by Raw Material Software Ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified under the terms of the GNU General
|
||||
Public License (Version 2), as published by the Free Software Foundation.
|
||||
A copy of the license is included in the JUCE distribution, or can be found
|
||||
online at www.gnu.org/licenses.
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.rawmaterialsoftware.com/juce for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../core/juce_StandardHeader.h"
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#include "juce_AbstractFifo.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
AbstractFifo::AbstractFifo (const int capacity) throw()
|
||||
: bufferSize (capacity)
|
||||
{
|
||||
jassert (bufferSize > 0);
|
||||
}
|
||||
|
||||
AbstractFifo::~AbstractFifo() {}
|
||||
|
||||
int AbstractFifo::getTotalSize() const throw() { return bufferSize; }
|
||||
int AbstractFifo::getFreeSpace() const throw() { return bufferSize - getNumReady(); }
|
||||
int AbstractFifo::getNumReady() const throw() { return validEnd.get() - validStart.get(); }
|
||||
|
||||
void AbstractFifo::reset() throw()
|
||||
{
|
||||
validEnd = 0;
|
||||
validStart = 0;
|
||||
}
|
||||
|
||||
void AbstractFifo::setTotalSize (int newSize) throw()
|
||||
{
|
||||
jassert (newSize > 0);
|
||||
reset();
|
||||
bufferSize = newSize;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) throw()
|
||||
{
|
||||
const int vs = validStart.get();
|
||||
const int ve = validEnd.get();
|
||||
|
||||
const int freeSpace = bufferSize - (ve - vs);
|
||||
numToWrite = jmin (numToWrite, freeSpace);
|
||||
|
||||
if (numToWrite <= 0)
|
||||
{
|
||||
startIndex1 = 0;
|
||||
startIndex2 = 0;
|
||||
blockSize1 = 0;
|
||||
blockSize2 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
startIndex1 = (int) (ve % bufferSize);
|
||||
startIndex2 = 0;
|
||||
blockSize1 = jmin (bufferSize - startIndex1, numToWrite);
|
||||
numToWrite -= blockSize1;
|
||||
blockSize2 = numToWrite <= 0 ? 0 : jmin (numToWrite, (int) (vs % bufferSize));
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractFifo::finishedWrite (int numWritten) throw()
|
||||
{
|
||||
jassert (numWritten >= 0 && numWritten < bufferSize);
|
||||
validEnd += numWritten;
|
||||
}
|
||||
|
||||
void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) throw()
|
||||
{
|
||||
const int vs = validStart.get();
|
||||
const int ve = validEnd.get();
|
||||
|
||||
const int numReady = ve - vs;
|
||||
numWanted = jmin (numWanted, numReady);
|
||||
|
||||
if (numWanted <= 0)
|
||||
{
|
||||
startIndex1 = 0;
|
||||
startIndex2 = 0;
|
||||
blockSize1 = 0;
|
||||
blockSize2 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
startIndex1 = (int) (vs % bufferSize);
|
||||
startIndex2 = 0;
|
||||
blockSize1 = jmin (bufferSize - startIndex1, numWanted);
|
||||
numWanted -= blockSize1;
|
||||
blockSize2 = numWanted <= 0 ? 0 : jmin (numWanted, (int) (ve % bufferSize));
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractFifo::finishedRead (int numRead) throw()
|
||||
{
|
||||
jassert (numRead >= 0 && numRead < bufferSize);
|
||||
validStart += numRead;
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
220
src/containers/juce_AbstractFifo.h
Normal file
220
src/containers/juce_AbstractFifo.h
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-10 by Raw Material Software Ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified under the terms of the GNU General
|
||||
Public License (Version 2), as published by the Free Software Foundation.
|
||||
A copy of the license is included in the JUCE distribution, or can be found
|
||||
online at www.gnu.org/licenses.
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.rawmaterialsoftware.com/juce for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JUCE_ABSTRACTFIFO_JUCEHEADER__
|
||||
#define __JUCE_ABSTRACTFIFO_JUCEHEADER__
|
||||
|
||||
#include "../core/juce_Atomic.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Encapsulates the logic required to implement a lock-free FIFO.
|
||||
|
||||
This class handles the logic needed when building a single-reader, single-writer FIFO.
|
||||
|
||||
It doesn't actually hold any data itself, but your FIFO class can use one of these to manage
|
||||
its position and status when reading or writing to it.
|
||||
|
||||
To use it, you can call prepareToWrite() to determine the position within your own buffer that
|
||||
an incoming block of data should be stored, and prepareToRead() to find out when the next
|
||||
outgoing block should be read from.
|
||||
|
||||
e.g.
|
||||
@code
|
||||
class MyFifo
|
||||
{
|
||||
public:
|
||||
MyFifo() : abstractFifo (1024)
|
||||
{
|
||||
}
|
||||
|
||||
void addToFifo (const int* someData, int numItems)
|
||||
{
|
||||
int start1, size1, start2, size2;
|
||||
prepareToWrite (numItems, start1, size1, start2, size2);
|
||||
|
||||
if (size1 > 0)
|
||||
copySomeData (myBuffer + start1, someData, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (myBuffer + start2, someData + size1, size2);
|
||||
|
||||
finishedWrite (size1 + size2);
|
||||
}
|
||||
|
||||
void readFromFifo (int* someData, int numItems)
|
||||
{
|
||||
int start1, size1, start2, size2;
|
||||
prepareToRead (numSamples, start1, size1, start2, size2);
|
||||
|
||||
if (size1 > 0)
|
||||
copySomeData (someData, myBuffer + start1, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (someData + size1, myBuffer + start2, size2);
|
||||
|
||||
finishedRead (size1 + size2);
|
||||
}
|
||||
|
||||
private:
|
||||
AbstractFifo abstractFifo;
|
||||
int myBuffer [1024];
|
||||
};
|
||||
@endcode
|
||||
*/
|
||||
class JUCE_API AbstractFifo
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a FIFO to manage a buffer with the specified capacity. */
|
||||
AbstractFifo (int capacity) throw();
|
||||
|
||||
/** Destructor */
|
||||
~AbstractFifo();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the total size of the buffer being managed. */
|
||||
int getTotalSize() const throw();
|
||||
|
||||
/** Returns the number of items that can currently be added to the buffer without it overflowing. */
|
||||
int getFreeSpace() const throw();
|
||||
|
||||
/** Returns the number of items that can currently be read from the buffer. */
|
||||
int getNumReady() const throw();
|
||||
|
||||
/** Clears the buffer positions, so that it appears empty. */
|
||||
void reset() throw();
|
||||
|
||||
/** Changes the buffer's total size.
|
||||
Note that this isn't thread-safe, so don't call it if there's any danger that it
|
||||
might overlap with a call to any other method in this class!
|
||||
*/
|
||||
void setTotalSize (int newSize) throw();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the location within the buffer at which an incoming block of data should be written.
|
||||
|
||||
Because the section of data that you want to add to the buffer may overlap the end
|
||||
and wrap around to the start, two blocks within your buffer are returned, and you
|
||||
should copy your data into the first one, with any remaining data spilling over into
|
||||
the second.
|
||||
|
||||
If the number of items you ask for is too large to fit within the buffer's free space, then
|
||||
blockSize1 + blockSize2 may add up to a lower value than numToWrite.
|
||||
|
||||
After calling this method, and writing your data, you must call finishedWrite() to tell the
|
||||
FIFO how much data you actually added.
|
||||
|
||||
e.g.
|
||||
@code
|
||||
void addToFifo (const int* someData, int numItems)
|
||||
{
|
||||
int start1, size1, start2, size2;
|
||||
prepareToWrite (numItems, start1, size1, start2, size2);
|
||||
|
||||
if (size1 > 0)
|
||||
copySomeData (myBuffer + start1, someData, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (myBuffer + start2, someData + size1, size2);
|
||||
|
||||
finishedWrite (size1 + size2);
|
||||
}
|
||||
@endcode
|
||||
|
||||
@param numToWrite indicates how many items you'd like to add to the buffer
|
||||
@param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
|
||||
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
|
||||
@param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
|
||||
the first block should be written
|
||||
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex2
|
||||
@see finishedWrite
|
||||
*/
|
||||
void prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) throw();
|
||||
|
||||
/** Called after reading from the FIFO, to indicate that this many items have been added.
|
||||
@see prepareToWrite
|
||||
*/
|
||||
void finishedWrite (int numWritten) throw();
|
||||
|
||||
/** Returns the location within the buffer from which the next block of data should be read.
|
||||
|
||||
Because the section of data that you want to read from the buffer may overlap the end
|
||||
and wrap around to the start, two blocks within your buffer are returned, and you
|
||||
should read from both of them.
|
||||
|
||||
If the number of items you ask for is greater than the amount of data available, then
|
||||
blockSize1 + blockSize2 may add up to a lower value than numWanted.
|
||||
|
||||
After calling this method, and reading the data, you must call finishedRead() to tell the
|
||||
FIFO how much data you have consumed.
|
||||
|
||||
e.g.
|
||||
@code
|
||||
void readFromFifo (int* someData, int numItems)
|
||||
{
|
||||
int start1, size1, start2, size2;
|
||||
prepareToRead (numSamples, start1, size1, start2, size2);
|
||||
|
||||
if (size1 > 0)
|
||||
copySomeData (someData, myBuffer + start1, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (someData + size1, myBuffer + start2, size2);
|
||||
|
||||
finishedRead (size1 + size2);
|
||||
}
|
||||
@endcode
|
||||
|
||||
@param numToWrite indicates how many items you'd like to add to the buffer
|
||||
@param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
|
||||
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
|
||||
@param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
|
||||
the first block should be written
|
||||
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex2
|
||||
@see finishedRead
|
||||
*/
|
||||
void prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) throw();
|
||||
|
||||
/** Called after reading from the FIFO, to indicate that this many items have now been consumed.
|
||||
@see prepareToRead
|
||||
*/
|
||||
void finishedRead (int numRead) throw();
|
||||
|
||||
|
||||
//==============================================================================
|
||||
juce_UseDebuggingNewOperator
|
||||
|
||||
private:
|
||||
int bufferSize;
|
||||
Atomic <int> validStart, validEnd;
|
||||
|
||||
AbstractFifo (const AbstractFifo&);
|
||||
AbstractFifo& operator= (const AbstractFifo&);
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCE_ABSTRACTFIFO_JUCEHEADER__
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
*/
|
||||
#define JUCE_MAJOR_VERSION 1
|
||||
#define JUCE_MINOR_VERSION 52
|
||||
#define JUCE_BUILDNUMBER 70
|
||||
#define JUCE_BUILDNUMBER 71
|
||||
|
||||
/** Current Juce version number.
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@
|
|||
#ifndef __JUCE_JUCE_CORE_INCLUDES_INCLUDEFILES__
|
||||
#define __JUCE_JUCE_CORE_INCLUDES_INCLUDEFILES__
|
||||
|
||||
#ifndef __JUCE_ABSTRACTFIFO_JUCEHEADER__
|
||||
#include "containers/juce_AbstractFifo.h"
|
||||
#endif
|
||||
#ifndef __JUCE_ARRAY_JUCEHEADER__
|
||||
#include "containers/juce_Array.h"
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue