1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-09 23:34:20 +00:00

WavAudioFormat: Add support for writing 32 bit integral (PCM) format

This commit is contained in:
attila 2025-05-09 14:53:09 +02:00 committed by Attila Szarvas
parent 34675235e5
commit 386daafe23
43 changed files with 677 additions and 125 deletions

View file

@ -525,6 +525,7 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatReaderSource.h" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatReaderSource.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.h" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriterOptions.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.cpp" "../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.cpp"
"../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.h" "../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.h"
"../../../../../modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp" "../../../../../modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp"
@ -3184,6 +3185,7 @@ set_source_files_properties(
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatReaderSource.h" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatReaderSource.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.h" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriterOptions.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.cpp" "../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.cpp"
"../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.h" "../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.h"
"../../../../../modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp" "../../../../../modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp"

View file

@ -3558,6 +3558,7 @@
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReaderSource.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReaderSource.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriterOptions.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_BufferingAudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_BufferingAudioFormatReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_MemoryMappedAudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_MemoryMappedAudioFormatReader.h"/>

View file

@ -4974,6 +4974,9 @@
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter> <Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriterOptions.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter> <Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude> </ClInclude>

View file

@ -3558,6 +3558,7 @@
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReaderSource.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReaderSource.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriterOptions.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_BufferingAudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_BufferingAudioFormatReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_MemoryMappedAudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_MemoryMappedAudioFormatReader.h"/>

View file

@ -4974,6 +4974,9 @@
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter> <Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriterOptions.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter> <Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude> </ClInclude>

View file

@ -480,6 +480,7 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatReaderSource.h" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatReaderSource.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.h" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriterOptions.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.cpp" "../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.cpp"
"../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.h" "../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.h"
"../../../../../modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp" "../../../../../modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp"
@ -2753,6 +2754,7 @@ set_source_files_properties(
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatReaderSource.h" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatReaderSource.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.h" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriterOptions.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.cpp" "../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.cpp"
"../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.h" "../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.h"
"../../../../../modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp" "../../../../../modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp"

View file

@ -3072,6 +3072,7 @@
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReaderSource.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReaderSource.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriterOptions.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_BufferingAudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_BufferingAudioFormatReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_MemoryMappedAudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_MemoryMappedAudioFormatReader.h"/>

View file

@ -4236,6 +4236,9 @@
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter> <Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriterOptions.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter> <Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude> </ClInclude>

View file

@ -513,6 +513,7 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatReaderSource.h" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatReaderSource.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.h" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriterOptions.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.cpp" "../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.cpp"
"../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.h" "../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.h"
"../../../../../modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp" "../../../../../modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp"
@ -2939,6 +2940,7 @@ set_source_files_properties(
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatReaderSource.h" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatReaderSource.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.h" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriterOptions.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.cpp" "../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.cpp"
"../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.h" "../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.h"
"../../../../../modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp" "../../../../../modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp"

View file

@ -3252,6 +3252,7 @@
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReaderSource.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReaderSource.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriterOptions.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_BufferingAudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_BufferingAudioFormatReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_MemoryMappedAudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_MemoryMappedAudioFormatReader.h"/>

View file

@ -4512,6 +4512,9 @@
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter> <Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriterOptions.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter> <Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude> </ClInclude>

View file

@ -3252,6 +3252,7 @@
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReaderSource.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReaderSource.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriterOptions.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_BufferingAudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_BufferingAudioFormatReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_MemoryMappedAudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_MemoryMappedAudioFormatReader.h"/>

View file

@ -4512,6 +4512,9 @@
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter> <Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriterOptions.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter> <Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude> </ClInclude>

View file

@ -484,6 +484,7 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatReaderSource.h" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatReaderSource.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.h" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriterOptions.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.cpp" "../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.cpp"
"../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.h" "../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.h"
"../../../../../modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp" "../../../../../modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp"
@ -2837,6 +2838,7 @@ set_source_files_properties(
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatReaderSource.h" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatReaderSource.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.h" "../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioFormatWriterOptions.h"
"../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.cpp" "../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.cpp"
"../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.h" "../../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.h"
"../../../../../modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp" "../../../../../modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp"

View file

@ -3163,6 +3163,7 @@
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReaderSource.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReaderSource.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriterOptions.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_BufferingAudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_BufferingAudioFormatReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_MemoryMappedAudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_MemoryMappedAudioFormatReader.h"/>

View file

@ -4377,6 +4377,9 @@
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter> <Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriterOptions.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter> <Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude> </ClInclude>

View file

@ -3364,6 +3364,7 @@
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReaderSource.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReaderSource.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriterOptions.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_BufferingAudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_BufferingAudioFormatReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_MemoryMappedAudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_MemoryMappedAudioFormatReader.h"/>

View file

@ -4671,6 +4671,9 @@
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter> <Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriterOptions.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter> <Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude> </ClInclude>

View file

@ -3364,6 +3364,7 @@
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReaderSource.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReaderSource.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriterOptions.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_BufferingAudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_BufferingAudioFormatReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_MemoryMappedAudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_MemoryMappedAudioFormatReader.h"/>

View file

@ -4671,6 +4671,9 @@
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter> <Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriterOptions.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter> <Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude> </ClInclude>

View file

@ -3139,6 +3139,7 @@
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReaderSource.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatReaderSource.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriterOptions.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_BufferingAudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_BufferingAudioFormatReader.h"/>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_MemoryMappedAudioFormatReader.h"/> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_MemoryMappedAudioFormatReader.h"/>

View file

@ -4344,6 +4344,9 @@
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h"> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriter.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter> <Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioFormatWriterOptions.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h"> <ClInclude Include="..\..\..\..\modules\juce_audio_formats\format\juce_AudioSubsectionReader.h">
<Filter>JUCE Modules\juce_audio_formats\format</Filter> <Filter>JUCE Modules\juce_audio_formats\format</Filter>
</ClInclude> </ClInclude>

View file

@ -1031,4 +1031,20 @@ AudioFormatWriter* AiffAudioFormat::createWriterFor (OutputStream* out,
return nullptr; return nullptr;
} }
std::unique_ptr<AudioFormatWriter> AiffAudioFormat::createWriterFor (std::unique_ptr<OutputStream>& streamToWriteTo,
const AudioFormatWriterOptions& options)
{
if (streamToWriteTo == nullptr || ! getPossibleBitDepths().contains (options.getBitsPerSample()))
return nullptr;
StringPairArray metadata;
metadata.addUnorderedMap (options.getMetadataValues());
return std::make_unique<AiffAudioFormatWriter> (std::exchange (streamToWriteTo, {}).release(),
options.getSampleRate(),
(unsigned int) options.getNumChannels(),
(unsigned int) options.getBitsPerSample(),
metadata);
}
} // namespace juce } // namespace juce

View file

@ -94,6 +94,10 @@ public:
int bitsPerSample, int bitsPerSample,
const StringPairArray& metadataValues, const StringPairArray& metadataValues,
int qualityOptionIndex) override; int qualityOptionIndex) override;
std::unique_ptr<AudioFormatWriter> createWriterFor (std::unique_ptr<OutputStream>& streamToWriteTo,
const AudioFormatWriterOptions& options) override;
using AudioFormat::createWriterFor; using AudioFormat::createWriterFor;
private: private:

