1
0
Fork 0
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:
Julian Storer 2010-09-29 17:58:46 +01:00
parent 9a1fde0470
commit 0e2e4e7c3a
27 changed files with 2056 additions and 1227 deletions

View file

@ -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"

View file

@ -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,

View file

@ -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"/>

View file

@ -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"/>

View file

@ -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"/>

View file

@ -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"/>

View file

@ -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>

View file

@ -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,

View file

@ -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"/>

View file

@ -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"

View file

@ -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;

View file

@ -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);

View file

@ -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]
//==============================================================================

View file

@ -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)

View file

@ -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);
}
}
}
};

View file

@ -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;

View file

@ -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

View 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

View 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

View file

@ -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);
}
}
}
};

View file

@ -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;

View file

@ -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,

View file

@ -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

View 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

View 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__

View file

@ -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.

View file

@ -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