| @@ -48,6 +48,8 @@ OBJECTS := \ | |||
| $(OBJDIR)/juce_AudioCDReader_c730f7a6.o \ | |||
| $(OBJDIR)/juce_AudioFormat_6605d0f9.o \ | |||
| $(OBJDIR)/juce_AudioFormatManager_949148fe.o \ | |||
| $(OBJDIR)/juce_AudioFormatReader_36f0295c.o \ | |||
| $(OBJDIR)/juce_AudioFormatWriter_11461d0c.o \ | |||
| $(OBJDIR)/juce_AudioSubsectionReader_65f61a0a.o \ | |||
| $(OBJDIR)/juce_AudioThumbnail_cb99b4b4.o \ | |||
| $(OBJDIR)/juce_AudioThumbnailCache_89a7c678.o \ | |||
| @@ -92,6 +94,7 @@ OBJECTS := \ | |||
| $(OBJDIR)/juce_GenericAudioProcessorEditor_2e8ec30d.o \ | |||
| $(OBJDIR)/juce_Sampler_98f716a4.o \ | |||
| $(OBJDIR)/juce_Synthesiser_2bffa1dd.o \ | |||
| $(OBJDIR)/juce_AbstractFifo_dfc0bd23.o \ | |||
| $(OBJDIR)/juce_BigInteger_63589133.o \ | |||
| $(OBJDIR)/juce_DynamicObject_69d02ab3.o \ | |||
| $(OBJDIR)/juce_Expression_1e9a5aad.o \ | |||
| @@ -404,6 +407,16 @@ $(OBJDIR)/juce_AudioFormatManager_949148fe.o: ../../src/audio/audio_file_formats | |||
| @echo "Compiling juce_AudioFormatManager.cpp" | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| $(OBJDIR)/juce_AudioFormatReader_36f0295c.o: ../../src/audio/audio_file_formats/juce_AudioFormatReader.cpp | |||
| -@mkdir -p $(OBJDIR) | |||
| @echo "Compiling juce_AudioFormatReader.cpp" | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| $(OBJDIR)/juce_AudioFormatWriter_11461d0c.o: ../../src/audio/audio_file_formats/juce_AudioFormatWriter.cpp | |||
| -@mkdir -p $(OBJDIR) | |||
| @echo "Compiling juce_AudioFormatWriter.cpp" | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| $(OBJDIR)/juce_AudioSubsectionReader_65f61a0a.o: ../../src/audio/audio_file_formats/juce_AudioSubsectionReader.cpp | |||
| -@mkdir -p $(OBJDIR) | |||
| @echo "Compiling juce_AudioSubsectionReader.cpp" | |||
| @@ -624,6 +637,11 @@ $(OBJDIR)/juce_Synthesiser_2bffa1dd.o: ../../src/audio/synthesisers/juce_Synthes | |||
| @echo "Compiling juce_Synthesiser.cpp" | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| $(OBJDIR)/juce_AbstractFifo_dfc0bd23.o: ../../src/containers/juce_AbstractFifo.cpp | |||
| -@mkdir -p $(OBJDIR) | |||
| @echo "Compiling juce_AbstractFifo.cpp" | |||
| @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
| $(OBJDIR)/juce_BigInteger_63589133.o: ../../src/containers/juce_BigInteger.cpp | |||
| -@mkdir -p $(OBJDIR) | |||
| @echo "Compiling juce_BigInteger.cpp" | |||
| @@ -15,6 +15,8 @@ | |||
| 983FCD60625A60993546F850 = { isa = PBXBuildFile; fileRef = 0877D5750D6F21C5231687CA; }; | |||
| 416D6F00E88DC74879B4DF2B = { isa = PBXBuildFile; fileRef = 7D85530D76756C33795ECCE9; }; | |||
| 9C709BC2F4F0EE60BF52FACA = { isa = PBXBuildFile; fileRef = 93006D32B18174D9FE0A5E9E; }; | |||
| 992F46189ABF711A047186A4 = { isa = PBXBuildFile; fileRef = 9349E14552FEA0371553E808; }; | |||
| 5C312E6678456C8293633E0F = { isa = PBXBuildFile; fileRef = 2AD64F53E12B20011B7A0DB7; }; | |||
| FB21B7E6A7CE55D3C0E3C37E = { isa = PBXBuildFile; fileRef = 59597FA0A88A08937801D198; }; | |||
| C1147D03F1F4D697CC30DD22 = { isa = PBXBuildFile; fileRef = 27C3C51DF2519B519B76E2EE; }; | |||
| C5CFF5508299C26380465290 = { isa = PBXBuildFile; fileRef = CB32D4EE59D5CA9DB12F944D; }; | |||
| @@ -61,6 +63,7 @@ | |||
| D1407BB28C169F5E1CAC3CC7 = { isa = PBXBuildFile; fileRef = 096CF2243648F17E1BF5421B; }; | |||
| 07E6E11A658930554FF0C56A = { isa = PBXBuildFile; fileRef = ED5966B95F865C586A3CE08F; }; | |||
| E8DFABC1603D55B97429A8E4 = { isa = PBXBuildFile; fileRef = 35668D8EEA19957C6C9AC83A; }; | |||
| 1F905F44E5FA23A2D5CCDA0A = { isa = PBXBuildFile; fileRef = 4F22276689685D839BD252EA; }; | |||
| BE25871C34D79FEFFD1B94B6 = { isa = PBXBuildFile; fileRef = 895D742F49DA9F100990879C; }; | |||
| 4AB5E55BDF79028F82F83D8E = { isa = PBXBuildFile; fileRef = F77C9170829579FABA5679AD; }; | |||
| 25018C91F79D918FEA084630 = { isa = PBXBuildFile; fileRef = 199DFD1C5A282FE13A585FEA; }; | |||
| @@ -359,7 +362,9 @@ | |||
| 013E8938EE1C6B4F63016B55 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioFormat.h; path = ../../src/audio/audio_file_formats/juce_AudioFormat.h; sourceTree = SOURCE_ROOT; }; | |||
| 93006D32B18174D9FE0A5E9E = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioFormatManager.cpp; path = ../../src/audio/audio_file_formats/juce_AudioFormatManager.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 41070806F82EC9C6D1C67689 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioFormatManager.h; path = ../../src/audio/audio_file_formats/juce_AudioFormatManager.h; sourceTree = SOURCE_ROOT; }; | |||
| 9349E14552FEA0371553E808 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioFormatReader.cpp; path = ../../src/audio/audio_file_formats/juce_AudioFormatReader.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 27356F5E93CEA4D472D83D8E = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioFormatReader.h; path = ../../src/audio/audio_file_formats/juce_AudioFormatReader.h; sourceTree = SOURCE_ROOT; }; | |||
| 2AD64F53E12B20011B7A0DB7 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioFormatWriter.cpp; path = ../../src/audio/audio_file_formats/juce_AudioFormatWriter.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 8BD38C2507C0F8E28930A4F8 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioFormatWriter.h; path = ../../src/audio/audio_file_formats/juce_AudioFormatWriter.h; sourceTree = SOURCE_ROOT; }; | |||
| 59597FA0A88A08937801D198 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioSubsectionReader.cpp; path = ../../src/audio/audio_file_formats/juce_AudioSubsectionReader.cpp; sourceTree = SOURCE_ROOT; }; | |||
| AE7F7F0D959C2E3CF5989C88 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioSubsectionReader.h; path = ../../src/audio/audio_file_formats/juce_AudioSubsectionReader.h; sourceTree = SOURCE_ROOT; }; | |||
| @@ -477,6 +482,8 @@ | |||
| 6C6C1C360138D9BD4B27588B = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Sampler.h; path = ../../src/audio/synthesisers/juce_Sampler.h; sourceTree = SOURCE_ROOT; }; | |||
| 35668D8EEA19957C6C9AC83A = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_Synthesiser.cpp; path = ../../src/audio/synthesisers/juce_Synthesiser.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 9E6C206F95245BCDE38FB2B5 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Synthesiser.h; path = ../../src/audio/synthesisers/juce_Synthesiser.h; sourceTree = SOURCE_ROOT; }; | |||
| 4F22276689685D839BD252EA = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AbstractFifo.cpp; path = ../../src/containers/juce_AbstractFifo.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 9584B84F23A4251755D49213 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AbstractFifo.h; path = ../../src/containers/juce_AbstractFifo.h; sourceTree = SOURCE_ROOT; }; | |||
| 839BE8047CF2F8EBE43ED34F = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Array.h; path = ../../src/containers/juce_Array.h; sourceTree = SOURCE_ROOT; }; | |||
| EDF52FDF87ACD33FE933142C = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ArrayAllocationBase.h; path = ../../src/containers/juce_ArrayAllocationBase.h; sourceTree = SOURCE_ROOT; }; | |||
| 895D742F49DA9F100990879C = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_BigInteger.cpp; path = ../../src/containers/juce_BigInteger.cpp; sourceTree = SOURCE_ROOT; }; | |||
| @@ -1048,7 +1055,9 @@ | |||
| 013E8938EE1C6B4F63016B55, | |||
| 93006D32B18174D9FE0A5E9E, | |||
| 41070806F82EC9C6D1C67689, | |||
| 9349E14552FEA0371553E808, | |||
| 27356F5E93CEA4D472D83D8E, | |||
| 2AD64F53E12B20011B7A0DB7, | |||
| 8BD38C2507C0F8E28930A4F8, | |||
| 59597FA0A88A08937801D198, | |||
| AE7F7F0D959C2E3CF5989C88, | |||
| @@ -1195,6 +1204,8 @@ | |||
| 231431F8B23F01DC6ECD4214, | |||
| DC641C77950A335A20FD4532 ); name = audio; sourceTree = "<group>"; }; | |||
| 1CC2889DB696E12FC34E3F50 = { isa = PBXGroup; children = ( | |||
| 4F22276689685D839BD252EA, | |||
| 9584B84F23A4251755D49213, | |||
| 839BE8047CF2F8EBE43ED34F, | |||
| EDF52FDF87ACD33FE933142C, | |||
| 895D742F49DA9F100990879C, | |||
| @@ -1915,6 +1926,8 @@ | |||
| 983FCD60625A60993546F850, | |||
| 416D6F00E88DC74879B4DF2B, | |||
| 9C709BC2F4F0EE60BF52FACA, | |||
| 992F46189ABF711A047186A4, | |||
| 5C312E6678456C8293633E0F, | |||
| FB21B7E6A7CE55D3C0E3C37E, | |||
| C1147D03F1F4D697CC30DD22, | |||
| C5CFF5508299C26380465290, | |||
| @@ -1961,6 +1974,7 @@ | |||
| D1407BB28C169F5E1CAC3CC7, | |||
| 07E6E11A658930554FF0C56A, | |||
| E8DFABC1603D55B97429A8E4, | |||
| 1F905F44E5FA23A2D5CCDA0A, | |||
| BE25871C34D79FEFFD1B94B6, | |||
| 4AB5E55BDF79028F82F83D8E, | |||
| 25018C91F79D918FEA084630, | |||
| @@ -124,7 +124,9 @@ | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormat.h"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatManager.cpp"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatManager.h"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatReader.cpp"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatReader.h"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatWriter.cpp"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatWriter.h"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioSubsectionReader.cpp"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioSubsectionReader.h"/> | |||
| @@ -343,6 +345,8 @@ | |||
| </Filter> | |||
| </Filter> | |||
| <Filter Name="containers"> | |||
| <File RelativePath="..\..\src\containers\juce_AbstractFifo.cpp"/> | |||
| <File RelativePath="..\..\src\containers\juce_AbstractFifo.h"/> | |||
| <File RelativePath="..\..\src\containers\juce_Array.h"/> | |||
| <File RelativePath="..\..\src\containers\juce_ArrayAllocationBase.h"/> | |||
| <File RelativePath="..\..\src\containers\juce_BigInteger.cpp"/> | |||
| @@ -124,7 +124,9 @@ | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormat.h"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatManager.cpp"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatManager.h"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatReader.cpp"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatReader.h"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatWriter.cpp"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatWriter.h"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioSubsectionReader.cpp"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioSubsectionReader.h"/> | |||
| @@ -343,6 +345,8 @@ | |||
| </Filter> | |||
| </Filter> | |||
| <Filter Name="containers"> | |||
| <File RelativePath="..\..\src\containers\juce_AbstractFifo.cpp"/> | |||
| <File RelativePath="..\..\src\containers\juce_AbstractFifo.h"/> | |||
| <File RelativePath="..\..\src\containers\juce_Array.h"/> | |||
| <File RelativePath="..\..\src\containers\juce_ArrayAllocationBase.h"/> | |||
| <File RelativePath="..\..\src\containers\juce_BigInteger.cpp"/> | |||
| @@ -126,7 +126,9 @@ | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormat.h"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatManager.cpp"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatManager.h"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatReader.cpp"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatReader.h"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatWriter.cpp"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioFormatWriter.h"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioSubsectionReader.cpp"/> | |||
| <File RelativePath="..\..\src\audio\audio_file_formats\juce_AudioSubsectionReader.h"/> | |||
| @@ -345,6 +347,8 @@ | |||
| </Filter> | |||
| </Filter> | |||
| <Filter Name="containers"> | |||
| <File RelativePath="..\..\src\containers\juce_AbstractFifo.cpp"/> | |||
| <File RelativePath="..\..\src\containers\juce_AbstractFifo.h"/> | |||
| <File RelativePath="..\..\src\containers\juce_Array.h"/> | |||
| <File RelativePath="..\..\src\containers\juce_ArrayAllocationBase.h"/> | |||
| <File RelativePath="..\..\src\containers\juce_BigInteger.cpp"/> | |||
| @@ -131,6 +131,8 @@ | |||
| <ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioCDReader.cpp"/> | |||
| <ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioFormat.cpp"/> | |||
| <ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioFormatManager.cpp"/> | |||
| <ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioFormatReader.cpp"/> | |||
| <ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioFormatWriter.cpp"/> | |||
| <ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioSubsectionReader.cpp"/> | |||
| <ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioThumbnail.cpp"/> | |||
| <ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioThumbnailCache.cpp"/> | |||
| @@ -175,6 +177,7 @@ | |||
| <ClCompile Include="..\..\src\audio\processors\juce_GenericAudioProcessorEditor.cpp"/> | |||
| <ClCompile Include="..\..\src\audio\synthesisers\juce_Sampler.cpp"/> | |||
| <ClCompile Include="..\..\src\audio\synthesisers\juce_Synthesiser.cpp"/> | |||
| <ClCompile Include="..\..\src\containers\juce_AbstractFifo.cpp"/> | |||
| <ClCompile Include="..\..\src\containers\juce_BigInteger.cpp"/> | |||
| <ClCompile Include="..\..\src\containers\juce_DynamicObject.cpp"/> | |||
| <ClCompile Include="..\..\src\containers\juce_Expression.cpp"/> | |||
| @@ -500,6 +503,7 @@ | |||
| <ClInclude Include="..\..\src\audio\processors\juce_GenericAudioProcessorEditor.h"/> | |||
| <ClInclude Include="..\..\src\audio\synthesisers\juce_Sampler.h"/> | |||
| <ClInclude Include="..\..\src\audio\synthesisers\juce_Synthesiser.h"/> | |||
| <ClInclude Include="..\..\src\containers\juce_AbstractFifo.h"/> | |||
| <ClInclude Include="..\..\src\containers\juce_Array.h"/> | |||
| <ClInclude Include="..\..\src\containers\juce_ArrayAllocationBase.h"/> | |||
| <ClInclude Include="..\..\src\containers\juce_BigInteger.h"/> | |||
| @@ -202,6 +202,12 @@ | |||
| <ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioFormatManager.cpp"> | |||
| <Filter>Juce\Source\audio\audio_file_formats</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioFormatReader.cpp"> | |||
| <Filter>Juce\Source\audio\audio_file_formats</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioFormatWriter.cpp"> | |||
| <Filter>Juce\Source\audio\audio_file_formats</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="..\..\src\audio\audio_file_formats\juce_AudioSubsectionReader.cpp"> | |||
| <Filter>Juce\Source\audio\audio_file_formats</Filter> | |||
| </ClCompile> | |||
| @@ -373,6 +379,9 @@ | |||
| <ClCompile Include="..\..\src\audio\synthesisers\juce_Synthesiser.cpp"> | |||
| <Filter>Juce\Source\audio\synthesisers</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="..\..\src\containers\juce_AbstractFifo.cpp"> | |||
| <Filter>Juce\Source\containers</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="..\..\src\containers\juce_BigInteger.cpp"> | |||
| <Filter>Juce\Source\containers</Filter> | |||
| </ClCompile> | |||
| @@ -1422,6 +1431,9 @@ | |||
| <ClInclude Include="..\..\src\audio\synthesisers\juce_Synthesiser.h"> | |||
| <Filter>Juce\Source\audio\synthesisers</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="..\..\src\containers\juce_AbstractFifo.h"> | |||
| <Filter>Juce\Source\containers</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="..\..\src\containers\juce_Array.h"> | |||
| <Filter>Juce\Source\containers</Filter> | |||
| </ClInclude> | |||
| @@ -15,6 +15,8 @@ | |||
| 983FCD60625A60993546F850 = { isa = PBXBuildFile; fileRef = 0877D5750D6F21C5231687CA; }; | |||
| 416D6F00E88DC74879B4DF2B = { isa = PBXBuildFile; fileRef = 7D85530D76756C33795ECCE9; }; | |||
| 9C709BC2F4F0EE60BF52FACA = { isa = PBXBuildFile; fileRef = 93006D32B18174D9FE0A5E9E; }; | |||
| 992F46189ABF711A047186A4 = { isa = PBXBuildFile; fileRef = 9349E14552FEA0371553E808; }; | |||
| 5C312E6678456C8293633E0F = { isa = PBXBuildFile; fileRef = 2AD64F53E12B20011B7A0DB7; }; | |||
| FB21B7E6A7CE55D3C0E3C37E = { isa = PBXBuildFile; fileRef = 59597FA0A88A08937801D198; }; | |||
| C1147D03F1F4D697CC30DD22 = { isa = PBXBuildFile; fileRef = 27C3C51DF2519B519B76E2EE; }; | |||
| C5CFF5508299C26380465290 = { isa = PBXBuildFile; fileRef = CB32D4EE59D5CA9DB12F944D; }; | |||
| @@ -61,6 +63,7 @@ | |||
| D1407BB28C169F5E1CAC3CC7 = { isa = PBXBuildFile; fileRef = 096CF2243648F17E1BF5421B; }; | |||
| 07E6E11A658930554FF0C56A = { isa = PBXBuildFile; fileRef = ED5966B95F865C586A3CE08F; }; | |||
| E8DFABC1603D55B97429A8E4 = { isa = PBXBuildFile; fileRef = 35668D8EEA19957C6C9AC83A; }; | |||
| 1F905F44E5FA23A2D5CCDA0A = { isa = PBXBuildFile; fileRef = 4F22276689685D839BD252EA; }; | |||
| BE25871C34D79FEFFD1B94B6 = { isa = PBXBuildFile; fileRef = 895D742F49DA9F100990879C; }; | |||
| 4AB5E55BDF79028F82F83D8E = { isa = PBXBuildFile; fileRef = F77C9170829579FABA5679AD; }; | |||
| 25018C91F79D918FEA084630 = { isa = PBXBuildFile; fileRef = 199DFD1C5A282FE13A585FEA; }; | |||
| @@ -359,7 +362,9 @@ | |||
| 013E8938EE1C6B4F63016B55 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioFormat.h; path = ../../src/audio/audio_file_formats/juce_AudioFormat.h; sourceTree = SOURCE_ROOT; }; | |||
| 93006D32B18174D9FE0A5E9E = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioFormatManager.cpp; path = ../../src/audio/audio_file_formats/juce_AudioFormatManager.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 41070806F82EC9C6D1C67689 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioFormatManager.h; path = ../../src/audio/audio_file_formats/juce_AudioFormatManager.h; sourceTree = SOURCE_ROOT; }; | |||
| 9349E14552FEA0371553E808 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioFormatReader.cpp; path = ../../src/audio/audio_file_formats/juce_AudioFormatReader.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 27356F5E93CEA4D472D83D8E = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioFormatReader.h; path = ../../src/audio/audio_file_formats/juce_AudioFormatReader.h; sourceTree = SOURCE_ROOT; }; | |||
| 2AD64F53E12B20011B7A0DB7 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioFormatWriter.cpp; path = ../../src/audio/audio_file_formats/juce_AudioFormatWriter.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 8BD38C2507C0F8E28930A4F8 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioFormatWriter.h; path = ../../src/audio/audio_file_formats/juce_AudioFormatWriter.h; sourceTree = SOURCE_ROOT; }; | |||
| 59597FA0A88A08937801D198 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AudioSubsectionReader.cpp; path = ../../src/audio/audio_file_formats/juce_AudioSubsectionReader.cpp; sourceTree = SOURCE_ROOT; }; | |||
| AE7F7F0D959C2E3CF5989C88 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AudioSubsectionReader.h; path = ../../src/audio/audio_file_formats/juce_AudioSubsectionReader.h; sourceTree = SOURCE_ROOT; }; | |||
| @@ -477,6 +482,8 @@ | |||
| 6C6C1C360138D9BD4B27588B = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Sampler.h; path = ../../src/audio/synthesisers/juce_Sampler.h; sourceTree = SOURCE_ROOT; }; | |||
| 35668D8EEA19957C6C9AC83A = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_Synthesiser.cpp; path = ../../src/audio/synthesisers/juce_Synthesiser.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 9E6C206F95245BCDE38FB2B5 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Synthesiser.h; path = ../../src/audio/synthesisers/juce_Synthesiser.h; sourceTree = SOURCE_ROOT; }; | |||
| 4F22276689685D839BD252EA = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AbstractFifo.cpp; path = ../../src/containers/juce_AbstractFifo.cpp; sourceTree = SOURCE_ROOT; }; | |||
| 9584B84F23A4251755D49213 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AbstractFifo.h; path = ../../src/containers/juce_AbstractFifo.h; sourceTree = SOURCE_ROOT; }; | |||
| 839BE8047CF2F8EBE43ED34F = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Array.h; path = ../../src/containers/juce_Array.h; sourceTree = SOURCE_ROOT; }; | |||
| EDF52FDF87ACD33FE933142C = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ArrayAllocationBase.h; path = ../../src/containers/juce_ArrayAllocationBase.h; sourceTree = SOURCE_ROOT; }; | |||
| 895D742F49DA9F100990879C = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_BigInteger.cpp; path = ../../src/containers/juce_BigInteger.cpp; sourceTree = SOURCE_ROOT; }; | |||
| @@ -1048,7 +1055,9 @@ | |||
| 013E8938EE1C6B4F63016B55, | |||
| 93006D32B18174D9FE0A5E9E, | |||
| 41070806F82EC9C6D1C67689, | |||
| 9349E14552FEA0371553E808, | |||
| 27356F5E93CEA4D472D83D8E, | |||
| 2AD64F53E12B20011B7A0DB7, | |||
| 8BD38C2507C0F8E28930A4F8, | |||
| 59597FA0A88A08937801D198, | |||
| AE7F7F0D959C2E3CF5989C88, | |||
| @@ -1195,6 +1204,8 @@ | |||
| 231431F8B23F01DC6ECD4214, | |||
| DC641C77950A335A20FD4532 ); name = audio; sourceTree = "<group>"; }; | |||
| 1CC2889DB696E12FC34E3F50 = { isa = PBXGroup; children = ( | |||
| 4F22276689685D839BD252EA, | |||
| 9584B84F23A4251755D49213, | |||
| 839BE8047CF2F8EBE43ED34F, | |||
| EDF52FDF87ACD33FE933142C, | |||
| 895D742F49DA9F100990879C, | |||
| @@ -1915,6 +1926,8 @@ | |||
| 983FCD60625A60993546F850, | |||
| 416D6F00E88DC74879B4DF2B, | |||
| 9C709BC2F4F0EE60BF52FACA, | |||
| 992F46189ABF711A047186A4, | |||
| 5C312E6678456C8293633E0F, | |||
| FB21B7E6A7CE55D3C0E3C37E, | |||
| C1147D03F1F4D697CC30DD22, | |||
| C5CFF5508299C26380465290, | |||
| @@ -1961,6 +1974,7 @@ | |||
| D1407BB28C169F5E1CAC3CC7, | |||
| 07E6E11A658930554FF0C56A, | |||
| E8DFABC1603D55B97429A8E4, | |||
| 1F905F44E5FA23A2D5CCDA0A, | |||
| BE25871C34D79FEFFD1B94B6, | |||
| 4AB5E55BDF79028F82F83D8E, | |||
| 25018C91F79D918FEA084630, | |||
| @@ -81,8 +81,12 @@ | |||
| resource="0" file="src/audio/audio_file_formats/juce_AudioFormatManager.cpp"/> | |||
| <FILE id="cz5oBf3fx" name="juce_AudioFormatManager.h" compile="0" resource="0" | |||
| file="src/audio/audio_file_formats/juce_AudioFormatManager.h"/> | |||
| <FILE id="0TiI3po" name="juce_AudioFormatReader.cpp" compile="1" resource="0" | |||
| file="src/audio/audio_file_formats/juce_AudioFormatReader.cpp"/> | |||
| <FILE id="x3bpEuQrJ" name="juce_AudioFormatReader.h" compile="0" resource="0" | |||
| file="src/audio/audio_file_formats/juce_AudioFormatReader.h"/> | |||
| <FILE id="G8yVpHF" name="juce_AudioFormatWriter.cpp" compile="1" resource="0" | |||
| file="src/audio/audio_file_formats/juce_AudioFormatWriter.cpp"/> | |||
| <FILE id="eCeRZdLR" name="juce_AudioFormatWriter.h" compile="0" resource="0" | |||
| file="src/audio/audio_file_formats/juce_AudioFormatWriter.h"/> | |||
| <FILE id="Fo4wJzEFh" name="juce_AudioSubsectionReader.cpp" compile="1" | |||
| @@ -346,6 +350,10 @@ | |||
| </GROUP> | |||
| </GROUP> | |||
| <GROUP id="jDNvJtXHE" name="containers"> | |||
| <FILE id="ChnNms" name="juce_AbstractFifo.cpp" compile="1" resource="0" | |||
| file="src/containers/juce_AbstractFifo.cpp"/> | |||
| <FILE id="llcRKU5" name="juce_AbstractFifo.h" compile="0" resource="0" | |||
| file="src/containers/juce_AbstractFifo.h"/> | |||
| <FILE id="MMVvnl2oo" name="juce_Array.h" compile="0" resource="0" file="src/containers/juce_Array.h"/> | |||
| <FILE id="I2LILZNlU" name="juce_ArrayAllocationBase.h" compile="0" | |||
| resource="0" file="src/containers/juce_ArrayAllocationBase.h"/> | |||
| @@ -103,6 +103,7 @@ | |||
| #include "../src/core/juce_SystemStats.cpp" | |||
| #include "../src/core/juce_Time.cpp" | |||
| #include "../src/core/juce_Initialisation.cpp" | |||
| #include "../src/containers/juce_AbstractFifo.cpp" | |||
| #include "../src/containers/juce_BigInteger.cpp" | |||
| #include "../src/containers/juce_MemoryBlock.cpp" | |||
| #include "../src/containers/juce_PropertySet.cpp" | |||
| @@ -164,6 +165,8 @@ | |||
| #include "../src/utilities/juce_UndoManager.cpp" | |||
| #include "../src/audio/audio_file_formats/juce_AiffAudioFormat.cpp" | |||
| #include "../src/audio/audio_file_formats/juce_AudioFormat.cpp" | |||
| #include "../src/audio/audio_file_formats/juce_AudioFormatReader.cpp" | |||
| #include "../src/audio/audio_file_formats/juce_AudioFormatWriter.cpp" | |||
| #include "../src/audio/audio_file_formats/juce_AudioFormatManager.cpp" | |||
| #include "../src/audio/audio_file_formats/juce_AudioSubsectionReader.cpp" | |||
| #include "../src/audio/audio_file_formats/juce_AudioThumbnail.cpp" | |||
| @@ -505,7 +505,7 @@ private: | |||
| s.add ("ZERO_LINK = NO"); | |||
| if (! isRTAS()) // (dwarf seems to be incompatible with the RTAS libs) | |||
| s.add ("DEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\""); | |||
| s.add ("DEBUG_INFORMATION_FORMAT = \"dwarf\""); | |||
| s.add ("PRODUCT_NAME = \"" + config.getTargetBinaryName().toString() + "\""); | |||
| return s; | |||
| @@ -27,112 +27,19 @@ | |||
| //[MiscUserDefs] You can add your own user definitions and misc code here... | |||
| //============================================================================== | |||
| /* This is a rough-and-ready circular buffer, used to allow the audio thread to | |||
| push data quickly into a queue, allowing a background thread to come along and | |||
| write it to disk later. | |||
| */ | |||
| 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 | |||
| /** A simple class that acts as an AudioIODeviceCallback and writes the | |||
| incoming audio data to a WAV file. | |||
| */ | |||
| class AudioRecorder : public AudioIODeviceCallback | |||
| { | |||
| public: | |||
| AudioRecorder() | |||
| : Thread ("audio recorder"), | |||
| circularBuffer (2, 48000), | |||
| recording (false), | |||
| sampleRate (0) | |||
| : backgroundThread ("Audio Recorder Thread"), | |||
| sampleRate (0), activeWriter (0) | |||
| { | |||
| backgroundThread.startThread(); | |||
| } | |||
| ~AudioRecorder() | |||
| @@ -147,24 +54,49 @@ public: | |||
| if (sampleRate > 0) | |||
| { | |||
| fileToRecord = file; | |||
| startThread(); | |||
| // Create an OutputStream to write to our destination file... | |||
| file.deleteFile(); | |||
| ScopedPointer<FileOutputStream> fileStream (file.createOutputStream()); | |||
| circularBuffer.clear(); | |||
| recording = true; | |||
| if (fileStream != 0) | |||
| { | |||
| // Now create a WAV writer object that writes to our output stream... | |||
| WavAudioFormat wavFormat; | |||
| AudioFormatWriter* writer = wavFormat.createWriterFor (fileStream, sampleRate, 1, 16, StringPairArray(), 0); | |||
| if (writer != 0) | |||
| { | |||
| fileStream.release(); // (passes responsibility for deleting the stream to the writer object that is now using it) | |||
| // Now we'll create one of these helper objects which will act as a FIFO buffer, and will | |||
| // write the data to disk on our background thread. | |||
| threadedWriter = new AudioFormatWriter::ThreadedWriter (writer, backgroundThread, 32768); | |||
| // And now, swap over our active writer pointer so that the audio callback will start using it.. | |||
| const ScopedLock sl (writerLock); | |||
| activeWriter = threadedWriter; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| void stop() | |||
| { | |||
| recording = false; | |||
| // First, clear this pointer to stop the audio callback from using our writer object.. | |||
| { | |||
| const ScopedLock sl (writerLock); | |||
| activeWriter = 0; | |||
| } | |||
| stopThread (5000); | |||
| // Now we can delete the writer object. It's done in this order because the deletion could | |||
| // take a little time while remaining data gets flushed to disk, so it's best to avoid blocking | |||
| // the audio callback while this happens. | |||
| threadedWriter = 0; | |||
| } | |||
| bool isRecording() const | |||
| { | |||
| return isThreadRunning() && recording; | |||
| return activeWriter != 0; | |||
| } | |||
| //============================================================================== | |||
| @@ -182,11 +114,10 @@ public: | |||
| float** outputChannelData, int numOutputChannels, | |||
| int numSamples) | |||
| { | |||
| if (recording) | |||
| { | |||
| const AudioSampleBuffer incomingData ((float**) inputChannelData, numInputChannels, numSamples); | |||
| circularBuffer.addSamplesToBuffer (incomingData, numSamples); | |||
| } | |||
| const ScopedLock sl (writerLock); | |||
| if (activeWriter != 0) | |||
| activeWriter->write (inputChannelData, numSamples); | |||
| // We need to clear the output buffers, in case they're full of junk.. | |||
| for (int i = 0; i < numOutputChannels; ++i) | |||
| @@ -194,44 +125,13 @@ public: | |||
| zeromem (outputChannelData[i], sizeof (float) * numSamples); | |||
| } | |||
| //============================================================================== | |||
| void run() | |||
| { | |||
| fileToRecord.deleteFile(); | |||
| OutputStream* outStream = fileToRecord.createOutputStream(); | |||
| if (outStream == 0) | |||
| return; | |||
| WavAudioFormat wavFormat; | |||
| AudioFormatWriter* writer = wavFormat.createWriterFor (outStream, sampleRate, 1, 16, StringPairArray(), 0); | |||
| if (writer == 0) | |||
| { | |||
| delete outStream; | |||
| return; | |||
| } | |||
| AudioSampleBuffer tempBuffer (2, 8192); | |||
| while (! threadShouldExit()) | |||
| { | |||
| int numSamplesReady = circularBuffer.readSamplesFromBuffer (tempBuffer, tempBuffer.getNumSamples()); | |||
| if (numSamplesReady > 0) | |||
| tempBuffer.writeToAudioWriter (writer, 0, numSamplesReady); | |||
| Thread::sleep (1); | |||
| } | |||
| delete writer; | |||
| } | |||
| File fileToRecord; | |||
| private: | |||
| TimeSliceThread backgroundThread; // the thread that will write our audio data to disk | |||
| ScopedPointer<AudioFormatWriter::ThreadedWriter> threadedWriter; // the FIFO used to buffer the incoming data | |||
| double sampleRate; | |||
| bool recording; | |||
| CircularAudioBuffer circularBuffer; | |||
| CriticalSection writerLock; | |||
| AudioFormatWriter::ThreadedWriter* volatile activeWriter; | |||
| }; | |||
| //[/MiscUserDefs] | |||
| @@ -275,10 +175,9 @@ AudioDemoRecordPage::AudioDemoRecordPage (AudioDeviceManager& deviceManager_) | |||
| AudioDemoRecordPage::~AudioDemoRecordPage() | |||
| { | |||
| //[Destructor_pre]. You can add your own custom destruction code here.. | |||
| recorder->stop(); | |||
| deviceManager.removeAudioCallback (recorder); | |||
| delete recorder; | |||
| deviceManager.removeAudioCallback (liveAudioDisplayComp); | |||
| recorder = 0; | |||
| //[/Destructor_pre] | |||
| deleteAndZero (liveAudioDisplayComp); | |||
| @@ -62,7 +62,7 @@ public: | |||
| private: | |||
| //[UserVariables] -- You can add your own custom variables in this section. | |||
| AudioDeviceManager& deviceManager; | |||
| AudioRecorder* recorder; | |||
| ScopedPointer<AudioRecorder> recorder; | |||
| //[/UserVariables] | |||
| //============================================================================== | |||
| @@ -2407,6 +2407,100 @@ END_JUCE_NAMESPACE | |||
| /*** End of inlined file: juce_Initialisation.cpp ***/ | |||
| /*** Start of inlined file: juce_AbstractFifo.cpp ***/ | |||
| BEGIN_JUCE_NAMESPACE | |||
| AbstractFifo::AbstractFifo (const int capacity) throw() | |||
| : bufferSize (capacity) | |||
| { | |||
| jassert (bufferSize > 0); | |||
| } | |||
| AbstractFifo::~AbstractFifo() {} | |||
| int AbstractFifo::getTotalSize() const throw() { return bufferSize; } | |||
| int AbstractFifo::getFreeSpace() const throw() { return bufferSize - getNumReady(); } | |||
| int AbstractFifo::getNumReady() const throw() { return validEnd.get() - validStart.get(); } | |||
| void AbstractFifo::reset() throw() | |||
| { | |||
| validEnd = 0; | |||
| validStart = 0; | |||
| } | |||
| void AbstractFifo::setTotalSize (int newSize) throw() | |||
| { | |||
| jassert (newSize > 0); | |||
| reset(); | |||
| bufferSize = newSize; | |||
| } | |||
| void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) throw() | |||
| { | |||
| const int vs = validStart.get(); | |||
| const int ve = validEnd.get(); | |||
| const int freeSpace = bufferSize - (ve - vs); | |||
| numToWrite = jmin (numToWrite, freeSpace); | |||
| if (numToWrite <= 0) | |||
| { | |||
| startIndex1 = 0; | |||
| startIndex2 = 0; | |||
| blockSize1 = 0; | |||
| blockSize2 = 0; | |||
| } | |||
| else | |||
| { | |||
| startIndex1 = (int) (ve % bufferSize); | |||
| startIndex2 = 0; | |||
| blockSize1 = jmin (bufferSize - startIndex1, numToWrite); | |||
| numToWrite -= blockSize1; | |||
| blockSize2 = numToWrite <= 0 ? 0 : jmin (numToWrite, (int) (vs % bufferSize)); | |||
| } | |||
| } | |||
| void AbstractFifo::finishedWrite (int numWritten) throw() | |||
| { | |||
| jassert (numWritten >= 0 && numWritten < bufferSize); | |||
| validEnd += numWritten; | |||
| } | |||
| void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) throw() | |||
| { | |||
| const int vs = validStart.get(); | |||
| const int ve = validEnd.get(); | |||
| const int numReady = ve - vs; | |||
| numWanted = jmin (numWanted, numReady); | |||
| if (numWanted <= 0) | |||
| { | |||
| startIndex1 = 0; | |||
| startIndex2 = 0; | |||
| blockSize1 = 0; | |||
| blockSize2 = 0; | |||
| } | |||
| else | |||
| { | |||
| startIndex1 = (int) (vs % bufferSize); | |||
| startIndex2 = 0; | |||
| blockSize1 = jmin (bufferSize - startIndex1, numWanted); | |||
| numWanted -= blockSize1; | |||
| blockSize2 = numWanted <= 0 ? 0 : jmin (numWanted, (int) (ve % bufferSize)); | |||
| } | |||
| } | |||
| void AbstractFifo::finishedRead (int numRead) throw() | |||
| { | |||
| jassert (numRead >= 0 && numRead < bufferSize); | |||
| validStart += numRead; | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| /*** End of inlined file: juce_AbstractFifo.cpp ***/ | |||
| /*** Start of inlined file: juce_BigInteger.cpp ***/ | |||
| BEGIN_JUCE_NAMESPACE | |||
| @@ -20755,7 +20849,7 @@ public: | |||
| { | |||
| switch (bitsPerSample) | |||
| { | |||
| case 8: ReadHelper<AudioData::Int32, AudioData::Int8, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; | |||
| case 8: ReadHelper<AudioData::Int32, AudioData::Int8, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; | |||
| case 16: ReadHelper<AudioData::Int32, AudioData::Int16, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; | |||
| case 24: ReadHelper<AudioData::Int32, AudioData::Int24, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; | |||
| case 32: ReadHelper<AudioData::Int32, AudioData::Int32, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; | |||
| @@ -20766,7 +20860,7 @@ public: | |||
| { | |||
| switch (bitsPerSample) | |||
| { | |||
| case 8: ReadHelper<AudioData::Int32, AudioData::Int8, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; | |||
| case 8: ReadHelper<AudioData::Int32, AudioData::Int8, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; | |||
| case 16: ReadHelper<AudioData::Int32, AudioData::Int16, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; | |||
| case 24: ReadHelper<AudioData::Int32, AudioData::Int24, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; | |||
| case 32: ReadHelper<AudioData::Int32, AudioData::Int32, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; | |||
| @@ -21007,6 +21101,37 @@ END_JUCE_NAMESPACE | |||
| /*** Start of inlined file: juce_AudioFormat.cpp ***/ | |||
| BEGIN_JUCE_NAMESPACE | |||
| AudioFormat::AudioFormat (const String& name, const StringArray& extensions) | |||
| : formatName (name), | |||
| fileExtensions (extensions) | |||
| { | |||
| } | |||
| AudioFormat::~AudioFormat() | |||
| { | |||
| } | |||
| bool AudioFormat::canHandleFile (const File& f) | |||
| { | |||
| for (int i = 0; i < fileExtensions.size(); ++i) | |||
| if (f.hasFileExtension (fileExtensions[i])) | |||
| return true; | |||
| return false; | |||
| } | |||
| const String& AudioFormat::getFormatName() const { return formatName; } | |||
| const StringArray& AudioFormat::getFileExtensions() const { return fileExtensions; } | |||
| bool AudioFormat::isCompressed() { return false; } | |||
| const StringArray AudioFormat::getQualityOptions() { return StringArray(); } | |||
| END_JUCE_NAMESPACE | |||
| /*** End of inlined file: juce_AudioFormat.cpp ***/ | |||
| /*** Start of inlined file: juce_AudioFormatReader.cpp ***/ | |||
| BEGIN_JUCE_NAMESPACE | |||
| AudioFormatReader::AudioFormatReader (InputStream* const in, | |||
| const String& formatName_) | |||
| : sampleRate (0), | |||
| @@ -21338,6 +21463,13 @@ int64 AudioFormatReader::searchForLevel (int64 startSample, | |||
| return -1; | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| /*** End of inlined file: juce_AudioFormatReader.cpp ***/ | |||
| /*** Start of inlined file: juce_AudioFormatWriter.cpp ***/ | |||
| BEGIN_JUCE_NAMESPACE | |||
| AudioFormatWriter::AudioFormatWriter (OutputStream* const out, | |||
| const String& formatName_, | |||
| const double rate, | |||
| @@ -21424,16 +21556,9 @@ bool AudioFormatWriter::writeFromAudioReader (AudioFormatReader& reader, | |||
| return true; | |||
| } | |||
| bool AudioFormatWriter::writeFromAudioSource (AudioSource& source, | |||
| int numSamplesToRead, | |||
| const int samplesPerBlock) | |||
| bool AudioFormatWriter::writeFromAudioSource (AudioSource& source, int numSamplesToRead, const int samplesPerBlock) | |||
| { | |||
| AudioSampleBuffer tempBuffer (getNumChannels(), samplesPerBlock); | |||
| int* buffers [128]; | |||
| zerostruct (buffers); | |||
| for (int i = tempBuffer.getNumChannels(); --i >= 0;) | |||
| buffers[i] = reinterpret_cast<int*> (tempBuffer.getSampleData (i, 0)); | |||
| while (numSamplesToRead > 0) | |||
| { | |||
| @@ -21447,30 +21572,7 @@ bool AudioFormatWriter::writeFromAudioSource (AudioSource& source, | |||
| source.getNextAudioBlock (info); | |||
| if (! isFloatingPoint()) | |||
| { | |||
| int** bufferChan = buffers; | |||
| while (*bufferChan != 0) | |||
| { | |||
| int* b = *bufferChan++; | |||
| // float -> int | |||
| for (int j = numToDo; --j >= 0;) | |||
| { | |||
| const double samp = *(const float*) b; | |||
| if (samp <= -1.0) | |||
| *b++ = std::numeric_limits<int>::min(); | |||
| else if (samp >= 1.0) | |||
| *b++ = std::numeric_limits<int>::max(); | |||
| else | |||
| *b++ = roundToInt (std::numeric_limits<int>::max() * samp); | |||
| } | |||
| } | |||
| } | |||
| if (! write ((const int**) buffers, numToDo)) | |||
| if (! writeFromAudioSampleBuffer (tempBuffer, 0, numToDo)) | |||
| return false; | |||
| numSamplesToRead -= numToDo; | |||
| @@ -21479,48 +21581,131 @@ bool AudioFormatWriter::writeFromAudioSource (AudioSource& source, | |||
| return true; | |||
| } | |||
| AudioFormat::AudioFormat (const String& name, | |||
| const StringArray& extensions) | |||
| : formatName (name), | |||
| fileExtensions (extensions) | |||
| bool AudioFormatWriter::writeFromAudioSampleBuffer (const AudioSampleBuffer& source, int startSample, int numSamples) | |||
| { | |||
| } | |||
| jassert (startSample >= 0 && startSample + numSamples <= source.getNumSamples() && source.getNumChannels() > 0); | |||
| AudioFormat::~AudioFormat() | |||
| { | |||
| } | |||
| if (numSamples <= 0) | |||
| return true; | |||
| const String& AudioFormat::getFormatName() const | |||
| { | |||
| return formatName; | |||
| } | |||
| HeapBlock<int> tempBuffer; | |||
| HeapBlock<int*> chans (numChannels + 1); | |||
| chans [numChannels] = 0; | |||
| const StringArray& AudioFormat::getFileExtensions() const | |||
| { | |||
| return fileExtensions; | |||
| 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); | |||
| } | |||
| bool AudioFormat::canHandleFile (const File& f) | |||
| class AudioFormatWriter::ThreadedWriter::Buffer : public TimeSliceClient, | |||
| public AbstractFifo | |||
| { | |||
| for (int i = 0; i < fileExtensions.size(); ++i) | |||
| if (f.hasFileExtension (fileExtensions[i])) | |||
| 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; | |||
| 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::getPossibleBitDepths() | |||
| { | |||
| return Array<int>(); | |||
| } | |||
| const Array <int> QuickTimeAudioFormat::getPossibleSampleRates() { 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) | |||
| @@ -188,7 +188,7 @@ public: | |||
| { | |||
| switch (bitsPerSample) | |||
| { | |||
| case 8: ReadHelper<AudioData::Int32, AudioData::Int8, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; | |||
| case 8: ReadHelper<AudioData::Int32, AudioData::Int8, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; | |||
| case 16: ReadHelper<AudioData::Int32, AudioData::Int16, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; | |||
| case 24: ReadHelper<AudioData::Int32, AudioData::Int24, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; | |||
| case 32: ReadHelper<AudioData::Int32, AudioData::Int32, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; | |||
| @@ -199,7 +199,7 @@ public: | |||
| { | |||
| switch (bitsPerSample) | |||
| { | |||
| case 8: ReadHelper<AudioData::Int32, AudioData::Int8, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; | |||
| case 8: ReadHelper<AudioData::Int32, AudioData::Int8, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; | |||
| case 16: ReadHelper<AudioData::Int32, AudioData::Int16, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; | |||
| case 24: ReadHelper<AudioData::Int32, AudioData::Int24, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; | |||
| case 32: ReadHelper<AudioData::Int32, AudioData::Int32, AudioData::BigEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, tempBuffer, numChannels, numThisTime); break; | |||
| @@ -28,486 +28,10 @@ | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "juce_AudioFormat.h" | |||
| #include "../dsp/juce_AudioSampleBuffer.h" | |||
| //============================================================================== | |||
| AudioFormatReader::AudioFormatReader (InputStream* const in, | |||
| const String& formatName_) | |||
| : sampleRate (0), | |||
| bitsPerSample (0), | |||
| lengthInSamples (0), | |||
| numChannels (0), | |||
| usesFloatingPointData (false), | |||
| input (in), | |||
| formatName (formatName_) | |||
| { | |||
| } | |||
| AudioFormatReader::~AudioFormatReader() | |||
| { | |||
| delete input; | |||
| } | |||
| bool AudioFormatReader::read (int* const* destSamples, | |||
| int numDestChannels, | |||
| int64 startSampleInSource, | |||
| int numSamplesToRead, | |||
| const bool fillLeftoverChannelsWithCopies) | |||
| { | |||
| jassert (numDestChannels > 0); // you have to actually give this some channels to work with! | |||
| int startOffsetInDestBuffer = 0; | |||
| if (startSampleInSource < 0) | |||
| { | |||
| const int silence = (int) jmin (-startSampleInSource, (int64) numSamplesToRead); | |||
| for (int i = numDestChannels; --i >= 0;) | |||
| if (destSamples[i] != 0) | |||
| zeromem (destSamples[i], sizeof (int) * silence); | |||
| startOffsetInDestBuffer += silence; | |||
| numSamplesToRead -= silence; | |||
| startSampleInSource = 0; | |||
| } | |||
| if (numSamplesToRead <= 0) | |||
| return true; | |||
| if (! readSamples (const_cast<int**> (destSamples), | |||
| jmin ((int) numChannels, numDestChannels), startOffsetInDestBuffer, | |||
| startSampleInSource, numSamplesToRead)) | |||
| return false; | |||
| if (numDestChannels > (int) numChannels) | |||
| { | |||
| if (fillLeftoverChannelsWithCopies) | |||
| { | |||
| int* lastFullChannel = destSamples[0]; | |||
| for (int i = (int) numChannels; --i > 0;) | |||
| { | |||
| if (destSamples[i] != 0) | |||
| { | |||
| lastFullChannel = destSamples[i]; | |||
| break; | |||
| } | |||
| } | |||
| if (lastFullChannel != 0) | |||
| for (int i = numChannels; i < numDestChannels; ++i) | |||
| if (destSamples[i] != 0) | |||
| memcpy (destSamples[i], lastFullChannel, sizeof (int) * numSamplesToRead); | |||
| } | |||
| else | |||
| { | |||
| for (int i = numChannels; i < numDestChannels; ++i) | |||
| if (destSamples[i] != 0) | |||
| zeromem (destSamples[i], sizeof (int) * numSamplesToRead); | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| static void findAudioBufferMaxMin (const float* const buffer, const int num, float& maxVal, float& minVal) throw() | |||
| { | |||
| float mn = buffer[0]; | |||
| float mx = mn; | |||
| for (int i = 1; i < num; ++i) | |||
| { | |||
| const float s = buffer[i]; | |||
| if (s > mx) mx = s; | |||
| if (s < mn) mn = s; | |||
| } | |||
| maxVal = mx; | |||
| minVal = mn; | |||
| } | |||
| void AudioFormatReader::readMaxLevels (int64 startSampleInFile, | |||
| int64 numSamples, | |||
| float& lowestLeft, float& highestLeft, | |||
| float& lowestRight, float& highestRight) | |||
| { | |||
| if (numSamples <= 0) | |||
| { | |||
| lowestLeft = 0; | |||
| lowestRight = 0; | |||
| highestLeft = 0; | |||
| highestRight = 0; | |||
| return; | |||
| } | |||
| const int bufferSize = (int) jmin (numSamples, (int64) 4096); | |||
| HeapBlock<int> tempSpace (bufferSize * 2 + 64); | |||
| int* tempBuffer[3]; | |||
| tempBuffer[0] = tempSpace.getData(); | |||
| tempBuffer[1] = tempSpace.getData() + bufferSize; | |||
| tempBuffer[2] = 0; | |||
| if (usesFloatingPointData) | |||
| { | |||
| float lmin = 1.0e6f; | |||
| float lmax = -lmin; | |||
| float rmin = lmin; | |||
| float rmax = lmax; | |||
| while (numSamples > 0) | |||
| { | |||
| const int numToDo = (int) jmin (numSamples, (int64) bufferSize); | |||
| read (tempBuffer, 2, startSampleInFile, numToDo, false); | |||
| numSamples -= numToDo; | |||
| startSampleInFile += numToDo; | |||
| float bufmin, bufmax; | |||
| findAudioBufferMaxMin (reinterpret_cast<float*> (tempBuffer[0]), numToDo, bufmax, bufmin); | |||
| lmin = jmin (lmin, bufmin); | |||
| lmax = jmax (lmax, bufmax); | |||
| if (numChannels > 1) | |||
| { | |||
| findAudioBufferMaxMin (reinterpret_cast<float*> (tempBuffer[1]), numToDo, bufmax, bufmin); | |||
| rmin = jmin (rmin, bufmin); | |||
| rmax = jmax (rmax, bufmax); | |||
| } | |||
| } | |||
| if (numChannels <= 1) | |||
| { | |||
| rmax = lmax; | |||
| rmin = lmin; | |||
| } | |||
| lowestLeft = lmin; | |||
| highestLeft = lmax; | |||
| lowestRight = rmin; | |||
| highestRight = rmax; | |||
| } | |||
| else | |||
| { | |||
| int lmax = std::numeric_limits<int>::min(); | |||
| int lmin = std::numeric_limits<int>::max(); | |||
| int rmax = std::numeric_limits<int>::min(); | |||
| int rmin = std::numeric_limits<int>::max(); | |||
| while (numSamples > 0) | |||
| { | |||
| const int numToDo = (int) jmin (numSamples, (int64) bufferSize); | |||
| read (tempBuffer, 2, startSampleInFile, numToDo, false); | |||
| numSamples -= numToDo; | |||
| startSampleInFile += numToDo; | |||
| for (int j = numChannels; --j >= 0;) | |||
| { | |||
| int bufMax = std::numeric_limits<int>::min(); | |||
| int bufMin = std::numeric_limits<int>::max(); | |||
| const int* const b = tempBuffer[j]; | |||
| for (int i = 0; i < numToDo; ++i) | |||
| { | |||
| const int samp = b[i]; | |||
| if (samp < bufMin) | |||
| bufMin = samp; | |||
| if (samp > bufMax) | |||
| bufMax = samp; | |||
| } | |||
| if (j == 0) | |||
| { | |||
| lmax = jmax (lmax, bufMax); | |||
| lmin = jmin (lmin, bufMin); | |||
| } | |||
| else | |||
| { | |||
| rmax = jmax (rmax, bufMax); | |||
| rmin = jmin (rmin, bufMin); | |||
| } | |||
| } | |||
| } | |||
| if (numChannels <= 1) | |||
| { | |||
| rmax = lmax; | |||
| rmin = lmin; | |||
| } | |||
| lowestLeft = lmin / (float) std::numeric_limits<int>::max(); | |||
| highestLeft = lmax / (float) std::numeric_limits<int>::max(); | |||
| lowestRight = rmin / (float) std::numeric_limits<int>::max(); | |||
| highestRight = rmax / (float) std::numeric_limits<int>::max(); | |||
| } | |||
| } | |||
| int64 AudioFormatReader::searchForLevel (int64 startSample, | |||
| int64 numSamplesToSearch, | |||
| const double magnitudeRangeMinimum, | |||
| const double magnitudeRangeMaximum, | |||
| const int minimumConsecutiveSamples) | |||
| { | |||
| if (numSamplesToSearch == 0) | |||
| return -1; | |||
| const int bufferSize = 4096; | |||
| HeapBlock<int> tempSpace (bufferSize * 2 + 64); | |||
| int* tempBuffer[3]; | |||
| tempBuffer[0] = tempSpace.getData(); | |||
| tempBuffer[1] = tempSpace.getData() + bufferSize; | |||
| tempBuffer[2] = 0; | |||
| int consecutive = 0; | |||
| int64 firstMatchPos = -1; | |||
| jassert (magnitudeRangeMaximum > magnitudeRangeMinimum); | |||
| const double doubleMin = jlimit (0.0, (double) std::numeric_limits<int>::max(), magnitudeRangeMinimum * std::numeric_limits<int>::max()); | |||
| const double doubleMax = jlimit (doubleMin, (double) std::numeric_limits<int>::max(), magnitudeRangeMaximum * std::numeric_limits<int>::max()); | |||
| const int intMagnitudeRangeMinimum = roundToInt (doubleMin); | |||
| const int intMagnitudeRangeMaximum = roundToInt (doubleMax); | |||
| while (numSamplesToSearch != 0) | |||
| { | |||
| const int numThisTime = (int) jmin (abs64 (numSamplesToSearch), (int64) bufferSize); | |||
| int64 bufferStart = startSample; | |||
| if (numSamplesToSearch < 0) | |||
| bufferStart -= numThisTime; | |||
| if (bufferStart >= (int) lengthInSamples) | |||
| break; | |||
| read (tempBuffer, 2, bufferStart, numThisTime, false); | |||
| int num = numThisTime; | |||
| while (--num >= 0) | |||
| { | |||
| if (numSamplesToSearch < 0) | |||
| --startSample; | |||
| bool matches = false; | |||
| const int index = (int) (startSample - bufferStart); | |||
| if (usesFloatingPointData) | |||
| { | |||
| const float sample1 = std::abs (((float*) tempBuffer[0]) [index]); | |||
| if (sample1 >= magnitudeRangeMinimum | |||
| && sample1 <= magnitudeRangeMaximum) | |||
| { | |||
| matches = true; | |||
| } | |||
| else if (numChannels > 1) | |||
| { | |||
| const float sample2 = std::abs (((float*) tempBuffer[1]) [index]); | |||
| matches = (sample2 >= magnitudeRangeMinimum | |||
| && sample2 <= magnitudeRangeMaximum); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| const int sample1 = abs (tempBuffer[0] [index]); | |||
| if (sample1 >= intMagnitudeRangeMinimum | |||
| && sample1 <= intMagnitudeRangeMaximum) | |||
| { | |||
| matches = true; | |||
| } | |||
| else if (numChannels > 1) | |||
| { | |||
| const int sample2 = abs (tempBuffer[1][index]); | |||
| matches = (sample2 >= intMagnitudeRangeMinimum | |||
| && sample2 <= intMagnitudeRangeMaximum); | |||
| } | |||
| } | |||
| if (matches) | |||
| { | |||
| if (firstMatchPos < 0) | |||
| firstMatchPos = startSample; | |||
| if (++consecutive >= minimumConsecutiveSamples) | |||
| { | |||
| if (firstMatchPos < 0 || firstMatchPos >= lengthInSamples) | |||
| return -1; | |||
| return firstMatchPos; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| consecutive = 0; | |||
| firstMatchPos = -1; | |||
| } | |||
| if (numSamplesToSearch > 0) | |||
| ++startSample; | |||
| } | |||
| if (numSamplesToSearch > 0) | |||
| numSamplesToSearch -= numThisTime; | |||
| else | |||
| numSamplesToSearch += numThisTime; | |||
| } | |||
| return -1; | |||
| } | |||
| //============================================================================== | |||
| AudioFormatWriter::AudioFormatWriter (OutputStream* const out, | |||
| const String& formatName_, | |||
| const double rate, | |||
| const unsigned int numChannels_, | |||
| const unsigned int bitsPerSample_) | |||
| : sampleRate (rate), | |||
| numChannels (numChannels_), | |||
| bitsPerSample (bitsPerSample_), | |||
| usesFloatingPointData (false), | |||
| output (out), | |||
| formatName (formatName_) | |||
| { | |||
| } | |||
| AudioFormatWriter::~AudioFormatWriter() | |||
| { | |||
| delete output; | |||
| } | |||
| bool AudioFormatWriter::writeFromAudioReader (AudioFormatReader& reader, | |||
| int64 startSample, | |||
| int64 numSamplesToRead) | |||
| { | |||
| const int bufferSize = 16384; | |||
| AudioSampleBuffer tempBuffer (numChannels, bufferSize); | |||
| int* buffers [128]; | |||
| zerostruct (buffers); | |||
| for (int i = tempBuffer.getNumChannels(); --i >= 0;) | |||
| buffers[i] = reinterpret_cast<int*> (tempBuffer.getSampleData (i, 0)); | |||
| if (numSamplesToRead < 0) | |||
| numSamplesToRead = reader.lengthInSamples; | |||
| while (numSamplesToRead > 0) | |||
| { | |||
| const int numToDo = (int) jmin (numSamplesToRead, (int64) bufferSize); | |||
| if (! reader.read (buffers, numChannels, startSample, numToDo, false)) | |||
| return false; | |||
| if (reader.usesFloatingPointData != isFloatingPoint()) | |||
| { | |||
| int** bufferChan = buffers; | |||
| while (*bufferChan != 0) | |||
| { | |||
| int* b = *bufferChan++; | |||
| if (isFloatingPoint()) | |||
| { | |||
| // int -> float | |||
| const double factor = 1.0 / std::numeric_limits<int>::max(); | |||
| for (int i = 0; i < numToDo; ++i) | |||
| ((float*) b)[i] = (float) (factor * b[i]); | |||
| } | |||
| else | |||
| { | |||
| // float -> int | |||
| for (int i = 0; i < numToDo; ++i) | |||
| { | |||
| const double samp = *(const float*) b; | |||
| if (samp <= -1.0) | |||
| *b++ = std::numeric_limits<int>::min(); | |||
| else if (samp >= 1.0) | |||
| *b++ = std::numeric_limits<int>::max(); | |||
| else | |||
| *b++ = roundToInt (std::numeric_limits<int>::max() * samp); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| if (! write (const_cast<const int**> (buffers), numToDo)) | |||
| return false; | |||
| numSamplesToRead -= numToDo; | |||
| startSample += numToDo; | |||
| } | |||
| return true; | |||
| } | |||
| bool AudioFormatWriter::writeFromAudioSource (AudioSource& source, | |||
| int numSamplesToRead, | |||
| const int samplesPerBlock) | |||
| { | |||
| AudioSampleBuffer tempBuffer (getNumChannels(), samplesPerBlock); | |||
| int* buffers [128]; | |||
| zerostruct (buffers); | |||
| for (int i = tempBuffer.getNumChannels(); --i >= 0;) | |||
| buffers[i] = reinterpret_cast<int*> (tempBuffer.getSampleData (i, 0)); | |||
| while (numSamplesToRead > 0) | |||
| { | |||
| const int numToDo = jmin (numSamplesToRead, samplesPerBlock); | |||
| AudioSourceChannelInfo info; | |||
| info.buffer = &tempBuffer; | |||
| info.startSample = 0; | |||
| info.numSamples = numToDo; | |||
| info.clearActiveBufferRegion(); | |||
| source.getNextAudioBlock (info); | |||
| if (! isFloatingPoint()) | |||
| { | |||
| int** bufferChan = buffers; | |||
| while (*bufferChan != 0) | |||
| { | |||
| int* b = *bufferChan++; | |||
| // float -> int | |||
| for (int j = numToDo; --j >= 0;) | |||
| { | |||
| const double samp = *(const float*) b; | |||
| if (samp <= -1.0) | |||
| *b++ = std::numeric_limits<int>::min(); | |||
| else if (samp >= 1.0) | |||
| *b++ = std::numeric_limits<int>::max(); | |||
| else | |||
| *b++ = roundToInt (std::numeric_limits<int>::max() * samp); | |||
| } | |||
| } | |||
| } | |||
| if (! write ((const int**) buffers, numToDo)) | |||
| return false; | |||
| numSamplesToRead -= numToDo; | |||
| } | |||
| return true; | |||
| } | |||
| //============================================================================== | |||
| AudioFormat::AudioFormat (const String& name, | |||
| const StringArray& extensions) | |||
| AudioFormat::AudioFormat (const String& name, const StringArray& extensions) | |||
| : formatName (name), | |||
| fileExtensions (extensions) | |||
| { | |||
| @@ -518,16 +42,6 @@ AudioFormat::~AudioFormat() | |||
| } | |||
| //============================================================================== | |||
| const String& AudioFormat::getFormatName() const | |||
| { | |||
| return formatName; | |||
| } | |||
| const StringArray& AudioFormat::getFileExtensions() const | |||
| { | |||
| return fileExtensions; | |||
| } | |||
| bool AudioFormat::canHandleFile (const File& f) | |||
| { | |||
| for (int i = 0; i < fileExtensions.size(); ++i) | |||
| @@ -537,15 +51,10 @@ bool AudioFormat::canHandleFile (const File& f) | |||
| return false; | |||
| } | |||
| bool AudioFormat::isCompressed() | |||
| { | |||
| return false; | |||
| } | |||
| const StringArray AudioFormat::getQualityOptions() | |||
| { | |||
| return StringArray(); | |||
| } | |||
| const String& AudioFormat::getFormatName() const { return formatName; } | |||
| const StringArray& AudioFormat::getFileExtensions() const { return fileExtensions; } | |||
| bool AudioFormat::isCompressed() { return false; } | |||
| const StringArray AudioFormat::getQualityOptions() { return StringArray(); } | |||
| END_JUCE_NAMESPACE | |||
| @@ -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 | |||
| @@ -0,0 +1,272 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-10 by Raw Material Software Ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||
| Public License (Version 2), as published by the Free Software Foundation. | |||
| A copy of the license is included in the JUCE distribution, or can be found | |||
| online at www.gnu.org/licenses. | |||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||
| ============================================================================== | |||
| */ | |||
| #include "../../core/juce_StandardHeader.h" | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "juce_AudioFormat.h" | |||
| #include "../dsp/juce_AudioSampleBuffer.h" | |||
| #include "../../containers/juce_AbstractFifo.h" | |||
| //============================================================================== | |||
| AudioFormatWriter::AudioFormatWriter (OutputStream* const out, | |||
| const String& formatName_, | |||
| const double rate, | |||
| const unsigned int numChannels_, | |||
| const unsigned int bitsPerSample_) | |||
| : sampleRate (rate), | |||
| numChannels (numChannels_), | |||
| bitsPerSample (bitsPerSample_), | |||
| usesFloatingPointData (false), | |||
| output (out), | |||
| formatName (formatName_) | |||
| { | |||
| } | |||
| AudioFormatWriter::~AudioFormatWriter() | |||
| { | |||
| delete output; | |||
| } | |||
| bool AudioFormatWriter::writeFromAudioReader (AudioFormatReader& reader, | |||
| int64 startSample, | |||
| int64 numSamplesToRead) | |||
| { | |||
| const int bufferSize = 16384; | |||
| AudioSampleBuffer tempBuffer (numChannels, bufferSize); | |||
| int* buffers [128]; | |||
| zerostruct (buffers); | |||
| for (int i = tempBuffer.getNumChannels(); --i >= 0;) | |||
| buffers[i] = reinterpret_cast<int*> (tempBuffer.getSampleData (i, 0)); | |||
| if (numSamplesToRead < 0) | |||
| numSamplesToRead = reader.lengthInSamples; | |||
| while (numSamplesToRead > 0) | |||
| { | |||
| const int numToDo = (int) jmin (numSamplesToRead, (int64) bufferSize); | |||
| if (! reader.read (buffers, numChannels, startSample, numToDo, false)) | |||
| return false; | |||
| if (reader.usesFloatingPointData != isFloatingPoint()) | |||
| { | |||
| int** bufferChan = buffers; | |||
| while (*bufferChan != 0) | |||
| { | |||
| int* b = *bufferChan++; | |||
| if (isFloatingPoint()) | |||
| { | |||
| // int -> float | |||
| const double factor = 1.0 / std::numeric_limits<int>::max(); | |||
| for (int i = 0; i < numToDo; ++i) | |||
| ((float*) b)[i] = (float) (factor * b[i]); | |||
| } | |||
| else | |||
| { | |||
| // float -> int | |||
| for (int i = 0; i < numToDo; ++i) | |||
| { | |||
| const double samp = *(const float*) b; | |||
| if (samp <= -1.0) | |||
| *b++ = std::numeric_limits<int>::min(); | |||
| else if (samp >= 1.0) | |||
| *b++ = std::numeric_limits<int>::max(); | |||
| else | |||
| *b++ = roundToInt (std::numeric_limits<int>::max() * samp); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| if (! write (const_cast<const int**> (buffers), numToDo)) | |||
| return false; | |||
| numSamplesToRead -= numToDo; | |||
| startSample += numToDo; | |||
| } | |||
| return true; | |||
| } | |||
| bool AudioFormatWriter::writeFromAudioSource (AudioSource& source, int numSamplesToRead, const int samplesPerBlock) | |||
| { | |||
| AudioSampleBuffer tempBuffer (getNumChannels(), samplesPerBlock); | |||
| while (numSamplesToRead > 0) | |||
| { | |||
| const int numToDo = jmin (numSamplesToRead, samplesPerBlock); | |||
| AudioSourceChannelInfo info; | |||
| info.buffer = &tempBuffer; | |||
| info.startSample = 0; | |||
| info.numSamples = numToDo; | |||
| info.clearActiveBufferRegion(); | |||
| source.getNextAudioBlock (info); | |||
| if (! writeFromAudioSampleBuffer (tempBuffer, 0, numToDo)) | |||
| return false; | |||
| numSamplesToRead -= numToDo; | |||
| } | |||
| return true; | |||
| } | |||
| bool AudioFormatWriter::writeFromAudioSampleBuffer (const AudioSampleBuffer& source, int startSample, int numSamples) | |||
| { | |||
| jassert (startSample >= 0 && startSample + numSamples <= source.getNumSamples() && source.getNumChannels() > 0); | |||
| if (numSamples <= 0) | |||
| return true; | |||
| HeapBlock<int> tempBuffer; | |||
| HeapBlock<int*> chans (numChannels + 1); | |||
| chans [numChannels] = 0; | |||
| if (isFloatingPoint()) | |||
| { | |||
| for (int i = numChannels; --i >= 0;) | |||
| chans[i] = reinterpret_cast<int*> (source.getSampleData (i, startSample)); | |||
| } | |||
| else | |||
| { | |||
| tempBuffer.malloc (numSamples * numChannels); | |||
| for (unsigned int i = 0; i < numChannels; ++i) | |||
| { | |||
| typedef AudioData::Pointer <AudioData::Int32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> DestSampleType; | |||
| typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> SourceSampleType; | |||
| DestSampleType destData (chans[i] = tempBuffer + i * numSamples); | |||
| SourceSampleType sourceData (source.getSampleData (i, startSample)); | |||
| destData.convertSamples (sourceData, numSamples); | |||
| } | |||
| } | |||
| return write ((const int**) chans.getData(), numSamples); | |||
| } | |||
| //============================================================================== | |||
| class AudioFormatWriter::ThreadedWriter::Buffer : public TimeSliceClient, | |||
| public AbstractFifo | |||
| { | |||
| public: | |||
| Buffer (TimeSliceThread& timeSliceThread_, AudioFormatWriter* writer_, int numChannels, int bufferSize) | |||
| : AbstractFifo (bufferSize), | |||
| buffer (numChannels, bufferSize), | |||
| timeSliceThread (timeSliceThread_), | |||
| writer (writer_), isRunning (true) | |||
| { | |||
| timeSliceThread.addTimeSliceClient (this); | |||
| } | |||
| ~Buffer() | |||
| { | |||
| isRunning = false; | |||
| timeSliceThread.removeTimeSliceClient (this); | |||
| while (useTimeSlice()) | |||
| {} | |||
| } | |||
| bool write (const float** data, int numSamples) | |||
| { | |||
| if (numSamples <= 0 || ! isRunning) | |||
| return true; | |||
| jassert (timeSliceThread.isThreadRunning()); // you need to get your thread running before pumping data into this! | |||
| int start1, size1, start2, size2; | |||
| prepareToWrite (numSamples, start1, size1, start2, size2); | |||
| if (size1 + size2 < numSamples) | |||
| return false; | |||
| for (int i = buffer.getNumChannels(); --i >= 0;) | |||
| { | |||
| buffer.copyFrom (i, start1, data[i], size1); | |||
| buffer.copyFrom (i, start2, data[i] + size1, size2); | |||
| } | |||
| finishedWrite (size1 + size2); | |||
| timeSliceThread.notify(); | |||
| return true; | |||
| } | |||
| bool useTimeSlice() | |||
| { | |||
| const int numToDo = getTotalSize() / 4; | |||
| int start1, size1, start2, size2; | |||
| prepareToRead (numToDo, start1, size1, start2, size2); | |||
| if (size1 <= 0) | |||
| return false; | |||
| writer->writeFromAudioSampleBuffer (buffer, start1, size1); | |||
| if (size2 > 0) | |||
| writer->writeFromAudioSampleBuffer (buffer, start2, size2); | |||
| finishedRead (size1 + size2); | |||
| return true; | |||
| } | |||
| private: | |||
| AudioSampleBuffer buffer; | |||
| TimeSliceThread& timeSliceThread; | |||
| ScopedPointer<AudioFormatWriter> writer; | |||
| volatile bool isRunning; | |||
| Buffer (const Buffer&); | |||
| Buffer& operator= (const Buffer&); | |||
| }; | |||
| AudioFormatWriter::ThreadedWriter::ThreadedWriter (AudioFormatWriter* writer, TimeSliceThread& backgroundThread, int numSamplesToBuffer) | |||
| : buffer (new AudioFormatWriter::ThreadedWriter::Buffer (backgroundThread, writer, writer->numChannels, numSamplesToBuffer)) | |||
| { | |||
| } | |||
| AudioFormatWriter::ThreadedWriter::~ThreadedWriter() | |||
| { | |||
| } | |||
| bool AudioFormatWriter::ThreadedWriter::write (const float** data, int numSamples) | |||
| { | |||
| return buffer->write (data, numSamples); | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -29,6 +29,7 @@ | |||
| #include "../../io/files/juce_FileOutputStream.h" | |||
| #include "juce_AudioFormatReader.h" | |||
| #include "../audio_sources/juce_AudioSource.h" | |||
| #include "../../threads/juce_TimeSliceThread.h" | |||
| //============================================================================== | |||
| @@ -127,6 +128,13 @@ public: | |||
| int numSamplesToRead, | |||
| int samplesPerBlock = 2048); | |||
| /** Writes some samples from an AudioSampleBuffer. | |||
| */ | |||
| bool writeFromAudioSampleBuffer (const AudioSampleBuffer& source, | |||
| int startSample, int numSamples); | |||
| //============================================================================== | |||
| /** Returns the sample rate being used. */ | |||
| double getSampleRate() const throw() { return sampleRate; } | |||
| @@ -140,6 +148,47 @@ public: | |||
| /** Returns true if it's a floating-point format, false if it's fixed-point. */ | |||
| bool isFloatingPoint() const throw() { return usesFloatingPointData; } | |||
| //============================================================================== | |||
| /** | |||
| Provides a FIFO for an AudioFormatWriter, allowing you to push incoming | |||
| data into a buffer which will be flushed to disk by a background thread. | |||
| */ | |||
| class ThreadedWriter | |||
| { | |||
| public: | |||
| /** Creates a ThreadedWriter for a given writer and a thread. | |||
| The writer object which is passed in here will be owned and deleted by | |||
| the ThreadedWriter when it is no longer needed. | |||
| To stop the writer and flush the buffer to disk, simply delete this object. | |||
| */ | |||
| ThreadedWriter (AudioFormatWriter* writer, | |||
| TimeSliceThread& backgroundThread, | |||
| int numSamplesToBuffer); | |||
| /** Destructor. */ | |||
| ~ThreadedWriter(); | |||
| /** Pushes some incoming audio data into the FIFO. | |||
| If there's enough free space in the buffer, this will add the data to it, | |||
| If the FIFO is too full to accept this many samples, the method will return | |||
| false - then you could either wait until the background thread has had time to | |||
| consume some of the buffered data and try again, or you can give up | |||
| and lost this block. | |||
| The data must be an array containing the same number of channels as the | |||
| AudioFormatWriter object is using. None of these channels can be null. | |||
| */ | |||
| bool write (const float** data, int numSamples); | |||
| private: | |||
| class Buffer; | |||
| friend class ScopedPointer<Buffer>; | |||
| ScopedPointer<Buffer> buffer; | |||
| }; | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| @@ -172,10 +221,16 @@ protected: | |||
| for (int i = 0; i < numDestChannels; ++i) | |||
| { | |||
| const DestType dest (addBytesToPointer (destData, i * DestType::getBytesPerSample()), numDestChannels); | |||
| dest.convertSamples (SourceType (*source), numSamples); | |||
| if (source[1] != 0) | |||
| if (*source != 0) | |||
| { | |||
| dest.convertSamples (SourceType (*source), numSamples); | |||
| ++source; | |||
| } | |||
| else | |||
| { | |||
| dest.clearSamples (numSamples); | |||
| } | |||
| } | |||
| } | |||
| }; | |||
| @@ -411,20 +411,13 @@ const Array <int> OggVorbisAudioFormat::getPossibleSampleRates() | |||
| const Array <int> OggVorbisAudioFormat::getPossibleBitDepths() | |||
| { | |||
| Array <int> depths; | |||
| depths.add (32); | |||
| return depths; | |||
| const int depths[] = { 32, 0 }; | |||
| return Array <int> (depths); | |||
| } | |||
| bool OggVorbisAudioFormat::canDoStereo() | |||
| { | |||
| return true; | |||
| } | |||
| bool OggVorbisAudioFormat::canDoMono() | |||
| { | |||
| return true; | |||
| } | |||
| bool OggVorbisAudioFormat::canDoStereo() { return true; } | |||
| bool OggVorbisAudioFormat::canDoMono() { return true; } | |||
| bool OggVorbisAudioFormat::isCompressed() { return true; } | |||
| AudioFormatReader* OggVorbisAudioFormat::createReaderFor (InputStream* in, | |||
| const bool deleteStreamIfOpeningFails) | |||
| @@ -456,11 +449,6 @@ AudioFormatWriter* OggVorbisAudioFormat::createWriterFor (OutputStream* out, | |||
| return w->ok ? w.release() : 0; | |||
| } | |||
| bool OggVorbisAudioFormat::isCompressed() | |||
| { | |||
| return true; | |||
| } | |||
| const StringArray OggVorbisAudioFormat::getQualityOptions() | |||
| { | |||
| StringArray s; | |||
| @@ -342,25 +342,11 @@ QuickTimeAudioFormat::~QuickTimeAudioFormat() | |||
| { | |||
| } | |||
| const Array <int> QuickTimeAudioFormat::getPossibleSampleRates() | |||
| { | |||
| return Array<int>(); | |||
| } | |||
| const Array <int> QuickTimeAudioFormat::getPossibleBitDepths() | |||
| { | |||
| return Array<int>(); | |||
| } | |||
| const Array <int> QuickTimeAudioFormat::getPossibleSampleRates() { return Array<int>(); } | |||
| const Array <int> QuickTimeAudioFormat::getPossibleBitDepths() { return Array<int>(); } | |||
| bool QuickTimeAudioFormat::canDoStereo() | |||
| { | |||
| return true; | |||
| } | |||
| bool QuickTimeAudioFormat::canDoMono() | |||
| { | |||
| return true; | |||
| } | |||
| bool QuickTimeAudioFormat::canDoStereo() { return true; } | |||
| bool QuickTimeAudioFormat::canDoMono() { return true; } | |||
| //============================================================================== | |||
| AudioFormatReader* QuickTimeAudioFormat::createReaderFor (InputStream* sourceStream, | |||
| @@ -633,45 +633,8 @@ void AudioSampleBuffer::writeToAudioWriter (AudioFormatWriter* writer, | |||
| const int startSample, | |||
| const int numSamples) const | |||
| { | |||
| jassert (startSample >= 0 && startSample + numSamples <= size && numChannels > 0); | |||
| if (numSamples > 0) | |||
| { | |||
| HeapBlock<int> tempBuffer; | |||
| HeapBlock<int*> chans (numChannels + 1); | |||
| chans [numChannels] = 0; | |||
| if (writer->isFloatingPoint()) | |||
| { | |||
| for (int i = numChannels; --i >= 0;) | |||
| chans[i] = reinterpret_cast<int*> (channels[i] + startSample); | |||
| } | |||
| else | |||
| { | |||
| tempBuffer.malloc (numSamples * numChannels); | |||
| for (int j = 0; j < numChannels; ++j) | |||
| { | |||
| int* const dest = tempBuffer + j * numSamples; | |||
| const float* const src = channels[j] + startSample; | |||
| chans[j] = dest; | |||
| for (int i = 0; i < numSamples; ++i) | |||
| { | |||
| const double samp = src[i]; | |||
| if (samp <= -1.0) | |||
| dest[i] = std::numeric_limits<int>::min(); | |||
| else if (samp >= 1.0) | |||
| dest[i] = std::numeric_limits<int>::max(); | |||
| else | |||
| dest[i] = roundToInt (std::numeric_limits<int>::max() * samp); | |||
| } | |||
| } | |||
| } | |||
| writer->write ((const int**) chans.getData(), numSamples); | |||
| } | |||
| jassert (writer != 0); | |||
| writer->writeFromAudioSampleBuffer (*this, startSample, numSamples); | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -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 | |||
| @@ -0,0 +1,220 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-10 by Raw Material Software Ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||
| Public License (Version 2), as published by the Free Software Foundation. | |||
| A copy of the license is included in the JUCE distribution, or can be found | |||
| online at www.gnu.org/licenses. | |||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_ABSTRACTFIFO_JUCEHEADER__ | |||
| #define __JUCE_ABSTRACTFIFO_JUCEHEADER__ | |||
| #include "../core/juce_Atomic.h" | |||
| //============================================================================== | |||
| /** | |||
| Encapsulates the logic required to implement a lock-free FIFO. | |||
| This class handles the logic needed when building a single-reader, single-writer FIFO. | |||
| It doesn't actually hold any data itself, but your FIFO class can use one of these to manage | |||
| its position and status when reading or writing to it. | |||
| To use it, you can call prepareToWrite() to determine the position within your own buffer that | |||
| an incoming block of data should be stored, and prepareToRead() to find out when the next | |||
| outgoing block should be read from. | |||
| e.g. | |||
| @code | |||
| class MyFifo | |||
| { | |||
| public: | |||
| MyFifo() : abstractFifo (1024) | |||
| { | |||
| } | |||
| void addToFifo (const int* someData, int numItems) | |||
| { | |||
| int start1, size1, start2, size2; | |||
| prepareToWrite (numItems, start1, size1, start2, size2); | |||
| if (size1 > 0) | |||
| copySomeData (myBuffer + start1, someData, size1); | |||
| if (size2 > 0) | |||
| copySomeData (myBuffer + start2, someData + size1, size2); | |||
| finishedWrite (size1 + size2); | |||
| } | |||
| void readFromFifo (int* someData, int numItems) | |||
| { | |||
| int start1, size1, start2, size2; | |||
| prepareToRead (numSamples, start1, size1, start2, size2); | |||
| if (size1 > 0) | |||
| copySomeData (someData, myBuffer + start1, size1); | |||
| if (size2 > 0) | |||
| copySomeData (someData + size1, myBuffer + start2, size2); | |||
| finishedRead (size1 + size2); | |||
| } | |||
| private: | |||
| AbstractFifo abstractFifo; | |||
| int myBuffer [1024]; | |||
| }; | |||
| @endcode | |||
| */ | |||
| class JUCE_API AbstractFifo | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** Creates a FIFO to manage a buffer with the specified capacity. */ | |||
| AbstractFifo (int capacity) throw(); | |||
| /** Destructor */ | |||
| ~AbstractFifo(); | |||
| //============================================================================== | |||
| /** Returns the total size of the buffer being managed. */ | |||
| int getTotalSize() const throw(); | |||
| /** Returns the number of items that can currently be added to the buffer without it overflowing. */ | |||
| int getFreeSpace() const throw(); | |||
| /** Returns the number of items that can currently be read from the buffer. */ | |||
| int getNumReady() const throw(); | |||
| /** Clears the buffer positions, so that it appears empty. */ | |||
| void reset() throw(); | |||
| /** Changes the buffer's total size. | |||
| Note that this isn't thread-safe, so don't call it if there's any danger that it | |||
| might overlap with a call to any other method in this class! | |||
| */ | |||
| void setTotalSize (int newSize) throw(); | |||
| //============================================================================== | |||
| /** Returns the location within the buffer at which an incoming block of data should be written. | |||
| Because the section of data that you want to add to the buffer may overlap the end | |||
| and wrap around to the start, two blocks within your buffer are returned, and you | |||
| should copy your data into the first one, with any remaining data spilling over into | |||
| the second. | |||
| If the number of items you ask for is too large to fit within the buffer's free space, then | |||
| blockSize1 + blockSize2 may add up to a lower value than numToWrite. | |||
| After calling this method, and writing your data, you must call finishedWrite() to tell the | |||
| FIFO how much data you actually added. | |||
| e.g. | |||
| @code | |||
| void addToFifo (const int* someData, int numItems) | |||
| { | |||
| int start1, size1, start2, size2; | |||
| prepareToWrite (numItems, start1, size1, start2, size2); | |||
| if (size1 > 0) | |||
| copySomeData (myBuffer + start1, someData, size1); | |||
| if (size2 > 0) | |||
| copySomeData (myBuffer + start2, someData + size1, size2); | |||
| finishedWrite (size1 + size2); | |||
| } | |||
| @endcode | |||
| @param numToWrite indicates how many items you'd like to add to the buffer | |||
| @param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written | |||
| @param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1 | |||
| @param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into | |||
| the first block should be written | |||
| @param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex2 | |||
| @see finishedWrite | |||
| */ | |||
| void prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) throw(); | |||
| /** Called after reading from the FIFO, to indicate that this many items have been added. | |||
| @see prepareToWrite | |||
| */ | |||
| void finishedWrite (int numWritten) throw(); | |||
| /** Returns the location within the buffer from which the next block of data should be read. | |||
| Because the section of data that you want to read from the buffer may overlap the end | |||
| and wrap around to the start, two blocks within your buffer are returned, and you | |||
| should read from both of them. | |||
| If the number of items you ask for is greater than the amount of data available, then | |||
| blockSize1 + blockSize2 may add up to a lower value than numWanted. | |||
| After calling this method, and reading the data, you must call finishedRead() to tell the | |||
| FIFO how much data you have consumed. | |||
| e.g. | |||
| @code | |||
| void readFromFifo (int* someData, int numItems) | |||
| { | |||
| int start1, size1, start2, size2; | |||
| prepareToRead (numSamples, start1, size1, start2, size2); | |||
| if (size1 > 0) | |||
| copySomeData (someData, myBuffer + start1, size1); | |||
| if (size2 > 0) | |||
| copySomeData (someData + size1, myBuffer + start2, size2); | |||
| finishedRead (size1 + size2); | |||
| } | |||
| @endcode | |||
| @param numToWrite indicates how many items you'd like to add to the buffer | |||
| @param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written | |||
| @param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1 | |||
| @param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into | |||
| the first block should be written | |||
| @param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex2 | |||
| @see finishedRead | |||
| */ | |||
| void prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) throw(); | |||
| /** Called after reading from the FIFO, to indicate that this many items have now been consumed. | |||
| @see prepareToRead | |||
| */ | |||
| void finishedRead (int numRead) throw(); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| int bufferSize; | |||
| Atomic <int> validStart, validEnd; | |||
| AbstractFifo (const AbstractFifo&); | |||
| AbstractFifo& operator= (const AbstractFifo&); | |||
| }; | |||
| #endif // __JUCE_ABSTRACTFIFO_JUCEHEADER__ | |||
| @@ -33,7 +33,7 @@ | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 52 | |||
| #define JUCE_BUILDNUMBER 70 | |||
| #define JUCE_BUILDNUMBER 71 | |||
| /** Current Juce version number. | |||
| @@ -26,6 +26,9 @@ | |||
| #ifndef __JUCE_JUCE_CORE_INCLUDES_INCLUDEFILES__ | |||
| #define __JUCE_JUCE_CORE_INCLUDES_INCLUDEFILES__ | |||
| #ifndef __JUCE_ABSTRACTFIFO_JUCEHEADER__ | |||
| #include "containers/juce_AbstractFifo.h" | |||
| #endif | |||
| #ifndef __JUCE_ARRAY_JUCEHEADER__ | |||
| #include "containers/juce_Array.h" | |||
| #endif | |||