View file

@ -665,6 +665,13 @@ AudioFormatWriter* CoreAudioFormat::createWriterFor (OutputStream*,
return nullptr; return nullptr;
} }
std::unique_ptr<AudioFormatWriter> CoreAudioFormat::createWriterFor (std::unique_ptr<OutputStream>&,
const AudioFormatWriterOptions&)
{
jassertfalse; // not yet implemented!
return nullptr;
}
//============================================================================== //==============================================================================
//============================================================================== //==============================================================================

View file

@ -112,6 +112,10 @@ public:
int bitsPerSample, int bitsPerSample,
const StringPairArray& metadataValues, const StringPairArray& metadataValues,
int qualityOptionIndex) override; int qualityOptionIndex) override;
std::unique_ptr<AudioFormatWriter> createWriterFor (std::unique_ptr<OutputStream>& streamToWriteTo,
const AudioFormatWriterOptions& options) override;
using AudioFormat::createWriterFor; using AudioFormat::createWriterFor;
private: private:

View file

@ -610,7 +610,7 @@ AudioFormatWriter* FlacAudioFormat::createWriterFor (OutputStream* out,
if (out != nullptr && getPossibleBitDepths().contains (bitsPerSample)) if (out != nullptr && getPossibleBitDepths().contains (bitsPerSample))
{ {
std::unique_ptr<FlacWriter> w (new FlacWriter (out, sampleRate, numberOfChannels, std::unique_ptr<FlacWriter> w (new FlacWriter (out, sampleRate, numberOfChannels,
(uint32) bitsPerSample, qualityOptionIndex)); (uint32) bitsPerSample, qualityOptionIndex));
if (w->ok) if (w->ok)
return w.release(); return w.release();
} }
@ -618,6 +618,24 @@ AudioFormatWriter* FlacAudioFormat::createWriterFor (OutputStream* out,
return nullptr; return nullptr;
} }
std::unique_ptr<AudioFormatWriter> FlacAudioFormat::createWriterFor (std::unique_ptr<OutputStream>& streamToWriteTo,
const AudioFormatWriterOptions& options)
{
if (streamToWriteTo == nullptr || ! getPossibleBitDepths().contains (options.getBitsPerSample()))
return nullptr;
auto writer = std::make_unique<FlacWriter> (std::exchange (streamToWriteTo, {}).release(),
options.getSampleRate(),
(uint32) options.getNumChannels(),
(uint32) options.getBitsPerSample(),
options.getQualityOptionIndex());
if (! writer->ok)
return nullptr;
return writer;
}
StringArray FlacAudioFormat::getQualityOptions() StringArray FlacAudioFormat::getQualityOptions()
{ {
return { "0 (Fastest)", "1", "2", "3", "4", "5 (Default)","6", "7", "8 (Highest quality)" }; return { "0 (Fastest)", "1", "2", "3", "4", "5 (Default)","6", "7", "8 (Highest quality)" };

View file

@ -63,6 +63,9 @@ public:
StringArray getQualityOptions() override; StringArray getQualityOptions() override;
//============================================================================== //==============================================================================
std::unique_ptr<AudioFormatWriter> createWriterFor (std::unique_ptr<OutputStream>& streamToWriteTo,
const AudioFormatWriterOptions& options) override;
AudioFormatReader* createReaderFor (InputStream* sourceStream, AudioFormatReader* createReaderFor (InputStream* sourceStream,
bool deleteStreamIfOpeningFails) override; bool deleteStreamIfOpeningFails) override;
@ -72,6 +75,7 @@ public:
int bitsPerSample, int bitsPerSample,
const StringPairArray& metadataValues, const StringPairArray& metadataValues,
int qualityOptionIndex) override; int qualityOptionIndex) override;
using AudioFormat::createWriterFor; using AudioFormat::createWriterFor;
private: private:

View file

@ -50,36 +50,39 @@ public:
{ {
WavAudioFormat wavFormat; WavAudioFormat wavFormat;
if (auto out = tempWav.getFile().createOutputStream()) writer = wavFormat.createWriterFor (tempWav.getFile().createOutputStream(),
AudioFormatWriter::Options{}.withSampleRate (sampleRateIn)
.withNumChannels ((int) numberOfChannels)
.withBitsPerSample (bitsPerSampleIn)
.withMetadataValues (metadata));
if (writer == nullptr)
return;
args.add (appFile.getFullPathName());
args.add ("--quiet");
if (cbrBitrate == 0)
{ {
writer.reset (wavFormat.createWriterFor (out.release(), sampleRateIn, numChannels, args.add ("--vbr-new");
bitsPerSampleIn, metadata, 0)); args.add ("-V");
args.add (String (vbrLevel));
args.add (appFile.getFullPathName());
args.add ("--quiet");
if (cbrBitrate == 0)
{
args.add ("--vbr-new");
args.add ("-V");
args.add (String (vbrLevel));
}
else
{
args.add ("--cbr");
args.add ("-b");
args.add (String (cbrBitrate));
}
addMetadataArg (metadata, "id3title", "--tt");
addMetadataArg (metadata, "id3artist", "--ta");
addMetadataArg (metadata, "id3album", "--tl");
addMetadataArg (metadata, "id3comment", "--tc");
addMetadataArg (metadata, "id3date", "--ty");
addMetadataArg (metadata, "id3genre", "--tg");
addMetadataArg (metadata, "id3trackNumber", "--tn");
} }
else
{
args.add ("--cbr");
args.add ("-b");
args.add (String (cbrBitrate));
}
addMetadataArg (metadata, "id3title", "--tt");
addMetadataArg (metadata, "id3artist", "--ta");
addMetadataArg (metadata, "id3album", "--tl");
addMetadataArg (metadata, "id3comment", "--tc");
addMetadataArg (metadata, "id3date", "--ty");
addMetadataArg (metadata, "id3genre", "--tg");
addMetadataArg (metadata, "id3trackNumber", "--tn");
} }
void addMetadataArg (const StringPairArray& metadata, const char* key, const char* lameFlag) void addMetadataArg (const StringPairArray& metadata, const char* key, const char* lameFlag)
@ -165,10 +168,6 @@ LAMEEncoderAudioFormat::LAMEEncoderAudioFormat (const File& lameApplication)
{ {
} }
LAMEEncoderAudioFormat::~LAMEEncoderAudioFormat()
{
}
bool LAMEEncoderAudioFormat::canHandleFile (const File&) bool LAMEEncoderAudioFormat::canHandleFile (const File&)
{ {
return false; return false;
@ -208,6 +207,33 @@ AudioFormatReader* LAMEEncoderAudioFormat::createReaderFor (InputStream*, const
return nullptr; return nullptr;
} }
std::unique_ptr<AudioFormatWriter> LAMEEncoderAudioFormat::createWriterFor (std::unique_ptr<OutputStream> streamToWriteTo,
const AudioFormatWriterOptions& options)
{
if (streamToWriteTo == nullptr)
return nullptr;
int vbr = 4;
int cbr = 0;
const String qual (getQualityOptions() [options.getQualityOptionIndex()]);
if (qual.contains ("VBR"))
vbr = qual.retainCharacters ("0123456789").getIntValue();
else
cbr = qual.getIntValue();
return std::make_unique<Writer> (streamToWriteTo.release(),
getFormatName(),
lameApp,
vbr,
cbr,
options.getSampleRate(),
(unsigned int) options.getNumChannels(),
options.getBitsPerSample(),
options.getMetadataValues());
}
AudioFormatWriter* LAMEEncoderAudioFormat::createWriterFor (OutputStream* streamToWriteTo, AudioFormatWriter* LAMEEncoderAudioFormat::createWriterFor (OutputStream* streamToWriteTo,
double sampleRateToUse, double sampleRateToUse,
unsigned int numberOfChannels, unsigned int numberOfChannels,

View file

@ -60,21 +60,24 @@ public:
executable at the location given. executable at the location given.
*/ */
LAMEEncoderAudioFormat (const File& lameExecutableToUse); LAMEEncoderAudioFormat (const File& lameExecutableToUse);
~LAMEEncoderAudioFormat();
bool canHandleFile (const File&); bool canHandleFile (const File&) override;
Array<int> getPossibleSampleRates(); Array<int> getPossibleSampleRates() override;
Array<int> getPossibleBitDepths(); Array<int> getPossibleBitDepths() override;
bool canDoStereo(); bool canDoStereo() override;
bool canDoMono(); bool canDoMono() override;
bool isCompressed(); bool isCompressed() override;
StringArray getQualityOptions(); StringArray getQualityOptions() override;
AudioFormatReader* createReaderFor (InputStream*, bool deleteStreamIfOpeningFails); std::unique_ptr<AudioFormatWriter> createWriterFor (std::unique_ptr<OutputStream> streamToWriteTo,
const AudioFormatWriterOptions& options) override;
AudioFormatReader* createReaderFor (InputStream*, bool deleteStreamIfOpeningFails) override;
AudioFormatWriter* createWriterFor (OutputStream*, double sampleRateToUse, AudioFormatWriter* createWriterFor (OutputStream*, double sampleRateToUse,
unsigned int numberOfChannels, int bitsPerSample, unsigned int numberOfChannels, int bitsPerSample,
const StringPairArray& metadataValues, int qualityOptionIndex); const StringPairArray& metadataValues, int qualityOptionIndex);
using AudioFormat::createWriterFor; using AudioFormat::createWriterFor;
private: private:

View file

@ -3173,6 +3173,13 @@ AudioFormatReader* MP3AudioFormat::createReaderFor (InputStream* sourceStream, c
return nullptr; return nullptr;
} }
std::unique_ptr<AudioFormatWriter> MP3AudioFormat::createWriterFor (std::unique_ptr<OutputStream>&,
const AudioFormatWriterOptions&)
{
jassertfalse; // not yet implemented!
return nullptr;
}
AudioFormatWriter* MP3AudioFormat::createWriterFor (OutputStream*, double /*sampleRateToUse*/, AudioFormatWriter* MP3AudioFormat::createWriterFor (OutputStream*, double /*sampleRateToUse*/,
unsigned int /*numberOfChannels*/, int /*bitsPerSample*/, unsigned int /*numberOfChannels*/, int /*bitsPerSample*/,
const StringPairArray& /*metadataValues*/, int /*qualityOptionIndex*/) const StringPairArray& /*metadataValues*/, int /*qualityOptionIndex*/)

View file

@ -74,6 +74,10 @@ public:
AudioFormatWriter* createWriterFor (OutputStream*, double sampleRateToUse, AudioFormatWriter* createWriterFor (OutputStream*, double sampleRateToUse,
unsigned int numberOfChannels, int bitsPerSample, unsigned int numberOfChannels, int bitsPerSample,
const StringPairArray& metadataValues, int qualityOptionIndex) override; const StringPairArray& metadataValues, int qualityOptionIndex) override;
std::unique_ptr<AudioFormatWriter> createWriterFor (std::unique_ptr<OutputStream>& streamToWriteTo,
const AudioFormatWriterOptions& options) override;
using AudioFormat::createWriterFor; using AudioFormat::createWriterFor;
}; };

View file

@ -463,6 +463,28 @@ AudioFormatReader* OggVorbisAudioFormat::createReaderFor (InputStream* in, bool
return nullptr; return nullptr;
} }
std::unique_ptr<AudioFormatWriter> OggVorbisAudioFormat::createWriterFor (std::unique_ptr<OutputStream>& streamToWriteTo,
const AudioFormatWriterOptions& options)
{
if (streamToWriteTo == nullptr)
return nullptr;
StringPairArray metadata;
metadata.addUnorderedMap (options.getMetadataValues());
auto w = std::make_unique<OggWriter> (std::exchange (streamToWriteTo, {}).release(),
options.getSampleRate(),
(unsigned int) options.getNumChannels(),
(unsigned int) options.getBitsPerSample(),
options.getQualityOptionIndex(),
metadata);
if (! w->ok)
return nullptr;
return w;
}
AudioFormatWriter* OggVorbisAudioFormat::createWriterFor (OutputStream* out, AudioFormatWriter* OggVorbisAudioFormat::createWriterFor (OutputStream* out,
double sampleRate, double sampleRate,
unsigned int numChannels, unsigned int numChannels,

View file

@ -93,12 +93,16 @@ public:
AudioFormatReader* createReaderFor (InputStream* sourceStream, AudioFormatReader* createReaderFor (InputStream* sourceStream,
bool deleteStreamIfOpeningFails) override; bool deleteStreamIfOpeningFails) override;
std::unique_ptr<AudioFormatWriter> createWriterFor (std::unique_ptr<OutputStream>& streamToWriteTo,
const AudioFormatWriterOptions& options) override;
AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo,
double sampleRateToUse, double sampleRateToUse,
unsigned int numberOfChannels, unsigned int numberOfChannels,
int bitsPerSample, int bitsPerSample,
const StringPairArray& metadataValues, const StringPairArray& metadataValues,
int qualityOptionIndex) override; int qualityOptionIndex) override;
using AudioFormat::createWriterFor; using AudioFormat::createWriterFor;
private: private:

View file

@ -35,18 +35,6 @@
namespace juce namespace juce
{ {
using StringMap = std::unordered_map<String, String>;
static auto toMap (const StringPairArray& array)
{
StringMap result;
for (auto i = 0; i < array.size(); ++i)
result[array.getAllKeys()[i]] = array.getAllValues()[i];
return result;
}
static auto getValueWithDefault (const StringMap& m, const String& key, const String& fallback = {}) static auto getValueWithDefault (const StringMap& m, const String& key, const String& fallback = {})
{ {
const auto iter = m.find (key); const auto iter = m.find (key);
@ -1599,30 +1587,36 @@ class WavAudioFormatWriter final : public AudioFormatWriter
public: public:
WavAudioFormatWriter (OutputStream* const out, const double rate, WavAudioFormatWriter (OutputStream* const out, const double rate,
const AudioChannelSet& channelLayoutToUse, const unsigned int bits, const AudioChannelSet& channelLayoutToUse, const unsigned int bits,
const StringPairArray& metadataValues) const StringMap& metadataValues,
AudioFormatWriterOptions::SampleFormat sampleFormat)
: AudioFormatWriter (out, wavFormatName, rate, channelLayoutToUse, bits) : AudioFormatWriter (out, wavFormatName, rate, channelLayoutToUse, bits)
{ {
using namespace WavFileHelpers; using namespace WavFileHelpers;
using SampleFormat = AudioFormatWriterOptions::SampleFormat;
if (metadataValues.size() > 0) // The floating point format is only supported with a bit depth of 32
jassert (sampleFormat != SampleFormat::floatingPoint || bits == 32);
usesFloatingPointData = bits == 32 && sampleFormat != SampleFormat::integral;
if (! metadataValues.empty())
{ {
// The meta data should have been sanitised for the WAV format. // The meta data should have been sanitised for the WAV format.
// If it was originally sourced from an AIFF file the MetaDataSource // If it was originally sourced from an AIFF file the MetaDataSource
// key should be removed (or set to "WAV") once this has been done // key should be removed (or set to "WAV") once this has been done
jassert (metadataValues.getValue ("MetaDataSource", "None") != "AIFF"); jassert (metadataValues.count ("MetaDataSource") == 0
|| metadataValues.at ("MetaDataSource") != "AIFF");
const auto map = toMap (metadataValues); bwavChunk = BWAVChunk::createFrom (metadataValues);
ixmlChunk = IXMLChunk::createFrom (metadataValues);
bwavChunk = BWAVChunk::createFrom (map); axmlChunk = AXMLChunk::createFrom (metadataValues);
ixmlChunk = IXMLChunk::createFrom (map); smplChunk = SMPLChunk::createFrom (metadataValues);
axmlChunk = AXMLChunk::createFrom (map); instChunk = InstChunk::createFrom (metadataValues);
smplChunk = SMPLChunk::createFrom (map); cueChunk = CueChunk ::createFrom (metadataValues);
instChunk = InstChunk::createFrom (map); listChunk = ListChunk::createFrom (metadataValues);
cueChunk = CueChunk ::createFrom (map); listInfoChunk = ListInfoChunk::createFrom (metadataValues);
listChunk = ListChunk::createFrom (map); acidChunk = AcidChunk::createFrom (metadataValues);
listInfoChunk = ListInfoChunk::createFrom (map); trckChunk = TracktionChunk::createFrom (metadataValues);
acidChunk = AcidChunk::createFrom (map);
trckChunk = TracktionChunk::createFrom (map);
} }
headerPosition = out->getPosition(); headerPosition = out->getPosition();
@ -1773,8 +1767,12 @@ private:
else else
{ {
writeChunkHeader (chunkName ("fmt "), 16); writeChunkHeader (chunkName ("fmt "), 16);
output->writeShort (bitsPerSample < 32 ? (short) 1 /*WAVE_FORMAT_PCM*/
: (short) 3 /*WAVE_FORMAT_IEEE_FLOAT*/); constexpr short waveFormatIeeeFloat = 3;
constexpr short waveFormatPcm = 1;
output->writeShort (usesFloatingPointData ? waveFormatIeeeFloat
: waveFormatPcm);
} }
output->writeShort ((short) numChannels); output->writeShort ((short) numChannels);
@ -1789,7 +1787,7 @@ private:
output->writeShort ((short) bitsPerSample); // wValidBitsPerSample output->writeShort ((short) bitsPerSample); // wValidBitsPerSample
output->writeInt (channelMask); output->writeInt (channelMask);
const ExtensibleWavSubFormat& subFormat = bitsPerSample < 32 ? pcmFormat : IEEEFloatFormat; const ExtensibleWavSubFormat& subFormat = usesFloatingPointData ? IEEEFloatFormat : pcmFormat;
output->writeInt ((int) subFormat.data1); output->writeInt ((int) subFormat.data1);
output->writeShort ((short) subFormat.data2); output->writeShort ((short) subFormat.data2);
@ -1809,8 +1807,6 @@ private:
writeChunk (trckChunk, chunkName ("Trkn")); writeChunk (trckChunk, chunkName ("Trkn"));
writeChunkHeader (chunkName ("data"), isRF64 ? -1 : (int) (lengthInSamples * bytesPerFrame)); writeChunkHeader (chunkName ("data"), isRF64 ? -1 : (int) (lengthInSamples * bytesPerFrame));
usesFloatingPointData = (bitsPerSample == 32);
} }
static size_t chunkSize (const MemoryBlock& data) noexcept { return data.isEmpty() ? 0 : (8 + data.getSize()); } static size_t chunkSize (const MemoryBlock& data) noexcept { return data.isEmpty() ? 0 : (8 + data.getSize()); }
@ -2027,6 +2023,25 @@ MemoryMappedAudioFormatReader* WavAudioFormat::createMemoryMappedReader (FileInp
return nullptr; return nullptr;
} }
std::unique_ptr<AudioFormatWriter> WavAudioFormat::createWriterFor (std::unique_ptr<OutputStream>& streamToWriteTo,
const AudioFormatWriterOptions& options)
{
if (streamToWriteTo == nullptr || ! getPossibleBitDepths().contains (options.getBitsPerSample()))
return nullptr;
const auto layout = options.getChannelLayout().value_or (WavFileHelpers::canonicalWavChannelSet (options.getNumChannels()));
if (! isChannelLayoutSupported (layout))
return nullptr;
return std::make_unique<WavAudioFormatWriter> (std::exchange (streamToWriteTo, {}).release(),
options.getSampleRate(),
layout,
(unsigned int) options.getBitsPerSample(),
options.getMetadataValues(),
options.getSampleFormat());
}
AudioFormatWriter* WavAudioFormat::createWriterFor (OutputStream* out, double sampleRate, AudioFormatWriter* WavAudioFormat::createWriterFor (OutputStream* out, double sampleRate,
unsigned int numChannels, int bitsPerSample, unsigned int numChannels, int bitsPerSample,
const StringPairArray& metadataValues, int qualityOptionIndex) const StringPairArray& metadataValues, int qualityOptionIndex)
@ -2044,44 +2059,39 @@ AudioFormatWriter* WavAudioFormat::createWriterFor (OutputStream* out,
{ {
if (out != nullptr && getPossibleBitDepths().contains (bitsPerSample) && isChannelLayoutSupported (channelLayout)) if (out != nullptr && getPossibleBitDepths().contains (bitsPerSample) && isChannelLayoutSupported (channelLayout))
return new WavAudioFormatWriter (out, sampleRate, channelLayout, return new WavAudioFormatWriter (out, sampleRate, channelLayout,
(unsigned int) bitsPerSample, metadataValues); (unsigned int) bitsPerSample, toMap (metadataValues),
AudioFormatWriterOptions::SampleFormat::automatic);
return nullptr; return nullptr;
} }
namespace WavFileHelpers namespace WavFileHelpers
{ {
static bool slowCopyWavFileWithNewMetadata (const File& file, const StringPairArray& metadata) static bool slowCopyWavFileWithNewMetadata (const File& file, const StringMap& metadata)
{ {
TemporaryFile tempFile (file); TemporaryFile tempFile (file);
WavAudioFormat wav; WavAudioFormat wav;
std::unique_ptr<AudioFormatReader> reader (wav.createReaderFor (file.createInputStream().release(), true)); std::unique_ptr<AudioFormatReader> reader (wav.createReaderFor (file.createInputStream().release(), true));
if (reader != nullptr) if (reader == nullptr)
{ return false;
std::unique_ptr<OutputStream> outStream (tempFile.getFile().createOutputStream());
if (outStream != nullptr) std::unique_ptr<OutputStream> stream = tempFile.getFile().createOutputStream();
{ auto writer = wav.createWriterFor (stream,
std::unique_ptr<AudioFormatWriter> writer (wav.createWriterFor (outStream.get(), reader->sampleRate, AudioFormatWriter::Options{}.withSampleRate (reader->sampleRate)
reader->numChannels, (int) reader->bitsPerSample, .withNumChannels ((int) reader->numChannels)
metadata, 0)); .withBitsPerSample ((int) reader->bitsPerSample)
.withMetadataValues (metadata));
if (writer != nullptr) if (writer == nullptr)
{ return false;
outStream.release();
bool ok = writer->writeFromAudioReader (*reader, 0, -1); bool ok = writer->writeFromAudioReader (*reader, 0, -1);
writer.reset(); writer.reset();
reader.reset(); reader.reset();
return ok && tempFile.overwriteTargetFileWithTemporary(); return ok && tempFile.overwriteTargetFileWithTemporary();
}
}
}
return false;
} }
} }
@ -2123,7 +2133,7 @@ bool WavAudioFormat::replaceMetadataInFile (const File& wavFile, const StringPai
} }
} }
return slowCopyWavFileWithNewMetadata (wavFile, newMetadata); return slowCopyWavFileWithNewMetadata (wavFile, toMap (newMetadata));
} }
@ -2172,15 +2182,14 @@ struct WaveAudioFormatTests final : public UnitTest
{ {
beginTest ("Metadata can be written and read"); beginTest ("Metadata can be written and read");
const auto newMetadata = getMetadataAfterReading (format, writeToBlock (format, metadataArray)); const auto newMetadata = getMetadataAfterReading (format, writeToBlock (format, metadataValues));
expect (newMetadata == metadataArray, "Somehow, the metadata is different!"); expect (newMetadata == metadataArray, "Somehow, the metadata is different!");
} }
{ {
beginTest ("Files containing a riff info source and an empty ISRC associate the source with the riffInfoSource key"); beginTest ("Files containing a riff info source and an empty ISRC associate the source with the riffInfoSource key");
StringPairArray meta; StringMap meta { { WavAudioFormat::riffInfoSource, "customsource" },
meta.addMap ({ { WavAudioFormat::riffInfoSource, "customsource" }, { WavAudioFormat::internationalStandardRecordingCode, "" } };
{ WavAudioFormat::internationalStandardRecordingCode, "" } });
const auto mb = writeToBlock (format, meta); const auto mb = writeToBlock (format, meta);
checkPatternsPresent (mb, { "INFOISRC" }); checkPatternsPresent (mb, { "INFOISRC" });
checkPatternsNotPresent (mb, { "ISRC:", "<ebucore" }); checkPatternsNotPresent (mb, { "ISRC:", "<ebucore" });
@ -2192,8 +2201,7 @@ struct WaveAudioFormatTests final : public UnitTest
{ {
beginTest ("Files containing a riff info source and no ISRC associate the source with both keys " beginTest ("Files containing a riff info source and no ISRC associate the source with both keys "
"for backwards compatibility"); "for backwards compatibility");
StringPairArray meta; StringMap meta { { WavAudioFormat::riffInfoSource, "customsource" } };
meta.addMap ({ { WavAudioFormat::riffInfoSource, "customsource" } });
const auto mb = writeToBlock (format, meta); const auto mb = writeToBlock (format, meta);
checkPatternsPresent (mb, { "INFOISRC", "ISRC:customsource", "<ebucore" }); checkPatternsPresent (mb, { "INFOISRC", "ISRC:customsource", "<ebucore" });
const auto a = getMetadataAfterReading (format, mb); const auto a = getMetadataAfterReading (format, mb);
@ -2204,8 +2212,7 @@ struct WaveAudioFormatTests final : public UnitTest
{ {
beginTest ("Files containing an ISRC associate the value with the internationalStandardRecordingCode key " beginTest ("Files containing an ISRC associate the value with the internationalStandardRecordingCode key "
"and the riffInfoSource key for backwards compatibility"); "and the riffInfoSource key for backwards compatibility");
StringPairArray meta; StringMap meta { { WavAudioFormat::internationalStandardRecordingCode, "AABBBCCDDDDD" } };
meta.addMap ({ { WavAudioFormat::internationalStandardRecordingCode, "AABBBCCDDDDD" } });
const auto mb = writeToBlock (format, meta); const auto mb = writeToBlock (format, meta);
checkPatternsPresent (mb, { "ISRC:AABBBCCDDDDD", "<ebucore" }); checkPatternsPresent (mb, { "ISRC:AABBBCCDDDDD", "<ebucore" });
checkPatternsNotPresent (mb, { "INFOISRC" }); checkPatternsNotPresent (mb, { "INFOISRC" });
@ -2216,9 +2223,8 @@ struct WaveAudioFormatTests final : public UnitTest
{ {
beginTest ("Files containing an ISRC and a riff info source associate the values with the appropriate keys"); beginTest ("Files containing an ISRC and a riff info source associate the values with the appropriate keys");
StringPairArray meta; StringMap meta { { WavAudioFormat::riffInfoSource, "source" },
meta.addMap ({ { WavAudioFormat::riffInfoSource, "source" } }); { WavAudioFormat::internationalStandardRecordingCode, "UUVVVXXYYYYY" } };
meta.addMap ({ { WavAudioFormat::internationalStandardRecordingCode, "UUVVVXXYYYYY" } });
const auto mb = writeToBlock (format, meta); const auto mb = writeToBlock (format, meta);
checkPatternsPresent (mb, { "INFOISRC", "ISRC:UUVVVXXYYYYY", "<ebucore" }); checkPatternsPresent (mb, { "INFOISRC", "ISRC:UUVVVXXYYYYY", "<ebucore" });
const auto a = getMetadataAfterReading (format, mb); const auto a = getMetadataAfterReading (format, mb);
@ -2229,13 +2235,19 @@ struct WaveAudioFormatTests final : public UnitTest
{ {
beginTest ("Files containing ASWG metadata read and write correctly"); beginTest ("Files containing ASWG metadata read and write correctly");
MemoryBlock block; MemoryBlock block;
StringPairArray meta; StringMap meta;
for (const auto& key : WavFileHelpers::IXMLChunk::aswgMetadataKeys) for (const auto& key : WavFileHelpers::IXMLChunk::aswgMetadataKeys)
meta.set (key, "Test123&<>"); meta[key] = "Test123&<>";
{ {
auto writer = rawToUniquePtr (WavAudioFormat().createWriterFor (new MemoryOutputStream (block, false), 48000, 1, 32, meta, 0)); const auto writerOptions = AudioFormatWriterOptions{}.withSampleRate (48000.0)
.withNumChannels (1)
.withBitsPerSample (32)
.withMetadataValues (meta);
std::unique_ptr<OutputStream> stream = std::make_unique<MemoryOutputStream> (block, false);
auto writer = format.createWriterFor (stream, writerOptions);
expect (writer != nullptr); expect (writer != nullptr);
} }
@ -2270,9 +2282,8 @@ struct WaveAudioFormatTests final : public UnitTest
auto reader = rawToUniquePtr (WavAudioFormat().createReaderFor (new MemoryInputStream (block, false), true)); auto reader = rawToUniquePtr (WavAudioFormat().createReaderFor (new MemoryInputStream (block, false), true));
expect (reader != nullptr); expect (reader != nullptr);
for (const auto& key : meta.getAllKeys()) for (const auto& [key, oldValue] : meta)
{ {
const auto oldValue = meta.getValue (key, "!");
const auto newValue = reader->metadataValues.getValue (key, ""); const auto newValue = reader->metadataValues.getValue (key, "");
expectEquals (oldValue, newValue); expectEquals (oldValue, newValue);
} }
@ -2280,22 +2291,128 @@ struct WaveAudioFormatTests final : public UnitTest
expect (reader->metadataValues.getValue (WavAudioFormat::aswgVersion, "") == "3.01"); expect (reader->metadataValues.getValue (WavAudioFormat::aswgVersion, "") == "3.01");
} }
} }
{
beginTest ("Writing 32-bit integer samples should work");
const auto minimum = std::numeric_limits<int>::min();
const auto maximum = std::numeric_limits<int>::max();
std::vector<int> dataIn { minimum,
minimum + 1,
minimum + 999,
0,
1,
maximum - 1001,
maximum - 1,
maximum };
const int* ptr = dataIn.data();
WavFormatWriterTestData integralTestData { &ptr,
dataIn.size(),
AudioFormatWriterOptions::SampleFormat::integral };
auto* reader = integralTestData.getReader();
if (reader == nullptr)
{
expect (false, "WavFormatReader should be non-null");
return;
}
std::vector<int> dataOut ((size_t) reader->lengthInSamples);
int* const outPtr = dataOut.data();
reader->read (&outPtr, 1, 0, (int) dataOut.size(), false);
expect (reader->usesFloatingPointData == false);
expect (dataIn == dataOut);
}
{
beginTest ("Writing 32-bit float samples should work");
std::vector<float> dataIn { -1.0f,
-0.8f,
0.0f,
0.8f,
1.0f };
const int* ptr = (int*) dataIn.data();
WavFormatWriterTestData floatingPointTestData { &ptr,
dataIn.size(),
AudioFormatWriterOptions::SampleFormat::floatingPoint };
auto* reader = floatingPointTestData.getReader();
if (reader == nullptr)
{
expect (false, "WavFormatReader should be non-null");
return;
}
std::vector<float> dataOut ((size_t) reader->lengthInSamples);
float* const outPtr = dataOut.data();
reader->read (&outPtr, 1, 0, (int) dataOut.size());
expect (reader->usesFloatingPointData == true);
expect (dataIn.size() == dataOut.size());
for (auto [index, value] : enumerate (dataOut, size_t{}))
expect (approximatelyEqual (value, dataIn[index]));
}
} }
private: private:
MemoryBlock writeToBlock (WavAudioFormat& format, StringPairArray meta) struct WavFormatWriterTestData
{
WavFormatWriterTestData (const int** ptr,
size_t numSamples,
AudioFormatWriterOptions::SampleFormat sampleFormat)
{
const auto writerOptions = AudioFormatWriterOptions{}.withSampleRate (48000.0)
.withNumChannels (1)
.withBitsPerSample (32)
.withSampleFormat (sampleFormat);
WavAudioFormat format;
{
std::unique_ptr<OutputStream> stream = std::make_unique<MemoryOutputStream> (block, false);
auto writer = format.createWriterFor (stream, writerOptions);
writer->write (ptr, (int) numSamples);
}
reader = rawToUniquePtr (format.createReaderFor (new MemoryInputStream (block, false), true));
}
AudioFormatReader* getReader()
{
return reader.get();
}
private:
MemoryBlock block;
std::unique_ptr<AudioFormatReader> reader;
};
MemoryBlock writeToBlock (WavAudioFormat& format, const StringMap& meta)
{ {
MemoryBlock mb; MemoryBlock mb;
{ {
const auto writerOptions = AudioFormatWriterOptions{}.withSampleRate (44100.0)
.withNumChannels ((int) numTestAudioBufferChannels)
.withBitsPerSample (16)
.withMetadataValues (meta);
// The destructor of the writer will modify the block, so make sure that we've // The destructor of the writer will modify the block, so make sure that we've
// destroyed the writer before returning the block! // destroyed the writer before returning the block!
auto writer = rawToUniquePtr (format.createWriterFor (new MemoryOutputStream (mb, false), std::unique_ptr<OutputStream> stream = std::make_unique<MemoryOutputStream> (mb, false);
44100.0, auto writer = format.createWriterFor (stream, writerOptions);
numTestAudioBufferChannels,
16,
meta,
0));
expect (writer != nullptr); expect (writer != nullptr);
AudioBuffer<float> buffer (numTestAudioBufferChannels, numTestAudioBufferSamples); AudioBuffer<float> buffer (numTestAudioBufferChannels, numTestAudioBufferSamples);
expect (writer->writeFromAudioSampleBuffer (buffer, 0, numTestAudioBufferSamples)); expect (writer->writeFromAudioSampleBuffer (buffer, 0, numTestAudioBufferSamples));

View file

@ -297,6 +297,9 @@ public:
MemoryMappedAudioFormatReader* createMemoryMappedReader (const File&) override; MemoryMappedAudioFormatReader* createMemoryMappedReader (const File&) override;
MemoryMappedAudioFormatReader* createMemoryMappedReader (FileInputStream*) override; MemoryMappedAudioFormatReader* createMemoryMappedReader (FileInputStream*) override;
std::unique_ptr<AudioFormatWriter> createWriterFor (std::unique_ptr<OutputStream>& streamToWriteTo,
const AudioFormatWriterOptions& options) override;
AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo,
double sampleRateToUse, double sampleRateToUse,
unsigned int numberOfChannels, unsigned int numberOfChannels,
@ -310,6 +313,7 @@ public:
int bitsPerSample, int bitsPerSample,
const StringPairArray& metadataValues, const StringPairArray& metadataValues,
int qualityOptionIndex) override; int qualityOptionIndex) override;
using AudioFormat::createWriterFor; using AudioFormat::createWriterFor;
//============================================================================== //==============================================================================

View file

@ -365,6 +365,13 @@ AudioFormatWriter* WindowsMediaAudioFormat::createWriterFor (OutputStream* /*str
return nullptr; return nullptr;
} }
std::unique_ptr<AudioFormatWriter> WindowsMediaAudioFormat::createWriterFor (std::unique_ptr<OutputStream>&,
const AudioFormatWriterOptions&)
{
jassertfalse; // not yet implemented!
return nullptr;
}
//============================================================================== //==============================================================================
//============================================================================== //==============================================================================
#if JUCE_UNIT_TESTS #if JUCE_UNIT_TESTS

View file

@ -60,9 +60,13 @@ public:
//============================================================================== //==============================================================================
AudioFormatReader* createReaderFor (InputStream*, bool deleteStreamIfOpeningFails) override; AudioFormatReader* createReaderFor (InputStream*, bool deleteStreamIfOpeningFails) override;
std::unique_ptr<AudioFormatWriter> createWriterFor (std::unique_ptr<OutputStream>& streamToWriteTo,
const AudioFormatWriterOptions& options) override;
AudioFormatWriter* createWriterFor (OutputStream*, double sampleRateToUse, AudioFormatWriter* createWriterFor (OutputStream*, double sampleRateToUse,
unsigned int numberOfChannels, int bitsPerSample, unsigned int numberOfChannels, int bitsPerSample,
const StringPairArray& metadataValues, int qualityOptionIndex) override; const StringPairArray& metadataValues, int qualityOptionIndex) override;
using AudioFormat::createWriterFor; using AudioFormat::createWriterFor;
}; };

View file

@ -82,6 +82,53 @@ bool AudioFormat::isChannelLayoutSupported (const AudioChannelSet& channelSet)
return false; return false;
} }
using StringMap = std::unordered_map<String, String>;
static StringMap toMap (const StringPairArray& array)
{
StringMap result;
for (auto i = 0; i < array.size(); ++i)
result[array.getAllKeys()[i]] = array.getAllValues()[i];
return result;
}
AudioFormatWriter* AudioFormat::createWriterForRawPtr (OutputStream* streamToWriteTo,
const AudioFormatWriterOptions& opt)
{
auto owned = rawToUniquePtr (streamToWriteTo);
if (auto writer = createWriterFor (owned, opt))
{
// Creating the writer succeeded, so it's the writer's responsibility to eventually free
// the stream
jassert (owned == nullptr);
return writer.release();
}
// Creating the writer failed, so the stream should remain alive for re-use
jassert (owned != nullptr);
owned.release();
return {};
}
AudioFormatWriter* AudioFormat::createWriterFor (OutputStream* streamToWriteTo,
double sampleRateToUse,
unsigned int numberOfChannels,
int bitsPerSample,
const StringPairArray& metadataValues,
int qualityOptionIndex)
{
auto opt = AudioFormatWriter::Options{}.withSampleRate (sampleRateToUse)
.withNumChannels ((int) numberOfChannels)
.withBitsPerSample (bitsPerSample)
.withMetadataValues (toMap (metadataValues))
.withQualityOptionIndex (qualityOptionIndex);
return createWriterForRawPtr (streamToWriteTo, opt);
}
AudioFormatWriter* AudioFormat::createWriterFor (OutputStream* streamToWriteTo, AudioFormatWriter* AudioFormat::createWriterFor (OutputStream* streamToWriteTo,
double sampleRateToUse, double sampleRateToUse,
const AudioChannelSet& channelLayout, const AudioChannelSet& channelLayout,
@ -89,12 +136,15 @@ AudioFormatWriter* AudioFormat::createWriterFor (OutputStream* streamToWriteTo,
const StringPairArray& metadataValues, const StringPairArray& metadataValues,
int qualityOptionIndex) int qualityOptionIndex)
{ {
if (isChannelLayoutSupported (channelLayout)) if (! isChannelLayoutSupported (channelLayout))
return createWriterFor (streamToWriteTo, sampleRateToUse, return nullptr;
static_cast<unsigned int> (channelLayout.size()),
bitsPerSample, metadataValues, qualityOptionIndex);
return nullptr; auto opt = AudioFormatWriter::Options{}.withSampleRate (sampleRateToUse)
.withChannelLayout (channelLayout)
.withBitsPerSample (bitsPerSample)
.withMetadataValues (toMap (metadataValues))
.withQualityOptionIndex (qualityOptionIndex);
return createWriterForRawPtr (streamToWriteTo, opt);
} }
} // namespace juce } // namespace juce

View file

@ -125,6 +125,26 @@ public:
virtual MemoryMappedAudioFormatReader* createMemoryMappedReader (const File& file); virtual MemoryMappedAudioFormatReader* createMemoryMappedReader (const File& file);
virtual MemoryMappedAudioFormatReader* createMemoryMappedReader (FileInputStream* fin); virtual MemoryMappedAudioFormatReader* createMemoryMappedReader (FileInputStream* fin);
/** Tries to create an object that can write to a stream with this audio format.
If the writer can't be created for some reason (e.g. the parameters passed in
here aren't suitable), this will return nullptr.
@param streamToWriteTo a reference to a unique_ptr that owns the output stream. If creating
the writer succeeds, then ownership of the stream will be
transferred to the writer, and this argument will be set to nullptr.
If creating the writer fails, then streamToWriteTo will remain
unchanged, allowing it to be reused to create a writer of a
different format.
@param options options that specify details of the output file. If the audio format
does not support these settings, then this function may return
nullptr.
@see AudioFormatWriterOptions
*/
virtual std::unique_ptr<AudioFormatWriter> createWriterFor (std::unique_ptr<OutputStream>& streamToWriteTo,
const AudioFormatWriterOptions& options) = 0;
/** Tries to create an object that can write to a stream with this audio format. /** Tries to create an object that can write to a stream with this audio format.
The writer object that is returned can be used to write to the stream, and The writer object that is returned can be used to write to the stream, and
@ -217,6 +237,8 @@ protected:
AudioFormat (StringRef formatName, StringRef fileExtensions); AudioFormat (StringRef formatName, StringRef fileExtensions);
private: private:
AudioFormatWriter* createWriterForRawPtr (OutputStream*, const AudioFormatWriterOptions&);
//============================================================================== //==============================================================================
String formatName; String formatName;
StringArray fileExtensions; StringArray fileExtensions;

View file

@ -93,6 +93,8 @@ protected:
unsigned int bitsPerSample); unsigned int bitsPerSample);
public: public:
using Options = AudioFormatWriterOptions;
/** Destructor. */ /** Destructor. */
virtual ~AudioFormatWriter(); virtual ~AudioFormatWriter();

View file

@ -0,0 +1,182 @@
/*
==============================================================================
This file is part of the JUCE framework.
Copyright (c) Raw Material Software Limited
JUCE is an open source framework subject to commercial or open source
licensing.
By downloading, installing, or using the JUCE framework, or combining the
JUCE framework with any other source code, object code, content or any other
copyrightable work, you agree to the terms of the JUCE End User Licence
Agreement, and all incorporated terms including the JUCE Privacy Policy and
the JUCE Website Terms of Service, as applicable, which will bind you. If you
do not agree to the terms of these agreements, we will not license the JUCE
framework to you, and you must discontinue the installation or download
process and cease use of the JUCE framework.
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
Or:
You may also use this code under the terms of the AGPLv3:
https://www.gnu.org/licenses/agpl-3.0.en.html
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
==============================================================================
*/
namespace juce
{
/**
Options that affect the output data format produced by an AudioFormatWriter. Format
specific writers may ignore some of these options.
@see AudioFormat::createWriterFor(), AudioFormatWriter
@tags{Audio}
*/
class JUCE_API AudioFormatWriterOptions final
{
public:
/** Used to provide a hint to the AudioFormatWriter for the output sample format.
Use automatic for the old behaviour. The values integral and floatingPoint can be used with
the WavAudioFormat when using a bit depth of 32. Other formats are not affected by this
setting.
*/
enum class SampleFormat
{
automatic, ///< Lets the writer decide the format based on the other parameter values.
integral, ///< Integral format, e.g. PCM in case of the WavAudioFormat
floatingPoint ///< IEEE floating point format
};
/** Returns a copy of these options with the specified sample format.
@see SampleFormat
*/
[[nodiscard]] AudioFormatWriterOptions withSampleFormat (SampleFormat x) const
{
return withMember (*this, &AudioFormatWriterOptions::sampleFormat, x);
}
/** Returns a copy of these options with the specified sample rate.
This specifies the sample rate for the file, which must be one of the ones
returned by AudioFormat::getPossibleSampleRates().
*/
[[nodiscard]] AudioFormatWriterOptions withSampleRate (double x) const
{
return withMember (*this, &AudioFormatWriterOptions::sampleRate, x);
}
/** Returns a copy of these options with the specified channel set.
Setting this option will supersede the value passed into withNumChannels().
You should prefer to use withChannelLayout(), if specifying an AudioChannelSet is
applicable, and withNumChannels() otherwise.
*/
[[nodiscard]] AudioFormatWriterOptions withChannelLayout (const AudioChannelSet& x) const
{
return withMember (*this, &AudioFormatWriterOptions::channelLayout, x);
}
/** Returns a copy of these options with the specified number of channels.
This is meant as a fallback for specifying the channel layout. Setting this option will
have no effect if the channel layout is specified.
@see withChannelLayout()
*/
[[nodiscard]] AudioFormatWriterOptions withNumChannels (int x) const
{
return withMember (*this, &AudioFormatWriterOptions::numChannels, x);
}
/** Returns a copy of these options with the specified bit size per sample.
This must be one of the values returned by AudioFormat::getPossibleBitDepths().
*/
[[nodiscard]] AudioFormatWriterOptions withBitsPerSample (int x) const
{
return withMember (*this, &AudioFormatWriterOptions::bitsPerSample, x);
}
/** Returns a copy of these options with the specified metadata container.
As an alternative to this function, you can specify the key-value pairs one-by-one using
the withMetadata function.
Subsequent calls of this function overwrites all previously added metadata.
This parameter is a set of metadata values that the writer should try to write to the stream.
Exactly what these are depends on the format, and the subclass doesn't actually have to do
anything with them if it doesn't want to. Have a look at the specific format implementation
classes to see possible values that can be used.
*/
[[nodiscard]] AudioFormatWriterOptions withMetadataValues (const std::unordered_map<String, String>& x) const
{
return withMember (*this, &AudioFormatWriterOptions::metadataValues, x);
}
/** Returns a copy of these options with the specified metadata added.
Subsequent calls of this function adds new metadata values, while also preserving the
previously added ones.
Here you can specify metadata values that the writer should try to write to the stream.
Exactly what these are depends on the format, and the subclass doesn't actually have to do
anything with them if it doesn't want to. Have a look at the specific format implementation
classes to see possible values that can be used.
*/
[[nodiscard]] AudioFormatWriterOptions withMetadata (const String& key, const String& value) const
{
auto copy = *this;
copy.metadataValues[key] = value;
return copy;
}
/** Returns a copy of these options with the specified quality option index.
The index of one of the items returned by the AudioFormat::getQualityOptions() method.
*/
[[nodiscard]] AudioFormatWriterOptions withQualityOptionIndex (int x) const
{
return withMember (*this, &AudioFormatWriterOptions::qualityOptionIndex, x);
}
/** @see withSampleRate() */
[[nodiscard]] auto getSampleRate() const { return sampleRate; }
/** @see withChannelLayout() */
[[nodiscard]] auto getChannelLayout() const { return channelLayout; }
/** @see withNumChannels() */
[[nodiscard]] auto getNumChannels() const { return channelLayout.has_value() ? channelLayout->size() : numChannels; }
/** @see withBitsPerSample() */
[[nodiscard]] auto getBitsPerSample() const { return bitsPerSample; }
/** @see withMetadataValues() */
[[nodiscard]] auto getMetadataValues() const { return metadataValues; }
/** @see withQualityOptionIndex() */
[[nodiscard]] auto getQualityOptionIndex() const { return qualityOptionIndex; }
/** @see withSampleFormat() */
[[nodiscard]] auto getSampleFormat() const { return sampleFormat; }
private:
double sampleRate = 48000.0;
int numChannels = 1;
std::optional<AudioChannelSet> channelLayout = std::nullopt;
int bitsPerSample = 16;
std::unordered_map<String, String> metadataValues;
int qualityOptionIndex = 0;
SampleFormat sampleFormat = SampleFormat::automatic;
};
} // namespace juce

View file

@ -121,6 +121,7 @@
//============================================================================== //==============================================================================
#include "format/juce_AudioFormatReader.h" #include "format/juce_AudioFormatReader.h"
#include "format/juce_AudioFormatWriterOptions.h"
#include "format/juce_AudioFormatWriter.h" #include "format/juce_AudioFormatWriter.h"
#include "format/juce_MemoryMappedAudioFormatReader.h" #include "format/juce_MemoryMappedAudioFormatReader.h"
#include "format/juce_AudioFormat.h" #include "format/juce_AudioFormat.h"