├── .gitattributes ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── appveyor.yml ├── caesar.sln └── src ├── Cbnk.cpp ├── Cbnk.hpp ├── Cgrp.cpp ├── Cgrp.hpp ├── Common.cpp ├── Common.hpp ├── Csar.cpp ├── Csar.hpp ├── Cseq.cpp ├── Cseq.hpp ├── Cwar.cpp ├── Cwar.hpp ├── Cwav.cpp ├── Cwav.hpp ├── caesar.cpp ├── caesar.vcxproj ├── caesar.vcxproj.filters ├── libsmfc ├── libsmfc.c ├── libsmfc.h ├── libsmfcx.c └── libsmfcx.h └── sf2cute-0.2 ├── .editorconfig ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── Doxyfile ├── LICENSE ├── README.md ├── appveyor.yml ├── cmake └── sf2cute-config.cmake.in ├── examples ├── debug.hpp └── write_sf2.cpp ├── include ├── sf2cute.hpp └── sf2cute │ ├── file.hpp │ ├── generator_item.hpp │ ├── instrument.hpp │ ├── instrument_zone.hpp │ ├── modulator.hpp │ ├── modulator_item.hpp │ ├── modulator_key.hpp │ ├── preset.hpp │ ├── preset_zone.hpp │ ├── sample.hpp │ ├── types.hpp │ ├── version.hpp │ └── zone.hpp ├── sf2cute.autopkg └── src └── sf2cute ├── byteio.hpp ├── file.cpp ├── file_writer.cpp ├── file_writer.hpp ├── generator_item.cpp ├── instrument.cpp ├── instrument_zone.cpp ├── modulator.cpp ├── modulator_item.cpp ├── modulator_key.cpp ├── preset.cpp ├── preset_zone.cpp ├── riff.cpp ├── riff.hpp ├── riff_ibag_chunk.cpp ├── riff_ibag_chunk.hpp ├── riff_igen_chunk.cpp ├── riff_igen_chunk.hpp ├── riff_imod_chunk.cpp ├── riff_imod_chunk.hpp ├── riff_inst_chunk.cpp ├── riff_inst_chunk.hpp ├── riff_pbag_chunk.cpp ├── riff_pbag_chunk.hpp ├── riff_pgen_chunk.cpp ├── riff_pgen_chunk.hpp ├── riff_phdr_chunk.cpp ├── riff_phdr_chunk.hpp ├── riff_pmod_chunk.cpp ├── riff_pmod_chunk.hpp ├── riff_shdr_chunk.cpp ├── riff_shdr_chunk.hpp ├── riff_smpl_chunk.cpp ├── riff_smpl_chunk.hpp ├── sample.cpp └── zone.cpp /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | 65 | * text eol=lf 66 | 67 | caesar/libsmfc/* linguist-vendored 68 | caesar/sf2cute-0.1/* linguist-vendored 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc 262 | 263 | # autotools/cmake garbage. 264 | build 265 | cmakebuild 266 | .deps 267 | .dirstamp 268 | autom4te.cache 269 | stamp-h1 270 | aclocal.m4 271 | compile 272 | config.guess 273 | config.log 274 | config.status 275 | config.sub 276 | configure 277 | depcomp 278 | install-sh 279 | missing 280 | Makefile.in 281 | Makefile 282 | config.h 283 | config.h.in 284 | CMakeFiles 285 | CMakeCache.txt 286 | cmake_install.cmake 287 | 288 | # generated/user files 289 | *.a 290 | *.bin 291 | *.d 292 | *.elf 293 | *.map 294 | *.o 295 | *.obj 296 | *.tsk 297 | *.bcsar 298 | *.exe 299 | caesar 300 | 301 | # macOS Garbage 302 | .DS_Store 303 | ._* 304 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ########## Project setup ########## 2 | PROJECT(caesar) 3 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11) 4 | 5 | set(CMAKE_CXX_STANDARD 17) 6 | 7 | # Find Macros 8 | SET(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) 9 | 10 | INCLUDE(CMakeDependentOption) 11 | INCLUDE(CheckCCompilerFlag) 12 | INCLUDE(CheckCSourceCompiles) 13 | INCLUDE(CheckIncludeFile) 14 | INCLUDE(TestBigEndian) 15 | ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/src/sf2cute-0.2/) 16 | 17 | INCLUDE_DIRECTORIES(BEFORE "${CMAKE_SOURCE_DIR}/src/sf2cute-0.2/include") 18 | 19 | FILE(GLOB SOURCES "src/*.cpp" "src/libsmfc/*.c") 20 | 21 | ADD_EXECUTABLE(caesar ${SOURCES}) 22 | 23 | TARGET_LINK_LIBRARIES(caesar sf2cute) 24 | 25 | if(MSVC) 26 | TARGET_COMPILE_OPTIONS(caesar PRIVATE /W4 /WX- -D_CRT_SECURE_NO_WARNINGS) 27 | else(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) 28 | TARGET_COMPILE_OPTIONS(caesar PRIVATE -Wall -Wconversion -Wsign-conversion -Wno-long-long -pedantic) 29 | endif() 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # caesar 2 | A tool that extracts the contents of Citrus Sound Archives. 3 | 4 | # Usage 5 | ``` 6 | OVERVIEW: Caesar 7 | 8 | USAGE: caesar [options] 9 | 10 | OPTIONS: 11 | -p Do not ignore pan values of stereo samples 12 | -w Show warnings 13 | ``` 14 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: '{build}' 2 | branches: 3 | only: 4 | - master 5 | image: 6 | - Visual Studio 2019 7 | configuration: 8 | - Release 9 | - Debug 10 | environment: 11 | matrix: 12 | - arch: Win64 13 | # - arch: #does not work, Release|x64 not a valid target 14 | matrix: 15 | fast_finish: true 16 | 17 | # skip unsupported combinations 18 | init: 19 | - set arch= 20 | - if "%arch%"=="Win64" ( set arch= Win64) 21 | - echo %arch% 22 | - echo %APPVEYOR_BUILD_WORKER_IMAGE% 23 | - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2019" ( set generator="Visual Studio 16 2019" ) 24 | - echo %generator% 25 | 26 | before_build: 27 | - cmd: |- 28 | cd C:\projects\caesar 29 | cmake --version 30 | cmake .. -G %generator% c:\projects\caesar 31 | build: 32 | project: c:\projects\caesar\caesar.sln 33 | verbosity: minimal 34 | parallel: true 35 | only_commits: 36 | files: 37 | - CMakeLists.txt 38 | - appveyor.yml 39 | - source/ 40 | - cmake/ 41 | artifacts: 42 | - path: Release\caesar.exe 43 | - path: Debug\caesar.exe 44 | -------------------------------------------------------------------------------- /caesar.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2035 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "caesar", "src\caesar.vcxproj", "{36E2B7A0-ED02-4D49-8FC2-3A8272C9F607}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {36E2B7A0-ED02-4D49-8FC2-3A8272C9F607}.Debug|x64.ActiveCfg = Debug|x64 17 | {36E2B7A0-ED02-4D49-8FC2-3A8272C9F607}.Debug|x64.Build.0 = Debug|x64 18 | {36E2B7A0-ED02-4D49-8FC2-3A8272C9F607}.Debug|x86.ActiveCfg = Debug|Win32 19 | {36E2B7A0-ED02-4D49-8FC2-3A8272C9F607}.Debug|x86.Build.0 = Debug|Win32 20 | {36E2B7A0-ED02-4D49-8FC2-3A8272C9F607}.Release|x64.ActiveCfg = Release|x64 21 | {36E2B7A0-ED02-4D49-8FC2-3A8272C9F607}.Release|x64.Build.0 = Release|x64 22 | {36E2B7A0-ED02-4D49-8FC2-3A8272C9F607}.Release|x86.ActiveCfg = Release|Win32 23 | {36E2B7A0-ED02-4D49-8FC2-3A8272C9F607}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {416DD618-6CFF-4C91-AAA5-79E93A15A8FA} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /src/Cbnk.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Cwar.hpp" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | struct CbnkCwav 12 | { 13 | uint32_t Cwar; 14 | uint32_t Id; 15 | uint32_t Key; 16 | 17 | uint16_t ChanCount; 18 | uint32_t SampleRate; 19 | 20 | std::vector LeftSamples; 21 | std::vector RightSamples; 22 | 23 | bool Loop = false; 24 | uint32_t LoopStart; 25 | uint32_t LoopEnd; 26 | }; 27 | 28 | struct WaveSmpl 29 | { 30 | uint32_t CuePointId; 31 | uint32_t Type; 32 | uint32_t Start; 33 | uint32_t End; 34 | uint32_t Fraction; 35 | uint32_t PlayCount; 36 | }; 37 | 38 | struct CbnkNote 39 | { 40 | bool Exists = true; 41 | uint8_t* Offset; 42 | 43 | CbnkCwav* Cwav; 44 | uint8_t StartNote; 45 | uint8_t EndNote; 46 | uint32_t RootKey; 47 | uint32_t Volume; 48 | uint32_t Pan; 49 | uint8_t Interpolation; 50 | uint8_t Attack; 51 | uint8_t Decay; 52 | uint8_t Sustain; 53 | uint8_t Hold; 54 | uint8_t Release; 55 | }; 56 | 57 | struct CbnkInst 58 | { 59 | bool Exists = true; 60 | uint8_t* Offset; 61 | 62 | uint32_t NoteCount; 63 | std::vector Notes; 64 | 65 | bool IsDrumKit = false; 66 | }; 67 | 68 | struct Cbnk 69 | { 70 | std::string FileName; 71 | std::streamoff Length; 72 | uint8_t* Data = nullptr; 73 | 74 | std::map* Cwars; 75 | bool P; 76 | 77 | Cbnk(const char* fileName, std::map* cwars, bool p); 78 | ~Cbnk(); 79 | bool Convert(std::string cwarPath); 80 | }; 81 | -------------------------------------------------------------------------------- /src/Cgrp.cpp: -------------------------------------------------------------------------------- 1 | #include "Cgrp.hpp" 2 | #include "Cbnk.hpp" 3 | #include "Common.hpp" 4 | #include "Cseq.hpp" 5 | #include "Cwar.hpp" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | using namespace filesystem; 16 | 17 | Cgrp::Cgrp(const char* fileName, map* cwars, const map& cseqsFromCsar, bool p) : FileName(fileName), Cwars(cwars), CseqsFromCsar(cseqsFromCsar), P(p) 18 | { 19 | ifstream ifs(FileName, ios::binary | ios::ate); 20 | 21 | Length = ifs.tellg(); 22 | Data = new uint8_t[Length]; 23 | 24 | Common::Push(FileName, Data); 25 | 26 | ifs.seekg(0, ios::beg); 27 | ifs.read(reinterpret_cast(Data), Length); 28 | ifs.close(); 29 | } 30 | 31 | Cgrp::~Cgrp() 32 | { 33 | for (auto cseq : Cseqs) 34 | { 35 | delete cseq; 36 | } 37 | 38 | for (auto cbnk : Cbnks) 39 | { 40 | delete cbnk; 41 | } 42 | 43 | Common::Pop(); 44 | 45 | delete[] Data; 46 | } 47 | 48 | bool Cgrp::Extract() 49 | { 50 | uint8_t* pos = Data; 51 | 52 | if (!Common::Assert(pos, 0x43475250, ReadFixLen(pos, 4, false))) { return false; } 53 | if (!Common::Assert(pos, 0xFEFF, ReadFixLen(pos, 2))) { return false; } 54 | if (!Common::Assert(pos, 0x40, ReadFixLen(pos, 2))) { return false; } 55 | 56 | uint32_t cgrpVersion = ReadFixLen(pos, 4); 57 | 58 | if (!Common::Assert(pos, Length, ReadFixLen(pos, 4))) { return false; } 59 | 60 | uint32_t chunkCount = ReadFixLen(pos, 4); 61 | 62 | uint32_t infoOffset = 0; 63 | uint32_t infoLength = 0; 64 | 65 | uint32_t fileOffset = 0; 66 | uint32_t fileLength = 0; 67 | 68 | uint32_t infxOffset = 0; 69 | uint32_t infxLength = 0; 70 | 71 | for (uint32_t i = 0; i < chunkCount; ++i) 72 | { 73 | uint32_t chunkId = ReadFixLen(pos, 4); 74 | 75 | switch (chunkId) 76 | { 77 | case 0x7800: 78 | infoOffset = ReadFixLen(pos, 4); 79 | infoLength = ReadFixLen(pos, 4); 80 | 81 | break; 82 | 83 | case 0x7801: 84 | fileOffset = ReadFixLen(pos, 4); 85 | fileLength = ReadFixLen(pos, 4); 86 | 87 | break; 88 | 89 | case 0x7802: 90 | infxOffset = ReadFixLen(pos, 4); 91 | infxLength = ReadFixLen(pos, 4); 92 | 93 | break; 94 | 95 | default: 96 | { 97 | Common::Error(pos - 4, "A valid chunk type", chunkId); 98 | 99 | return false; 100 | } 101 | } 102 | } 103 | 104 | pos = Data + infoOffset; 105 | 106 | if (!Common::Assert(pos, 0x494E464F, ReadFixLen(pos, 4, false))) { return false; } 107 | if (!Common::Assert(pos, infoLength, ReadFixLen(pos, 4))) { return false; } 108 | 109 | uint32_t fileCount = ReadFixLen(pos, 4); 110 | 111 | vector fileOffsets; 112 | 113 | for (uint32_t i = 0; i < fileCount; ++i) 114 | { 115 | if (!Common::Assert(pos, 0x7900, ReadFixLen(pos, 4))) { return false; } 116 | 117 | fileOffsets.push_back(Data + infoOffset + 8 + ReadFixLen(pos, 4)); 118 | } 119 | 120 | vector files; 121 | 122 | for (uint32_t i = 0; i < fileCount; ++i) 123 | { 124 | CgrpFile file{}; 125 | file.Id = ReadFixLen(pos, 4); 126 | file.Offset = ReadFixLen(pos, 4) == 0x1F00 ? Data + fileOffset + 8 + ReadFixLen(pos, 4) : nullptr; 127 | file.Length = ReadFixLen(pos, 4); 128 | 129 | files.push_back(file); 130 | } 131 | 132 | for (uint32_t i = 0; i < fileCount; ++i) 133 | { 134 | if (files[i].Offset == nullptr) 135 | { 136 | continue; 137 | } 138 | 139 | if (CseqsFromCsar[files[i].Id] == true) 140 | { 141 | continue; 142 | } 143 | 144 | pos = files[i].Offset; 145 | 146 | uint32_t fileId = ReadFixLen(pos, 4, false); 147 | 148 | switch (fileId) 149 | { 150 | case 0x43574152: 151 | { 152 | pos += 8; 153 | 154 | uint32_t cwarLength = ReadFixLen(pos, 4); 155 | 156 | pos -= 16; 157 | 158 | create_directory(to_string(files[i].Id)); 159 | current_path(to_string(files[i].Id)); 160 | 161 | ofstream ofs(string(to_string(files[i].Id) + ".bcwar"), ofstream::binary); 162 | ofs.write(reinterpret_cast(pos), cwarLength); 163 | ofs.close(); 164 | 165 | (*Cwars)[files[i].Id] = new Cwar(string(to_string(files[i].Id) + ".bcwar").c_str()); 166 | 167 | current_path(".."); 168 | 169 | current_path(((*Cwars)[files[i].Id]->FileName.substr(0, (*Cwars)[files[i].Id]->FileName.length() - 6))); 170 | 171 | if (!(*Cwars)[files[i].Id]->Extract()) 172 | { 173 | return false; 174 | } 175 | 176 | current_path(".."); 177 | 178 | break; 179 | } 180 | 181 | case 0x43424E4B: 182 | { 183 | pos += 8; 184 | 185 | uint32_t cbnkLength = ReadFixLen(pos, 4); 186 | 187 | pos -= 16; 188 | 189 | create_directory(to_string(files[i].Id)); 190 | current_path(to_string(files[i].Id)); 191 | 192 | ofstream ofs(string(to_string(files[i].Id) + ".bcbnk"), ofstream::binary); 193 | ofs.write(reinterpret_cast(pos), cbnkLength); 194 | ofs.close(); 195 | 196 | Cbnks.push_back(new Cbnk(string(to_string(files[i].Id) + ".bcbnk").c_str(), Cwars, P)); 197 | 198 | current_path(".."); 199 | 200 | break; 201 | } 202 | 203 | case 0x43534551: 204 | { 205 | pos += 8; 206 | 207 | uint32_t cseqLength = ReadFixLen(pos, 4); 208 | 209 | pos -= 16; 210 | 211 | ofstream ofs(string(to_string(files[i].Id) + ".bcseq"), ofstream::binary); 212 | ofs.write(reinterpret_cast(pos), cseqLength); 213 | ofs.close(); 214 | 215 | Cseqs.push_back(new Cseq(string(to_string(files[i].Id) + ".bcseq").c_str())); 216 | 217 | break; 218 | } 219 | 220 | case 0x43575344: 221 | { 222 | Common::Warning(pos - 4, "Skipping CWSD"); 223 | 224 | break; 225 | } 226 | 227 | default: 228 | { 229 | Common::Error(pos - 4, "A valid file type", fileId); 230 | 231 | return false; 232 | } 233 | } 234 | } 235 | 236 | for (uint32_t i = 0; i < Cbnks.size(); ++i) 237 | { 238 | current_path(Cbnks[i]->FileName.substr(0, Cbnks[i]->FileName.length() - 6)); 239 | 240 | if (!Cbnks[i]->Convert("..")) 241 | { 242 | return false; 243 | } 244 | 245 | current_path(".."); 246 | } 247 | 248 | for (uint32_t i = 0; i < Cseqs.size(); ++i) 249 | { 250 | if (!Cseqs[i]->Convert()) 251 | { 252 | return false; 253 | } 254 | } 255 | 256 | if (infxOffset) 257 | { 258 | pos = Data + infxOffset; 259 | 260 | Common::Warning(pos, "Skipping INFX chunk"); 261 | } 262 | 263 | return true; 264 | } 265 | -------------------------------------------------------------------------------- /src/Cgrp.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Cbnk.hpp" 4 | #include "Cseq.hpp" 5 | #include "Cwar.hpp" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | struct CgrpFile 14 | { 15 | uint32_t Id; 16 | uint8_t* Offset; 17 | uint32_t Length; 18 | }; 19 | 20 | struct Cgrp 21 | { 22 | std::string FileName; 23 | std::streamoff Length; 24 | uint8_t* Data = nullptr; 25 | 26 | std::map* Cwars; 27 | std::vector Cbnks; 28 | std::vector Cseqs; 29 | std::map CseqsFromCsar; 30 | bool P; 31 | 32 | Cgrp(const char* fileName, std::map* cwars, const std::map& cseqsFromCsar, bool p); 33 | ~Cgrp(); 34 | bool Extract(); 35 | }; 36 | -------------------------------------------------------------------------------- /src/Common.cpp: -------------------------------------------------------------------------------- 1 | #include "Common.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | bool Common::ShowWarnings = false; 13 | stack Common::FileNames; 14 | stack Common::Offsets; 15 | vector Common::Log; 16 | 17 | int32_t ReadFixLen(uint8_t*& pos, size_t bytes, bool littleEndian, bool isSigned) 18 | { 19 | int32_t result = 0; 20 | 21 | for (size_t i = 0; i < bytes; ++i) 22 | { 23 | result |= *pos++ << ((littleEndian ? i : bytes - i - 1) * 8); 24 | } 25 | 26 | if (isSigned && (result >= (1 << ((bytes * 8) - 1)))) 27 | { 28 | result -= 1 << (bytes * 8); 29 | } 30 | 31 | return result; 32 | } 33 | 34 | int32_t ReadVarLen(uint8_t*& pos) 35 | { 36 | int32_t result = 0; 37 | 38 | do 39 | { 40 | result = (result << 7) | (*pos & 0x7F); 41 | } while (*pos++ & 0x80); 42 | 43 | return result; 44 | } 45 | 46 | void Common::Warning(uint8_t* pos, string msg) 47 | { 48 | if (ShowWarnings) 49 | { 50 | cerr << hex << setfill('0') << uppercase << endl; 51 | cerr << "WARNING IN\t" << Common::FileNames.top() << endl; 52 | cerr << "AT POSITION\t0x" << setw(8) << pos - Common::Offsets.top() << endl; 53 | cerr << "MESSAGE\t\t" << msg << endl; 54 | cerr << endl; 55 | } 56 | } 57 | 58 | void Common::Push(string fileName, uint8_t* data) 59 | { 60 | FileNames.push(fileName); 61 | Offsets.push(data); 62 | 63 | cout << FileNames.top() << endl; 64 | } 65 | 66 | void Common::Pop() 67 | { 68 | Offsets.pop(); 69 | FileNames.pop(); 70 | } 71 | 72 | void Common::Analyse(string tag, uint32_t val) 73 | { 74 | Common::Log.push_back(FileNames.top() + "," + tag + "," + to_string(val)); 75 | } 76 | 77 | void Common::Dump(string fileName) 78 | { 79 | ofstream ofs(fileName); 80 | ofs << "fileName,tag,val" << endl; 81 | 82 | for (size_t i = 0; i < Common::Log.size(); ++i) 83 | { 84 | ofs << Common::Log[i] << endl; 85 | } 86 | 87 | ofs.close(); 88 | } 89 | -------------------------------------------------------------------------------- /src/Common.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int32_t ReadFixLen(uint8_t*& pos, size_t bytes, bool littleEndian = true, bool isSigned = false); 12 | int32_t ReadVarLen(uint8_t*& pos); 13 | 14 | struct Common 15 | { 16 | static bool ShowWarnings; 17 | static std::stack FileNames; 18 | static std::stack Offsets; 19 | static std::vector Log; 20 | 21 | template 22 | static bool Assert(uint8_t* pos, T expected, T found) 23 | { 24 | if (found != expected) 25 | { 26 | std::cerr << std::hex << std::setfill('0') << std::uppercase << std::endl; 27 | std::cerr << "ERROR IN\t" << Common::FileNames.top() << std::endl; 28 | std::cerr << "AT POSITION\t0x" << std::setw(8) << pos - Common::Offsets.top() << std::endl; 29 | std::cerr << "EXPECTED\t0x" << std::setw(8) << expected << std::endl; 30 | std::cerr << "INSTEAD GOT\t0x" << std::setw(8) << found << std::endl; 31 | std::cerr << std::endl; 32 | 33 | return false; 34 | } 35 | 36 | return true; 37 | } 38 | 39 | template 40 | static void Error(uint8_t* pos, std::string expected, T found) 41 | { 42 | std::cerr << std::hex << std::setfill('0') << std::uppercase << std::endl; 43 | std::cerr << "ERROR IN\t" << Common::FileNames.top() << std::endl; 44 | std::cerr << "AT POSITION\t0x" << std::setw(8) << pos - Common::Offsets.top() << std::endl; 45 | std::cerr << "EXPECTED\t" << expected << std::endl; 46 | std::cerr << "INSTEAD GOT\t0x" << std::setw(8) << found << std::endl; 47 | std::cerr << std::endl; 48 | } 49 | 50 | static void Warning(uint8_t* pos, std::string msg); 51 | static void Push(std::string fileName, uint8_t* data); 52 | static void Pop(); 53 | static void Analyse(std::string tag, uint32_t val); 54 | static void Dump(std::string fileName); 55 | }; 56 | -------------------------------------------------------------------------------- /src/Csar.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Cwar.hpp" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | struct CsarStrg 11 | { 12 | uint8_t* Offset; 13 | uint32_t Length; 14 | 15 | std::string String; 16 | }; 17 | 18 | struct CsarFile 19 | { 20 | uint8_t* Offset; 21 | uint32_t Length; 22 | 23 | std::string Location = ""; 24 | }; 25 | 26 | struct CsarCbnk 27 | { 28 | uint8_t* Offset; 29 | 30 | uint32_t Id; 31 | std::string FileName; 32 | }; 33 | 34 | struct CsarCseq 35 | { 36 | uint8_t* Offset; 37 | 38 | std::string FileName; 39 | }; 40 | 41 | struct CsarCgrp 42 | { 43 | uint8_t* Offset; 44 | 45 | uint32_t Id; 46 | std::string FileName; 47 | }; 48 | 49 | struct Csar 50 | { 51 | std::string FileName; 52 | std::streamoff Length; 53 | uint8_t* Data = nullptr; 54 | 55 | std::map Cwars; 56 | bool P; 57 | 58 | Csar(const char* fileName, bool p); 59 | ~Csar(); 60 | bool Extract(); 61 | }; 62 | -------------------------------------------------------------------------------- /src/Cseq.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | enum class SuffixType { None, Rnd, Var, Time, TimeRnd, TimeVar, If }; 9 | enum class ArgType { None, Uint8, Int8, Uint16, Int16, Rnd, Var, VarLen }; 10 | 11 | std::vector ReadArgs(uint8_t*& pos, ArgType argType); 12 | 13 | struct CseqCmd 14 | { 15 | SuffixType Suffix1 = SuffixType::None; 16 | SuffixType Suffix2 = SuffixType::None; 17 | SuffixType Suffix3 = SuffixType::None; 18 | bool Extended = false; 19 | uint8_t Cmd; 20 | std::vector Args; 21 | 22 | ArgType Arg1 = ArgType::None; 23 | ArgType Arg2 = ArgType::None; 24 | 25 | std::string Label; 26 | }; 27 | 28 | struct CseqLabl 29 | { 30 | uint8_t* Offset; 31 | std::string Label; 32 | }; 33 | 34 | struct Cseq 35 | { 36 | std::string FileName; 37 | std::streamoff Length; 38 | uint8_t* Data = nullptr; 39 | 40 | Cseq(const char* fileName); 41 | ~Cseq(); 42 | bool Convert(); 43 | }; 44 | -------------------------------------------------------------------------------- /src/Cwar.cpp: -------------------------------------------------------------------------------- 1 | #include "Cwar.hpp" 2 | #include "Common.hpp" 3 | #include "Cwav.hpp" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | Cwar::Cwar(const char* fileName) : FileName(fileName) 12 | { 13 | ifstream ifs(FileName, ios::binary | ios::ate); 14 | 15 | Length = ifs.tellg(); 16 | Data = new uint8_t[Length]; 17 | 18 | Common::Push(FileName, Data); 19 | 20 | ifs.seekg(0, ios::beg); 21 | ifs.read(reinterpret_cast(Data), Length); 22 | ifs.close(); 23 | } 24 | 25 | Cwar::~Cwar() 26 | { 27 | for (auto cwav : Cwavs) 28 | { 29 | delete cwav; 30 | } 31 | 32 | Common::Pop(); 33 | 34 | delete[] Data; 35 | } 36 | 37 | bool Cwar::Extract() 38 | { 39 | uint8_t* pos = Data; 40 | 41 | if (!Common::Assert(pos, 0x43574152, ReadFixLen(pos, 4, false))) { return false; } 42 | if (!Common::Assert(pos, 0xFEFF, ReadFixLen(pos, 2))) { return false; } 43 | if (!Common::Assert(pos, 0x40, ReadFixLen(pos, 2))) { return false; } 44 | 45 | uint32_t cwarVersion = ReadFixLen(pos, 4); 46 | 47 | if (!Common::Assert(pos, Length, ReadFixLen(pos, 4))) { return false; } 48 | if (!Common::Assert(pos, 0x2, ReadFixLen(pos, 4))) { return false; } 49 | if (!Common::Assert(pos, 0x6800, ReadFixLen(pos, 4))) { return false; } 50 | 51 | uint32_t infoOffset = ReadFixLen(pos, 4); 52 | uint32_t infoLength = ReadFixLen(pos, 4); 53 | 54 | if (!Common::Assert(pos, 0x6801, ReadFixLen(pos, 4))) { return false; } 55 | 56 | uint32_t fileOffset = ReadFixLen(pos, 4); 57 | uint32_t fileLength = ReadFixLen(pos, 4); 58 | 59 | pos = Data + infoOffset; 60 | 61 | if (!Common::Assert(pos, 0x494E464F, ReadFixLen(pos, 4, false))) { return false; } 62 | if (!Common::Assert(pos, infoLength, ReadFixLen(pos, 4))) { return false; } 63 | 64 | uint32_t cwavCount = ReadFixLen(pos, 4); 65 | 66 | vector cwavs; 67 | 68 | for (uint32_t i = 0; i < cwavCount; ++i) 69 | { 70 | if (!Common::Assert(pos, 0x1F00, ReadFixLen(pos, 4))) { return false; } 71 | 72 | CwarCwav cwav{}; 73 | cwav.Offset = Data + fileOffset + 8 + ReadFixLen(pos, 4); 74 | cwav.Length = ReadFixLen(pos, 4); 75 | 76 | cwavs.push_back(cwav); 77 | } 78 | 79 | pos = Data + fileOffset; 80 | 81 | if (!Common::Assert(pos, 0x46494C45, ReadFixLen(pos, 4, false))) { return false; } 82 | if (!Common::Assert(pos, fileLength, ReadFixLen(pos, 4))) { return false; } 83 | 84 | for (uint32_t i = 0; i < cwavCount; ++i) 85 | { 86 | ofstream ofs(string(to_string(i) + ".bcwav"), ofstream::binary); 87 | ofs.write(reinterpret_cast(cwavs[i].Offset), cwavs[i].Length); 88 | ofs.close(); 89 | 90 | Cwavs.push_back(new Cwav(string(to_string(i) + ".bcwav").c_str())); 91 | 92 | if (!Cwavs[i]->Convert()) 93 | { 94 | return false; 95 | } 96 | } 97 | 98 | return true; 99 | } 100 | -------------------------------------------------------------------------------- /src/Cwar.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Cwav.hpp" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | struct CwarCwav 11 | { 12 | uint8_t* Offset; 13 | uint32_t Length; 14 | }; 15 | 16 | struct Cwar 17 | { 18 | std::string FileName; 19 | std::streamoff Length; 20 | uint8_t* Data = nullptr; 21 | 22 | std::vector Cwavs; 23 | 24 | Cwar(const char* fileName); 25 | ~Cwar(); 26 | bool Extract(); 27 | }; 28 | -------------------------------------------------------------------------------- /src/Cwav.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct DspContext 9 | { 10 | uint8_t PredScal; 11 | int16_t SampHist1; 12 | int16_t SampHist2; 13 | }; 14 | 15 | struct CwavChan 16 | { 17 | uint8_t* Offset; 18 | 19 | uint8_t* SampOffset; 20 | uint32_t AdpcmType; 21 | uint8_t* AdpcmOffset; 22 | 23 | int16_t DspCoeffs[16]; 24 | DspContext DspCntx; 25 | DspContext DspLoopCntx; 26 | 27 | std::vector PcmSamples; 28 | }; 29 | 30 | struct Cwav 31 | { 32 | std::string FileName; 33 | std::streamoff Length; 34 | uint8_t* Data = nullptr; 35 | 36 | uint8_t SampleMode; 37 | 38 | Cwav(const char* fileName); 39 | ~Cwav(); 40 | bool Convert(); 41 | }; 42 | -------------------------------------------------------------------------------- /src/caesar.cpp: -------------------------------------------------------------------------------- 1 | #include "Common.hpp" 2 | #include "Csar.hpp" 3 | 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | int main(int argc, char* argv[]) 10 | { 11 | bool p = false; 12 | 13 | if (argc == 1) 14 | { 15 | cout << "OVERVIEW: Caesar" << endl << endl; 16 | cout << "USAGE: caesar [options] " << endl << endl; 17 | cout << "OPTIONS:" << endl; 18 | cout << "\t-p\tDo not ignore pan values of stereo samples" << endl; 19 | cout << "\t-w\tShow warnings" << endl; 20 | 21 | return 1; 22 | } 23 | else 24 | { 25 | for (int i = 1; i < argc; ++i) 26 | { 27 | if (!strcmp(argv[i], "-p")) 28 | { 29 | p = true; 30 | } 31 | else if (!strcmp(argv[i], "-w")) 32 | { 33 | Common::ShowWarnings = true; 34 | } 35 | else 36 | { 37 | Csar csar(argv[i], p); 38 | 39 | if (!csar.Extract()) 40 | { 41 | return 1; 42 | } 43 | } 44 | } 45 | } 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /src/libsmfc/libsmfc.h: -------------------------------------------------------------------------------- 1 | /** 2 | * libsmfc.h: simple standard midi writer by loveemu 3 | */ 4 | 5 | 6 | #ifndef LIBSMFC_H 7 | #define LIBSMFC_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" 11 | { 12 | #endif 13 | 14 | #include 15 | 16 | #if !defined(bool) && !defined(__cplusplus) 17 | typedef int bool; 18 | #define true 1 19 | #define false 0 20 | #endif /* !bool */ 21 | 22 | #ifndef byte 23 | typedef unsigned char byte; 24 | #endif /* !byte */ 25 | #ifndef sbyte 26 | typedef signed char sbyte; 27 | #endif /* !sbyte */ 28 | 29 | unsigned int smfReadVarLength(byte* buffer, size_t bufferSize); 30 | size_t smfWriteByte(size_t sizeToTransfer, unsigned int value, byte* buffer, size_t bufferSize); 31 | size_t smfGetVarLengthSize(unsigned int value); 32 | size_t smfWriteVarLength(unsigned int value, byte* buffer, size_t bufferSize); 33 | 34 | 35 | typedef struct TagSmfEvent SmfEvent; 36 | struct TagSmfEvent 37 | { 38 | byte* data; 39 | size_t size; 40 | int time; 41 | int port; 42 | SmfEvent* prevEvent; 43 | SmfEvent* nextEvent; 44 | }; 45 | 46 | SmfEvent* smfEventCreate(int time, int port, const byte* data, size_t dataSize); 47 | void smfEventDelete(SmfEvent* event); 48 | SmfEvent* smfEventCopy(SmfEvent* event); 49 | size_t smfEventGetSize(SmfEvent* event); 50 | size_t smfEventWrite(SmfEvent* event, byte* buffer, size_t bufferSize); 51 | int smfEventCompare(SmfEvent* event, SmfEvent* targetEvent); 52 | 53 | 54 | typedef struct TagSmfTrack 55 | { 56 | SmfEvent* firstEvent; 57 | SmfEvent* lastEvent; 58 | } SmfTrack; 59 | 60 | SmfTrack* smfTrackCreate(void); 61 | void smfTrackDelete(SmfTrack* track); 62 | SmfTrack* smfTrackCopy(SmfTrack* track); 63 | bool smfTrackInsertEvent(SmfTrack* track, int time, int port, const byte* data, size_t dataSize); 64 | size_t smfTrackGetSize(SmfTrack* track); 65 | size_t smfTrackWrite(SmfTrack* track, byte* buffer, size_t bufferSize); 66 | int smfTrackGetEndTiming(SmfTrack* track); 67 | int smfTrackSetEndTiming(SmfTrack* track, int newEndTiming); 68 | 69 | 70 | typedef struct TagSmf 71 | { 72 | int numTracks; 73 | int timebase; 74 | SmfTrack** track; 75 | } Smf; 76 | 77 | Smf* smfCreate(void); 78 | void smfDelete(Smf* seq); 79 | Smf* smfCopy(Smf* seq); 80 | bool smfInsertEvent(Smf* seq, int time, int port, int track, const byte* data, size_t dataSize); 81 | size_t smfGetSize(Smf* seq); 82 | size_t smfWrite(Smf* seq, byte* buffer, size_t bufferSize); 83 | int smfSetTimebase(Smf* seq, int newTimebase); 84 | int smfSetEndTimingOfTrack(Smf* seq, int track, int newEndTiming); 85 | 86 | #ifdef __cplusplus 87 | } 88 | #endif 89 | 90 | #endif /* !LIBSMFC_H */ 91 | -------------------------------------------------------------------------------- /src/libsmfc/libsmfcx.h: -------------------------------------------------------------------------------- 1 | /** 2 | * libsmfcx.h: libsmfc extra functions by loveemu 3 | */ 4 | 5 | 6 | #ifndef LIBSMFCX_H 7 | #define LIBSMFCX_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" 11 | { 12 | #endif 13 | 14 | #include "libsmfc.h" 15 | 16 | #define SMF_CONTROL_BANKSELM 0 17 | #define SMF_CONTROL_MODULATION 1 18 | #define SMF_CONTROL_PORTAMENTOTIME 5 19 | #define SMF_CONTROL_DATAENTRYM 6 20 | #define SMF_CONTROL_VOLUME 7 21 | #define SMF_CONTROL_PANPOT 10 22 | #define SMF_CONTROL_EXPRESSION 11 23 | #define SMF_CONTROL_BANKSELL 32 24 | #define SMF_CONTROL_DATAENTRYL 38 25 | #define SMF_CONTROL_PORTAMENTO 65 26 | #define SMF_CONTROL_PORTAMENTOCTRL 84 27 | #define SMF_CONTROL_TIMBRE 71 28 | #define SMF_CONTROL_RELEASETIME 72 29 | #define SMF_CONTROL_ATTACKTIME 73 30 | #define SMF_CONTROL_BRIGHTNESS 74 31 | #define SMF_CONTROL_DECAYTIME 75 32 | #define SMF_CONTROL_VIBRATORATE 76 33 | #define SMF_CONTROL_VIBRATODEPTH 77 34 | #define SMF_CONTROL_VIBRATODELAY 78 35 | #define SMF_CONTROL_REVERB 91 36 | #define SMF_CONTROL_CHORUS 93 37 | #define SMF_CONTROL_NRPNL 98 38 | #define SMF_CONTROL_NRPNM 99 39 | #define SMF_CONTROL_RPNL 100 40 | #define SMF_CONTROL_RPNM 101 41 | #define SMF_CONTROL_MONO 126 42 | #define SMF_CONTROL_POLY 127 43 | 44 | #define SMF_META_TEXT 0x01 45 | #define SMF_META_COPYRIGHT 0x02 46 | #define SMF_META_TRACKNAME 0x03 47 | #define SMF_META_SEQUENCENAME 0x03 48 | #define SMF_META_SETTEMPO 0x51 49 | 50 | bool smfWriteFile(Smf* seq, const char* filename); 51 | bool smfInsertNoteOff(Smf* seq, int time, int channel, int track, int key, int velocity); 52 | bool smfInsertNoteOn(Smf* seq, int time, int channel, int track, int key, int velocity); 53 | bool smfInsertNote(Smf* seq, int time, int channel, int track, int key, int velocity, int duration); 54 | bool smfInsertKeyPress(Smf* seq, int time, int channel, int track, int key, int amount); 55 | bool smfInsertControl(Smf* seq, int time, int channel, int track, int controlNumber, int value); 56 | bool smfInsertProgram(Smf* seq, int time, int channel, int track, int programNumber); 57 | bool smfInsertChanPress(Smf* seq, int time, int channel, int track, int key, int amount); 58 | bool smfInsertPitchBend(Smf* seq, int time, int channel, int track, int value); 59 | bool smfInsertSysex(Smf* seq, int time, int port, int track, const byte* data, size_t dataSize); 60 | bool smfInsertMetaEvent(Smf* seq, int time, int track, int metaType, const byte* data, size_t dataSize); 61 | bool smfInsertMetaText(Smf* seq, int time, int track, int metaType, const char* text); 62 | 63 | bool smfInsertGM1SystemOn(Smf* seq, int time, int port, int track); 64 | bool smfInsertMasterVolume(Smf* seq, int time, int port, int track, int volume); 65 | bool smfInsertTempo(Smf* seq, int time, int track, int microSeconds); 66 | bool smfInsertTempoBPM(Smf* seq, int time, int track, double bpm); 67 | 68 | #ifdef __cplusplus 69 | } 70 | #endif 71 | 72 | #endif /* !LIBSMFCX_H */ 73 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | #end_of_line = lf 5 | 6 | [*.{c,cpp,h,hpp}] 7 | charset = utf-8 8 | indent_style = space 9 | indent_size = 2 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/.gitignore: -------------------------------------------------------------------------------- 1 | # Doxygen artifacts 2 | doc/ 3 | 4 | ### C++ ### 5 | # Compiled Object files 6 | *.slo 7 | *.lo 8 | *.o 9 | *.obj 10 | 11 | # Precompiled Headers 12 | *.gch 13 | *.pch 14 | 15 | # Compiled Dynamic libraries 16 | *.so 17 | *.dylib 18 | *.dll 19 | 20 | # Fortran module files 21 | *.mod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | ### CMake ### 35 | CMakeCache.txt 36 | CMakeFiles 37 | CMakeScripts 38 | Makefile 39 | cmake_install.cmake 40 | install_manifest.txt 41 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | dist: trusty 3 | language: cpp 4 | 5 | matrix: 6 | include: 7 | # GCC5 8 | - os: linux 9 | addons: 10 | apt: 11 | sources: 12 | - ubuntu-toolchain-r-test 13 | packages: 14 | - g++-5 15 | env: 16 | - MATRIX_EVAL="CC=gcc-5 && CXX=g++-5" 17 | 18 | # GCC6 19 | - os: linux 20 | addons: 21 | apt: 22 | sources: 23 | - ubuntu-toolchain-r-test 24 | packages: 25 | - g++-6 26 | env: 27 | - MATRIX_EVAL="CC=gcc-6 && CXX=g++-6" 28 | 29 | # GCC7 30 | - os: linux 31 | addons: 32 | apt: 33 | sources: 34 | - ubuntu-toolchain-r-test 35 | packages: 36 | - g++-7 37 | env: 38 | - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" 39 | before_install: 40 | - eval "${MATRIX_EVAL}" 41 | 42 | # Clang 3.6 43 | - os: linux 44 | addons: 45 | apt: 46 | sources: 47 | - ubuntu-toolchain-r-test 48 | - llvm-toolchain-precise-3.6 49 | packages: 50 | - clang-3.6 51 | env: 52 | - MATRIX_EVAL="CC=clang-3.6 && CXX=clang++-3.6" 53 | 54 | before_install: 55 | - eval "${MATRIX_EVAL}" 56 | 57 | script: 58 | - cmake -H. -Bbuild 59 | - cmake --build build 60 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8.2) 2 | 3 | project(sf2cute 4 | LANGUAGES C CXX 5 | VERSION 0.2.0) 6 | 7 | set(SF2CUTE_EXAMPLES_INSTALL_DIR "bin" CACHE "PATH" "Where to install the examples") 8 | option(SF2CUTE_INSTALL_EXAMPLES "Install example executables" ON) 9 | 10 | #============================================================================ 11 | # sf2cute library 12 | #============================================================================ 13 | add_library(sf2cute "") 14 | 15 | target_sources(sf2cute 16 | PRIVATE 17 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/file.cpp 18 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/file_writer.cpp 19 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/generator_item.cpp 20 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/instrument.cpp 21 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/instrument_zone.cpp 22 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/modulator.cpp 23 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/modulator_key.cpp 24 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/modulator_item.cpp 25 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/preset.cpp 26 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/preset_zone.cpp 27 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff.cpp 28 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff_ibag_chunk.cpp 29 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff_igen_chunk.cpp 30 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff_imod_chunk.cpp 31 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff_inst_chunk.cpp 32 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff_pbag_chunk.cpp 33 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff_pgen_chunk.cpp 34 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff_phdr_chunk.cpp 35 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff_pmod_chunk.cpp 36 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff_shdr_chunk.cpp 37 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff_smpl_chunk.cpp 38 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/sample.cpp 39 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/zone.cpp 40 | 41 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/byteio.hpp 42 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/file_writer.hpp 43 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff.hpp 44 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff_ibag_chunk.hpp 45 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff_igen_chunk.hpp 46 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff_imod_chunk.hpp 47 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff_inst_chunk.hpp 48 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff_pbag_chunk.hpp 49 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff_pgen_chunk.hpp 50 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff_phdr_chunk.hpp 51 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff_pmod_chunk.hpp 52 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff_shdr_chunk.hpp 53 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute/riff_smpl_chunk.hpp 54 | 55 | ${CMAKE_CURRENT_LIST_DIR}/include/sf2cute.hpp 56 | ${CMAKE_CURRENT_LIST_DIR}/include/sf2cute/modulator_item.hpp 57 | ${CMAKE_CURRENT_LIST_DIR}/include/sf2cute/preset.hpp 58 | ${CMAKE_CURRENT_LIST_DIR}/include/sf2cute/preset_zone.hpp 59 | ${CMAKE_CURRENT_LIST_DIR}/include/sf2cute/sample.hpp 60 | ${CMAKE_CURRENT_LIST_DIR}/include/sf2cute/types.hpp 61 | ${CMAKE_CURRENT_LIST_DIR}/include/sf2cute/version.hpp 62 | ${CMAKE_CURRENT_LIST_DIR}/include/sf2cute/zone.hpp 63 | ${CMAKE_CURRENT_LIST_DIR}/include/sf2cute/file.hpp 64 | ${CMAKE_CURRENT_LIST_DIR}/include/sf2cute/generator_item.hpp 65 | ${CMAKE_CURRENT_LIST_DIR}/include/sf2cute/instrument.hpp 66 | ${CMAKE_CURRENT_LIST_DIR}/include/sf2cute/instrument_zone.hpp 67 | ${CMAKE_CURRENT_LIST_DIR}/include/sf2cute/modulator.hpp 68 | ${CMAKE_CURRENT_LIST_DIR}/include/sf2cute/modulator_key.hpp 69 | ) 70 | 71 | target_include_directories(sf2cute 72 | PUBLIC 73 | $ 74 | $ 75 | PRIVATE 76 | ${CMAKE_CURRENT_LIST_DIR}/src/sf2cute 77 | ) 78 | 79 | set_target_properties(sf2cute PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) 80 | 81 | target_compile_features(sf2cute PUBLIC cxx_std_14) 82 | 83 | add_library(sf2cute::sf2cute ALIAS sf2cute) 84 | 85 | add_executable(write_sf2 "") 86 | 87 | target_sources(write_sf2 88 | PRIVATE 89 | ${CMAKE_CURRENT_LIST_DIR}/examples/write_sf2.cpp 90 | ) 91 | target_link_libraries(write_sf2 PRIVATE sf2cute) 92 | 93 | #============================================================================ 94 | # Install and Export sf2cute 95 | #============================================================================ 96 | 97 | include(GNUInstallDirs) 98 | 99 | # install library files needed for linking 100 | install( 101 | TARGETS sf2cute 102 | EXPORT sf2cute-targets 103 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 104 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 105 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 106 | ) 107 | 108 | # install the public header files 109 | install( 110 | DIRECTORY ${CMAKE_SOURCE_DIR}/include/ 111 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 112 | ) 113 | 114 | # installs the *cmake files in share directory 115 | install( 116 | EXPORT sf2cute-targets 117 | FILE sf2cute-targets.cmake 118 | NAMESPACE sf2cute:: 119 | DESTINATION share/sf2cute 120 | ) 121 | 122 | include(CMakePackageConfigHelpers) 123 | 124 | write_basic_package_version_file( 125 | ${CMAKE_BINARY_DIR}/cmake/sf2cute-config-version.cmake 126 | VERSION ${SF2CUTE_VERSION} 127 | COMPATIBILITY AnyNewerVersion 128 | ) 129 | 130 | configure_package_config_file( 131 | ${CMAKE_CURRENT_LIST_DIR}/cmake/sf2cute-config.cmake.in 132 | ${CMAKE_CURRENT_BINARY_DIR}/cmake/sf2cute-config.cmake 133 | INSTALL_DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/sf2cute 134 | ) 135 | 136 | install( 137 | FILES 138 | ${CMAKE_BINARY_DIR}/cmake/sf2cute-config.cmake 139 | ${CMAKE_BINARY_DIR}/cmake/sf2cute-config-version.cmake 140 | DESTINATION share/sf2cute 141 | ) 142 | 143 | if(SF2CUTE_INSTALL_EXAMPLES) 144 | install( 145 | TARGETS write_sf2 146 | RUNTIME DESTINATION ${SF2CUTE_EXAMPLES_INSTALL_DIR} 147 | ) 148 | endif() 149 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/LICENSE: -------------------------------------------------------------------------------- 1 | The zlib/libpng License 2 | ======================= 3 | 4 | Copyright (c) 2016 gocha 5 | 6 | This software is provided 'as-is', without any express or implied 7 | warranty. In no event will the authors be held liable for any damages 8 | arising from the use of this software. 9 | 10 | Permission is granted to anyone to use this software for any purpose, 11 | including commercial applications, and to alter it and redistribute it 12 | freely, subject to the following restrictions: 13 | 14 | 1. The origin of this software must not be misrepresented; you must not 15 | claim that you wrote the original software. If you use this software 16 | in a product, an acknowledgment in the product documentation would be 17 | appreciated but is not required. 18 | 19 | 2. Altered source versions must be plainly marked as such, and must not be 20 | misrepresented as being the original software. 21 | 22 | 3. This notice may not be removed or altered from any source 23 | distribution. 24 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/README.md: -------------------------------------------------------------------------------- 1 | SF2cute: C++ Library for SoundFont 2 2 | ==================================== 3 | [![Travis Build Status](https://travis-ci.org/gocha/sf2cute.svg?branch=master)](https://travis-ci.org/gocha/sf2cute) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/elt3wbk82y8natuy/branch/master?svg=true)](https://ci.appveyor.com/project/gocha/sf2cute/branch/master) 4 | 5 | SF2cute is a C++ library for writing SoundFont 2. 6 | 7 | Downloading 8 | ----------- 9 | 10 | You can download a source code package of the latest release 11 | from [Releases](https://github.com/gocha/sf2cute/releases/latest) page. 12 | 13 | Visual Studio users can install the precompiled binaries from the [SF2cute NuGet Gallery](https://www.nuget.org/packages/sf2cute). 14 | 15 | [SF2cute Documentation](http://gocha.github.io/sf2cute/) is available on the GitHub Pages. 16 | You can also build the documentation by yourself using [Doxygen](http://www.doxygen.org). 17 | 18 | Compiling 19 | --------- 20 | 21 | First of all, install the following prerequisite softwares. 22 | 23 | * [CMake](https://cmake.org/) 24 | * Modern C++ compiler (requires C++14 features) 25 | - Clang 3.6 or later 26 | - GCC (G++) 5 or later 27 | - [Visual Studio Community Edition](https://www.visualstudio.com/products/visual-studio-community-vs) 2015 or later (Windows only) 28 | 29 | The following command will generate a Makefile for your system. You can use `cmake-gui` if you want to use a GUI and configure the options. 30 | 31 | ``` bash 32 | cmake . 33 | ``` 34 | 35 | Then compile the library using the generated project file. 36 | 37 | ``` bash 38 | make 39 | ``` 40 | 41 | SoundFont file writing example 42 | ------------------------------ 43 | 44 | Here is an example of SoundFont file writing. 45 | 46 | ``` cpp 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | 54 | #include 55 | 56 | using namespace sf2cute; 57 | 58 | /// Makes a pulse wave of n/8 duty cycle. 59 | /// @param n the duty cycle n/8. 60 | /// @return the pulse wave sample datapoints. 61 | std::vector MakePulseVector(int n) { 62 | std::vector data(200); 63 | size_t width = data.size() * n / 8; 64 | std::fill(data.begin(), std::next(data.begin(), width), 0x4000); 65 | std::fill(std::next(data.begin(), width), data.end(), 0); 66 | return data; 67 | } 68 | 69 | /// Writes SoundFont 2 file using SF2cute. 70 | /// @param argc Number of arguments. Not used. 71 | /// @param argv Argument vector. Not used. 72 | /// @return 0 if the SoundFont file is successfully written. 73 | int main(int argc, char * argv[]) { 74 | SoundFont sf2; 75 | 76 | // Set metadata. 77 | sf2.set_sound_engine("EMU8000"); 78 | sf2.set_bank_name("Chipsound"); 79 | sf2.set_rom_name("ROM"); 80 | 81 | // Construct sample datapoints. 82 | std::vector data_50 = MakePulseVector(4); 83 | 84 | // Add a sample. 85 | std::shared_ptr sample_50 = sf2.NewSample( 86 | "Square", // name 87 | data_50, // sample data 88 | 0, // start loop 89 | uint32_t(data_50.size()), // end loop 90 | 44100, // sample rate 91 | 57, // root key 92 | 0); // microtuning 93 | 94 | // Make an instrument zone. 95 | SFInstrumentZone instrument_zone(sample_50, 96 | std::vector{ 97 | //SFGeneratorItem(SFGenerator::kKeyRange, RangesType(0, 127)), 98 | //SFGeneratorItem(SFGenerator::kVelRange, RangesType(0, 127)), 99 | SFGeneratorItem(SFGenerator::kSampleModes, uint16_t(SampleMode::kLoopContinuously)), 100 | }, 101 | std::vector{}); 102 | // Add more generators or modulators if necessary. 103 | instrument_zone.SetGenerator(SFGeneratorItem(SFGenerator::kReverbEffectsSend, 618)); 104 | instrument_zone.SetModulator(SFModulatorItem( 105 | SFModulator(SFGeneralController::kNoteOnVelocity, 106 | SFControllerDirection::kDecrease, SFControllerPolarity::kUnipolar, 107 | SFControllerType::kConcave), 108 | SFGenerator::kInitialAttenuation, 109 | 960, 110 | SFModulator(0), 111 | SFTransform::kLinear)); 112 | 113 | // Add an instrument. 114 | std::shared_ptr instrument_50 = sf2.NewInstrument( 115 | sample_50->name(), 116 | std::vector{ 117 | std::move(instrument_zone) 118 | }); 119 | 120 | // Add a preset. 121 | std::shared_ptr preset_50 = sf2.NewPreset( 122 | instrument_50->name(), 0, 0, 123 | std::vector{ 124 | SFPresetZone(instrument_50) 125 | }); 126 | 127 | // Write SoundFont file. 128 | try { 129 | std::ofstream ofs("output.sf2", std::ios::binary); 130 | sf2.Write(ofs); 131 | return 0; 132 | } 133 | catch (const std::fstream::failure & e) { 134 | // File output error. 135 | std::cerr << e.what() << std::endl; 136 | return 1; 137 | } 138 | catch (const std::exception & e) { 139 | // Other errors. 140 | // For example: Too many samples. 141 | std::cerr << e.what() << std::endl; 142 | return 1; 143 | } 144 | } 145 | ``` 146 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 0.2.{build} 2 | 3 | image: Visual Studio 2017 4 | 5 | environment: 6 | matrix: 7 | - generator: "Visual Studio 15" 8 | config: Release 9 | arch: vs2017-x86 10 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 11 | 12 | - generator: "Visual Studio 15 Win64" 13 | config: Release 14 | arch: vs2017-x64 15 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 16 | 17 | - generator: "Visual Studio 14" 18 | config: Release 19 | arch: vs2015-x86 20 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 21 | 22 | - generator: "Visual Studio 14 Win64" 23 | config: Release 24 | arch: vs2015-x64 25 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 26 | 27 | init: 28 | - git config --global core.autocrlf input 29 | 30 | build_script: 31 | - cmake -G"%generator%" -H. -Bbuild 32 | #- cmake --build build --config "%config%" 33 | - msbuild build\sf2cute.sln /t:build /p:Configuration="%config%" /m /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" 34 | 35 | after_build: 36 | - ps: $env:gitrev = git describe --tags 37 | - ps: $env:my_version = "$env:gitrev" 38 | - set package_name=sf2cute-%my_version%-%arch% 39 | - mkdir lib 40 | - copy "build\%config%\sf2cute.lib" lib 41 | - 7z a %package_name%.zip examples include lib README.md LICENSE 42 | 43 | artifacts: 44 | - path: $(package_name).zip 45 | name: $(arch) 46 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/cmake/sf2cute-config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | if(NOT TARGET sf2cute::sf2cute) 4 | include(${CMAKE_CURRENT_LIST_DIR}/sf2cute-targets.cmake) 5 | endif() -------------------------------------------------------------------------------- /src/sf2cute-0.2/examples/debug.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// Prints SoundFont 2 object. 3 | 4 | #ifndef SF2CUTE_EXAMPLES_DEBUG_HPP_ 5 | #define SF2CUTE_EXAMPLES_DEBUG_HPP_ 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | namespace { 15 | 16 | /// Prints internal informations of a SoundFont object. 17 | /// @param sf2 the SoundFont object. 18 | void PrintSoundFont(const sf2cute::SoundFont & sf2) { 19 | //using namespace sf2cute; 20 | 21 | // Child elements: 22 | printf("File %p\n", &sf2); 23 | printf(" Presets: %zu\n", sf2.presets().size()); 24 | printf(" Instruments: %zu\n", sf2.instruments().size()); 25 | printf(" Samples: %zu\n", sf2.samples().size()); 26 | printf("\n"); 27 | 28 | // INFO fields: 29 | printf("Sound Engine: %s\n", sf2.sound_engine().c_str()); 30 | printf("Bank Name: %s\n", sf2.bank_name().c_str()); 31 | printf("ROM Name: %s\n", sf2.has_rom_name() ? sf2.rom_name().c_str() : "(none)"); 32 | printf("ROM Version: %s\n", sf2.has_rom_version() ? sf2.rom_version().to_string().c_str() : "(none)"); 33 | printf("Creation Date: %s\n", sf2.has_creation_date() ? sf2.creation_date().c_str() : "(none)"); 34 | printf("Sound Engineers: %s\n", sf2.has_engineers() ? sf2.engineers().c_str() : "(none)"); 35 | printf("Product: %s\n", sf2.has_product() ? sf2.product().c_str() : "(none)"); 36 | printf("Copyright: %s\n", sf2.has_copyright() ? sf2.copyright().c_str() : "(none)"); 37 | printf("Comment: %s\n", sf2.has_comment() ? sf2.comment().c_str() : "(none)"); 38 | printf("Software: %s\n", sf2.has_software() ? sf2.software().c_str() : "(none)"); 39 | printf("\n"); 40 | 41 | // Presets: 42 | for (auto && preset : sf2.presets()) { 43 | printf("Preset [%d:%d] %p \"%s\" (parent file: %p)\n", 44 | preset->bank(), 45 | preset->preset_number(), 46 | preset.get(), 47 | preset->name().c_str(), 48 | preset->has_parent_file() ? &preset->parent_file() : nullptr); 49 | 50 | // Global preset zone: 51 | if (preset->has_global_zone()) { 52 | printf(" -> Global Preset Zone %p\n", &preset->global_zone()); 53 | 54 | // Generators: 55 | for (const auto & generator : preset->global_zone().generators()) { 56 | printf(" -> Generator %p\n", &generator); 57 | } 58 | 59 | // Modulators: 60 | for (const auto & modulator : preset->global_zone().modulators()) { 61 | printf(" -> Modulator %p\n", &modulator); 62 | } 63 | } 64 | 65 | // Preset zones: 66 | for (const auto & preset_zone : preset->zones()) { 67 | printf(" -> Preset Zone %p\n", &preset_zone); 68 | 69 | // Instrument: 70 | if (preset_zone->has_instrument()) { 71 | auto instrument = preset_zone->instrument(); 72 | printf(" -> Instrument %p \"%s\" (parent file: %p)\n", 73 | instrument.get(), 74 | instrument->name().c_str(), 75 | instrument->has_parent_file() ? &instrument->parent_file() : nullptr); 76 | } 77 | 78 | // Generators: 79 | for (const auto & generator : preset_zone->generators()) { 80 | printf(" -> Generator %p\n", &generator); 81 | } 82 | 83 | // Modulators: 84 | for (const auto & modulator : preset_zone->modulators()) { 85 | printf(" -> Modulator %p\n", &modulator); 86 | } 87 | } 88 | } 89 | printf("\n"); 90 | 91 | // Instruments: 92 | for (auto && instrument : sf2.instruments()) { 93 | printf("Instrument %p \"%s\" (parent file: %p)\n", 94 | instrument.get(), 95 | instrument->name().c_str(), 96 | instrument->has_parent_file() ? &instrument->parent_file() : nullptr); 97 | 98 | // Global instrument zone: 99 | if (instrument->has_global_zone()) { 100 | printf(" -> Global Instrument Zone %p (parent instrument %p)\n", 101 | &instrument->global_zone(), 102 | instrument->global_zone().has_parent_instrument() ? &instrument->global_zone().parent_instrument() : nullptr); 103 | 104 | // Generators: 105 | for (const auto & generator : instrument->global_zone().generators()) { 106 | printf(" -> Generator %p\n", &generator); 107 | } 108 | 109 | // Modulators: 110 | for (const auto & modulator : instrument->global_zone().modulators()) { 111 | printf(" -> Modulator %p\n", &modulator); 112 | } 113 | } 114 | 115 | // Instrument zones: 116 | for (auto && instrument_zone : instrument->zones()) { 117 | printf(" -> Instrument Zone %p\n", &instrument_zone); 118 | 119 | // Sample: 120 | if (instrument_zone->has_sample()) { 121 | auto sample = instrument_zone->sample(); 122 | printf(" -> Sample %p \"%s\" (parent file: %p)\n", 123 | sample.get(), 124 | sample->name().c_str(), 125 | sample->has_parent_file() ? &sample->parent_file() : nullptr); 126 | 127 | // Generators: 128 | for (const auto & generator : instrument_zone->generators()) { 129 | printf(" -> Generator %p\n", &generator); 130 | } 131 | 132 | // Modulators: 133 | for (const auto & modulator : instrument_zone->modulators()) { 134 | printf(" -> Modulator %p\n", &modulator); 135 | } 136 | } 137 | } 138 | } 139 | printf("\n"); 140 | 141 | // Samples: 142 | for (auto && sample : sf2.samples()) { 143 | printf("Sample %p \"%s\" (link %p, parent file: %p)\n", 144 | sample.get(), 145 | sample->name().c_str(), 146 | sample->has_link() ? sample->link().get() : nullptr, 147 | sample->has_parent_file() ? &sample->parent_file() : nullptr); 148 | } 149 | printf("\n"); 150 | } 151 | 152 | } // namespace 153 | 154 | #endif // SF2CUTE_EXAMPLES_DEBUG_HPP_ 155 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/examples/write_sf2.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// Writes SoundFont 2 file using SF2cute. 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | //#include "debug.hpp" 14 | 15 | using namespace sf2cute; 16 | 17 | /// Makes a pulse wave of n/8 duty cycle. 18 | /// @param n the duty cycle n/8. 19 | /// @return the pulse wave sample datapoints. 20 | std::vector MakePulseVector(int n) { 21 | std::vector data(200); 22 | size_t width = data.size() * n / 8; 23 | std::fill(data.begin(), std::next(data.begin(), width), 0x4000); 24 | std::fill(std::next(data.begin(), width), data.end(), 0); 25 | return data; 26 | } 27 | 28 | /// Writes SoundFont 2 file using SF2cute. 29 | /// @param argc Number of arguments. Not used. 30 | /// @param argv Argument vector. Not used. 31 | /// @return 0 if the SoundFont file is successfully written. 32 | int main(int argc, char * argv[]) { 33 | SoundFont sf2; 34 | 35 | // Set metadata. 36 | sf2.set_sound_engine("EMU8000"); 37 | sf2.set_bank_name("Chipsound"); 38 | sf2.set_rom_name("ROM"); 39 | 40 | // Construct sample datapoints. 41 | std::vector data_50 = MakePulseVector(4); 42 | 43 | // Add a sample. 44 | std::shared_ptr sample_50 = sf2.NewSample( 45 | "Square", // name 46 | data_50, // sample data 47 | 0, // start loop 48 | uint32_t(data_50.size()), // end loop 49 | 44100, // sample rate 50 | 57, // root key 51 | 0); // microtuning 52 | 53 | // Make an instrument zone. 54 | SFInstrumentZone instrument_zone(sample_50, 55 | std::vector{ 56 | //SFGeneratorItem(SFGenerator::kKeyRange, RangesType(0, 127)), 57 | //SFGeneratorItem(SFGenerator::kVelRange, RangesType(0, 127)), 58 | SFGeneratorItem(SFGenerator::kSampleModes, uint16_t(SampleMode::kLoopContinuously)), 59 | }, 60 | std::vector{}); 61 | // Add more generators or modulators if necessary. 62 | instrument_zone.SetGenerator(SFGeneratorItem(SFGenerator::kReverbEffectsSend, 618)); 63 | instrument_zone.SetModulator(SFModulatorItem( 64 | SFModulator(SFGeneralController::kNoteOnVelocity, 65 | SFControllerDirection::kDecrease, SFControllerPolarity::kUnipolar, 66 | SFControllerType::kConcave), 67 | SFGenerator::kInitialAttenuation, 68 | 960, 69 | SFModulator(0), 70 | SFTransform::kLinear)); 71 | 72 | // Add an instrument. 73 | std::shared_ptr instrument_50 = sf2.NewInstrument( 74 | sample_50->name(), 75 | std::vector{ 76 | std::move(instrument_zone) 77 | }); 78 | 79 | // Add a preset. 80 | std::shared_ptr preset_50 = sf2.NewPreset( 81 | instrument_50->name(), 0, 0, 82 | std::vector{ 83 | SFPresetZone(instrument_50) 84 | }); 85 | 86 | // Print the tree for debugging. 87 | #ifdef SF2CUTE_EXAMPLES_DEBUG_HPP_ 88 | PrintSoundFont(sf2); 89 | #endif 90 | 91 | // Write SoundFont file. 92 | try { 93 | std::ofstream ofs("output.sf2", std::ios::binary); 94 | sf2.Write(ofs); 95 | return 0; 96 | } 97 | catch (const std::fstream::failure & e) { 98 | // File output error. 99 | std::cerr << e.what() << std::endl; 100 | return 1; 101 | } 102 | catch (const std::exception & e) { 103 | // Other errors. 104 | // For example: Too many samples. 105 | std::cerr << e.what() << std::endl; 106 | return 1; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/include/sf2cute.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont 2 library header. 3 | /// 4 | /// @author gocha 5 | 6 | #ifndef SF2CUTE_SF2CUTE_HPP_ 7 | #define SF2CUTE_SF2CUTE_HPP_ 8 | 9 | #include "sf2cute/version.hpp" 10 | #include "sf2cute/types.hpp" 11 | #include "sf2cute/modulator.hpp" 12 | #include "sf2cute/sample.hpp" 13 | #include "sf2cute/generator_item.hpp" 14 | #include "sf2cute/modulator_key.hpp" 15 | #include "sf2cute/modulator_item.hpp" 16 | #include "sf2cute/zone.hpp" 17 | #include "sf2cute/instrument_zone.hpp" 18 | #include "sf2cute/instrument.hpp" 19 | #include "sf2cute/preset_zone.hpp" 20 | #include "sf2cute/preset.hpp" 21 | #include "sf2cute/file.hpp" 22 | 23 | #endif // SF2CUTE_SF2CUTE_HPP_ 24 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/include/sf2cute/generator_item.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont 2 Generator class header. 3 | /// 4 | /// @author gocha 5 | 6 | #ifndef SF2CUTE_GENERATOR_ITEM_HPP_ 7 | #define SF2CUTE_GENERATOR_ITEM_HPP_ 8 | 9 | #include 10 | #include 11 | 12 | #include "types.hpp" 13 | 14 | namespace sf2cute { 15 | 16 | /// The SFGeneratorItem class represents a generator. 17 | /// 18 | /// @remarks This class represents the official sfGenList/sfInstGenList type. 19 | /// @see "7.5 The PGEN Sub-chunk". In SoundFont Technical Specification 2.04. 20 | /// @see "7.9 The IGEN Sub-chunk". In SoundFont Technical Specification 2.04. 21 | class SFGeneratorItem { 22 | public: 23 | /// Constructs a new SFGeneratorItem. 24 | SFGeneratorItem(); 25 | 26 | /// Constructs a new SFGeneratorItem using the specified properties. 27 | /// @param op the type of the generator. 28 | /// @param amount the value to be assigned to the generator. 29 | SFGeneratorItem(SFGenerator op, GenAmountType amount); 30 | 31 | /// Constructs a new copy of specified SFGeneratorItem. 32 | /// @param origin a SFGeneratorItem object. 33 | SFGeneratorItem(const SFGeneratorItem & origin) = default; 34 | 35 | /// Copy-assigns a new value to the SFGeneratorItem, replacing its current contents. 36 | /// @param origin a SFGeneratorItem object. 37 | SFGeneratorItem & operator=(const SFGeneratorItem & origin) = default; 38 | 39 | /// Acquires the contents of specified SFGeneratorItem. 40 | /// @param origin a SFGeneratorItem object. 41 | SFGeneratorItem(SFGeneratorItem && origin) = default; 42 | 43 | /// Move-assigns a new value to the SFGeneratorItem, replacing its current contents. 44 | /// @param origin a SFGeneratorItem object. 45 | SFGeneratorItem & operator=(SFGeneratorItem && origin) = default; 46 | 47 | /// Destructs the SFGeneratorItem. 48 | ~SFGeneratorItem() = default; 49 | 50 | /// Returns the type of the generator. 51 | /// @return the type of the generator. 52 | SFGenerator op() const noexcept { 53 | return op_; 54 | } 55 | 56 | /// Sets the type of the generator. 57 | /// @param op the type of the generator. 58 | void set_op(SFGenerator op) { 59 | op_ = std::move(op); 60 | } 61 | 62 | /// Returns the amount of the generator. 63 | /// @return the value represents the amount of the generator. 64 | GenAmountType amount() const noexcept { 65 | return amount_; 66 | } 67 | 68 | /// Sets the amount of the generator. 69 | /// @param amount the value to be assigned to the generator. 70 | void set_amount(GenAmountType amount) { 71 | amount_ = std::move(amount); 72 | } 73 | 74 | /// Sets the amount of the generator in a range. 75 | /// @param lo the low end of range. 76 | /// @param hi the high end of range. 77 | void set_amount(uint8_t lo, uint8_t hi) { 78 | amount_.range.lo = std::move(lo); 79 | amount_.range.hi = std::move(hi); 80 | } 81 | 82 | /// Sets the amount of the generator in an integer. 83 | /// @param amount the value to be assigned to the generator. 84 | void set_amount(int16_t amount) { 85 | amount_.value = std::move(amount); 86 | } 87 | 88 | /// Sets the amount of the generator in an unsigned integer. 89 | /// @param amount the value to be assigned to the generator. 90 | void set_amount(uint16_t amount) { 91 | amount_.uvalue = std::move(amount); 92 | } 93 | 94 | /// Indicates a SFGenerator object is "less than" the other one. 95 | /// @param x the first SFGenerator to be compared. 96 | /// @param y the second SFGenerator to be compared. 97 | /// @return true if a SFGenerator object is "less than" the other one. 98 | /// 99 | /// @remarks This function compares two SFGenerator enums based on the ordering requirement of a generator chunk. 100 | static bool Compare(const SFGenerator & x, const SFGenerator & y) noexcept; 101 | 102 | private: 103 | /// The type of the generator. 104 | SFGenerator op_; 105 | 106 | /// The amount of the generator. 107 | GenAmountType amount_; 108 | }; 109 | 110 | } // namespace sf2cute 111 | 112 | #endif // SF2CUTE_GENERATOR_ITEM_HPP_ 113 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/include/sf2cute/instrument_zone.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont 2 Instrument Zone class header. 3 | /// 4 | /// @author gocha 5 | 6 | #ifndef SF2CUTE_INSTRUMENT_ZONE_HPP_ 7 | #define SF2CUTE_INSTRUMENT_ZONE_HPP_ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "zone.hpp" 14 | 15 | namespace sf2cute { 16 | 17 | class SFSample; 18 | class SFGeneratorItem; 19 | class SFModulatorItem; 20 | class SFInstrument; 21 | class SoundFont; 22 | 23 | /// The SFInstrumentZone class represents an instrument zone. 24 | /// 25 | /// @remarks This class represents the official sfInstBag type and the sampleID generator. 26 | /// @see "7.6 The IBAG Sub-chunk". In SoundFont Technical Specification 2.04. 27 | class SFInstrumentZone : public SFZone { 28 | friend class SFInstrument; 29 | 30 | public: 31 | /// Constructs a new empty SFInstrumentZone. 32 | SFInstrumentZone(); 33 | 34 | /// Constructs a new SFInstrumentZone with a sample. 35 | /// @param sample the sample to be associated with the zone. 36 | explicit SFInstrumentZone(std::weak_ptr sample); 37 | 38 | /// Constructs a new SFInstrumentZone with a sample, using the specified generators and modulators. 39 | /// @param sample the sample to be associated with the zone. 40 | /// @param generators a collection of generators to be assigned to the zone. 41 | /// @param modulators a collection of modulators to be assigned to the zone. 42 | SFInstrumentZone(std::weak_ptr sample, 43 | std::vector generators, 44 | std::vector modulators); 45 | 46 | /// Constructs a new copy of specified SFInstrumentZone. 47 | /// @param origin a SFInstrumentZone object. 48 | SFInstrumentZone(const SFInstrumentZone & origin); 49 | 50 | /// Copy-assigns a new value to the SFInstrumentZone, replacing its current contents. 51 | /// @param origin a SFInstrumentZone object. 52 | SFInstrumentZone & operator=(const SFInstrumentZone & origin); 53 | 54 | /// Acquires the contents of specified SFInstrumentZone. 55 | /// @param origin a SFInstrumentZone object. 56 | SFInstrumentZone(SFInstrumentZone && origin) = default; 57 | 58 | /// Move-assigns a new value to the SFInstrumentZone, replacing its current contents. 59 | /// @param origin a SFInstrumentZone object. 60 | SFInstrumentZone & operator=(SFInstrumentZone && origin) = default; 61 | 62 | /// Destructs the SFInstrumentZone. 63 | virtual ~SFInstrumentZone() override = default; 64 | 65 | /// Returns true if the zone has an associated sample. 66 | /// @return true if the zone has an associated sample. 67 | /// @remarks This function returns false if the associated sample has been deleted. 68 | bool has_sample() const noexcept { 69 | return !sample_.expired(); 70 | } 71 | 72 | /// Returns the associated sample. 73 | /// @return a pointer to the associated sample. 74 | /// @remarks This function returns nullptr if the associated sample has been deleted. 75 | std::shared_ptr sample() const noexcept { 76 | return sample_.lock(); 77 | } 78 | 79 | /// Sets the associated sample. 80 | /// @param sample a pointer to the associated sample. 81 | void set_sample(std::weak_ptr sample); 82 | 83 | /// Resets the associated sample. 84 | void reset_sample() noexcept { 85 | sample_.reset(); 86 | } 87 | 88 | /// Returns true if the zone has a parent file. 89 | /// @return true if the zone has a parent file. 90 | bool has_parent_file() const noexcept; 91 | 92 | /// Returns the parent file. 93 | /// @return the parent file. 94 | SoundFont & parent_file() const noexcept; 95 | 96 | /// Returns true if the zone has a parent instrument. 97 | /// @return true if the zone has a parent instrument. 98 | bool has_parent_instrument() const noexcept { 99 | return parent_instrument_ != nullptr; 100 | } 101 | 102 | /// Returns the parent instrument. 103 | /// @return the parent instrument. 104 | SFInstrument & parent_instrument() const noexcept; 105 | 106 | private: 107 | /// Sets the parent instrument. 108 | /// @param parent_instrument the parent instrument. 109 | void set_parent_instrument( 110 | SFInstrument & parent_instrument) noexcept; 111 | 112 | /// Resets the parent instrument. 113 | void reset_parent_instrument() noexcept { 114 | parent_instrument_ = nullptr; 115 | } 116 | 117 | /// The associated sample. 118 | std::weak_ptr sample_; 119 | 120 | /// The parent instrument. 121 | SFInstrument * parent_instrument_; 122 | }; 123 | 124 | } // namespace sf2cute 125 | 126 | #endif // SF2CUTE_INSTRUMENT_ZONE_HPP_ 127 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/include/sf2cute/modulator_item.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont 2 Modulator class header. 3 | /// 4 | /// @author gocha 5 | 6 | #ifndef SF2CUTE_MODULATOR_ITEM_HPP_ 7 | #define SF2CUTE_MODULATOR_ITEM_HPP_ 8 | 9 | #include 10 | #include 11 | 12 | #include "types.hpp" 13 | #include "modulator.hpp" 14 | #include "modulator_key.hpp" 15 | 16 | namespace sf2cute { 17 | 18 | /// The SFModulatorItem class represents a modulator. 19 | /// 20 | /// @remarks This class represents the official sfModList/sfInstModList type. 21 | /// @see "7.4 The PMOD Sub-chunk". In SoundFont Technical Specification 2.04. 22 | /// @see "7.8 The IMOD Sub-chunk". In SoundFont Technical Specification 2.04. 23 | class SFModulatorItem { 24 | public: 25 | /// Constructs a new SFModulatorItem. 26 | SFModulatorItem(); 27 | 28 | /// Constructs a new SFModulatorItem using the specified controllers. 29 | /// @param source_op the source of data for the modulator. 30 | /// @param destination_op the destination of the modulator. 31 | /// @param amount the degree to which the source modulates the destination. 32 | /// @param amount_source_op the modulation source to be applied to the modulation amount. 33 | /// @param transform_op the transform type to be applied to the modulation source. 34 | SFModulatorItem(SFModulator source_op, 35 | SFGenerator destination_op, 36 | int16_t amount, 37 | SFModulator amount_source_op, 38 | SFTransform transform_op); 39 | 40 | /// Constructs a new copy of specified SFModulatorItem. 41 | /// @param origin a SFModulatorItem object. 42 | SFModulatorItem(const SFModulatorItem & origin) = default; 43 | 44 | /// Copy-assigns a new value to the SFModulatorItem, replacing its current contents. 45 | /// @param origin a SFModulatorItem object. 46 | SFModulatorItem & operator=(const SFModulatorItem & origin) = default; 47 | 48 | /// Acquires the contents of specified SFModulatorItem. 49 | /// @param origin a SFModulatorItem object. 50 | SFModulatorItem(SFModulatorItem && origin) = default; 51 | 52 | /// Move-assigns a new value to the SFModulatorItem, replacing its current contents. 53 | /// @param origin a SFModulatorItem object. 54 | SFModulatorItem & operator=(SFModulatorItem && origin) = default; 55 | 56 | /// Destructs the SFModulatorItem. 57 | ~SFModulatorItem() = default; 58 | 59 | /// Returns the unique key of the modulator. 60 | /// @return the unique key of the modulator. 61 | /// @remarks Using source_op(), destination_op() or amount_source_op() is recommended for an individual member access. 62 | /// @see source_op() 63 | /// @see destination_op() 64 | /// @see amount_source_op() 65 | SFModulatorKey key() const noexcept { 66 | return key_; 67 | } 68 | 69 | /// Sets the unique key of the modulator. 70 | /// @param key the unique key of the modulator. 71 | /// @remarks Using set_source_op(SFModulator), set_destination_op(SFGenerator) or set_amount_source_op(SFModulator) is recommended for an individual member access. 72 | /// @see set_source_op(SFModulator) 73 | /// @see set_destination_op(SFGenerator) 74 | /// @see set_amount_source_op(SFModulator) 75 | void set_key(SFModulatorKey key) { 76 | key_ = std::move(key); 77 | } 78 | 79 | /// Returns the source of data for the modulator. 80 | /// @return the source of data for the modulator. 81 | SFModulator source_op() const noexcept { 82 | return key_.source_op(); 83 | } 84 | 85 | /// Sets the source of data for the modulator. 86 | /// @param source_op the source of data for the modulator. 87 | void set_source_op(SFModulator source_op) { 88 | key_.set_source_op(std::move(source_op)); 89 | } 90 | 91 | /// Returns the destination of the modulator. 92 | /// @return the destination of the modulator. 93 | SFGenerator destination_op() const noexcept { 94 | return key_.destination_op(); 95 | } 96 | 97 | /// Sets the destination of the modulator. 98 | /// @param destination_op the destination of the modulator. 99 | void set_destination_op(SFGenerator destination_op) { 100 | key_.set_destination_op(std::move(destination_op)); 101 | } 102 | 103 | /// Returns the constant of modulation amount. 104 | /// @return the constant of modulation amount. 105 | int16_t amount() const noexcept { 106 | return amount_; 107 | } 108 | 109 | /// Sets the constant of modulation amount. 110 | /// @param amount the degree to which the source modulates the destination. 111 | void set_amount(int16_t amount) { 112 | amount_ = std::move(amount); 113 | } 114 | 115 | /// Returns the modulation source to be applied to the modulation amount. 116 | /// @return the modulation source to be applied to the modulation amount. 117 | SFModulator amount_source_op() const noexcept { 118 | return key_.amount_source_op(); 119 | } 120 | 121 | /// Sets the modulation source to be applied to the modulation amount. 122 | /// @param amount_source_op the modulation source to be applied to the modulation amount. 123 | void set_amount_source_op(SFModulator amount_source_op) { 124 | key_.set_amount_source_op(std::move(amount_source_op)); 125 | } 126 | 127 | /// Returns the transform type to be applied to the modulation source. 128 | /// @return the transform type to be applied to the modulation source. 129 | SFTransform transform_op() const noexcept { 130 | return transform_op_; 131 | } 132 | 133 | /// Sets the transform type to be applied to the modulation source. 134 | /// @param transform_op the transform type to be applied to the modulation source. 135 | void set_transform_op(SFTransform transform_op) { 136 | transform_op_ = std::move(transform_op); 137 | } 138 | 139 | private: 140 | /// The unique key of the modulator. 141 | SFModulatorKey key_; 142 | 143 | /// The degree to which the source modulates the destination. 144 | int16_t amount_; 145 | 146 | /// The transform type to be applied to the modulation source. 147 | SFTransform transform_op_; 148 | }; 149 | 150 | } // namespace sf2cute 151 | 152 | #endif // SF2CUTE_MODULATOR_ITEM_HPP_ 153 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/include/sf2cute/preset_zone.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont 2 Preset Zone class header. 3 | /// 4 | /// @author gocha 5 | 6 | #ifndef SF2CUTE_PRESET_ZONE_HPP_ 7 | #define SF2CUTE_PRESET_ZONE_HPP_ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "zone.hpp" 14 | 15 | namespace sf2cute { 16 | 17 | class SFGeneratorItem; 18 | class SFModulatorItem; 19 | class SFInstrument; 20 | class SFPreset; 21 | class SoundFont; 22 | 23 | /// The SFPresetZone class represents a preset zone. 24 | /// 25 | /// @remarks This class represents the official sfPresetBag type and the instrument generator. 26 | /// @see "7.3 The PBAG Sub-chunk". In SoundFont Technical Specification 2.04. 27 | class SFPresetZone : public SFZone { 28 | friend class SFPreset; 29 | 30 | public: 31 | /// Constructs a new empty SFPresetZone. 32 | SFPresetZone(); 33 | 34 | /// Constructs a new SFPresetZone with an instrument. 35 | /// @param instrument the instrument to be associated with the zone. 36 | explicit SFPresetZone(std::weak_ptr instrument); 37 | 38 | /// Constructs a new SFPresetZone with an instrument, using the specified generators and modulators. 39 | /// @param instrument the instrument to be associated with the zone. 40 | /// @param generators a collection of generators to be assigned to the zone. 41 | /// @param modulators a collection of modulators to be assigned to the zone. 42 | SFPresetZone(std::weak_ptr instrument, 43 | std::vector generators, 44 | std::vector modulators); 45 | 46 | /// Constructs a new copy of specified SFPresetZone. 47 | /// @param origin a SFPresetZone object. 48 | SFPresetZone(const SFPresetZone & origin); 49 | 50 | /// Copy-assigns a new value to the SFPresetZone, replacing its current contents. 51 | /// @param origin a SFPresetZone object. 52 | SFPresetZone & operator=(const SFPresetZone & origin); 53 | 54 | /// Acquires the contents of specified SFPresetZone. 55 | /// @param origin a SFPresetZone object. 56 | SFPresetZone(SFPresetZone && origin) = default; 57 | 58 | /// Move-assigns a new value to the SFPresetZone, replacing its current contents. 59 | /// @param origin a SFPresetZone object. 60 | SFPresetZone & operator=(SFPresetZone && origin) = default; 61 | 62 | /// Destructs the SFPresetZone. 63 | virtual ~SFPresetZone() override = default; 64 | 65 | /// Returns true if the zone has an associated instrument. 66 | /// @return true if the zone has an associated instrument. 67 | /// @remarks This function returns false if the associated instrument has been deleted. 68 | bool has_instrument() const noexcept { 69 | return !instrument_.expired(); 70 | } 71 | 72 | /// Returns the associated instrument. 73 | /// @return a pointer to the associated instrument. 74 | /// @remarks This function returns nullptr if the associated instrument has been deleted. 75 | std::shared_ptr instrument() const noexcept { 76 | return instrument_.lock(); 77 | } 78 | 79 | /// Sets the associated instrument. 80 | /// @param instrument a pointer to the associated instrument. 81 | void set_instrument(std::weak_ptr instrument); 82 | 83 | /// Resets the associated instrument. 84 | void reset_instrument() noexcept { 85 | instrument_.reset(); 86 | } 87 | 88 | /// Returns true if the zone has a parent file. 89 | /// @return true if the zone has a parent file. 90 | bool has_parent_file() const noexcept; 91 | 92 | /// Returns the parent file. 93 | /// @return the parent file. 94 | SoundFont & parent_file() const noexcept; 95 | 96 | /// Returns true if the zone has a parent preset. 97 | /// @return true if the zone has a parent preset. 98 | bool has_parent_preset() const noexcept { 99 | return parent_preset_ != nullptr; 100 | } 101 | 102 | /// Returns the parent preset. 103 | /// @return the parent preset. 104 | SFPreset & parent_preset() const noexcept; 105 | 106 | private: 107 | /// Sets the parent preset. 108 | /// @param parent_preset the parent preset. 109 | void set_parent_preset(SFPreset & parent_preset) noexcept; 110 | 111 | /// Resets the parent preset. 112 | void reset_parent_preset() noexcept { 113 | parent_preset_ = nullptr; 114 | } 115 | 116 | /// The associated instrument. 117 | std::weak_ptr instrument_; 118 | 119 | /// The parent preset. 120 | SFPreset * parent_preset_; 121 | }; 122 | 123 | } // namespace sf2cute 124 | 125 | #endif // SF2CUTE_PRESET_ZONE_HPP_ 126 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/include/sf2cute/version.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont 2 library version. 3 | /// 4 | /// @author gocha 5 | 6 | #ifndef SF2CUTE_VERSION_HPP_ 7 | #define SF2CUTE_VERSION_HPP_ 8 | 9 | /// The version number of SoundFont 2 library. 10 | /// 11 | /// SF2CUTE_VERSION % 100 is the patch level. \n 12 | /// SF2CUTE_VERSION / 100 % 1000 is the minor version. \n 13 | /// SF2CUTE_VERSION / 100000 is the major version. 14 | #define SF2CUTE_VERSION 100 15 | 16 | #endif // SF2CUTE_VERSION_HPP_ 17 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/include/sf2cute/zone.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont 2 Zone class header. 3 | /// 4 | /// @author gocha 5 | 6 | #ifndef SF2CUTE_ZONE_HPP_ 7 | #define SF2CUTE_ZONE_HPP_ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "types.hpp" 14 | #include "generator_item.hpp" 15 | #include "modulator_key.hpp" 16 | #include "modulator_item.hpp" 17 | 18 | namespace sf2cute { 19 | 20 | /// The SFZone class represents a zone. 21 | /// 22 | /// @remarks This class represents the official sfPresetBag/sfInstBag type. 23 | /// @see "7.3 The PBAG Sub-chunk". In SoundFont Technical Specification 2.04. 24 | /// @see "7.7 The IBAG Sub-chunk". In SoundFont Technical Specification 2.04. 25 | class SFZone { 26 | public: 27 | /// Constructs a new empty SFZone. 28 | SFZone(); 29 | 30 | /// Constructs a new SFZone using the specified generators and modulators. 31 | /// @param generators a collection of generators to be assigned to the zone. 32 | /// @param modulators a collection of modulators to be assigned to the zone. 33 | SFZone( 34 | std::vector generators, 35 | std::vector modulators); 36 | 37 | /// Constructs a new copy of specified SFZone. 38 | /// @param origin a SFZone object. 39 | SFZone(const SFZone & origin); 40 | 41 | /// Copy-assigns a new value to the SFZone, replacing its current contents. 42 | /// @param origin a SFZone object. 43 | SFZone & operator=(const SFZone & origin); 44 | 45 | /// Acquires the contents of specified SFZone. 46 | /// @param origin a SFZone object. 47 | SFZone(SFZone && origin) = default; 48 | 49 | /// Move-assigns a new value to the SFZone, replacing its current contents. 50 | /// @param origin a SFZone object. 51 | SFZone & operator=(SFZone && origin) = default; 52 | 53 | /// Destructs the SFZone. 54 | virtual ~SFZone() = default; 55 | 56 | /// Returns the list of generators. 57 | /// @return the list of generators assigned to the zone. 58 | const std::vector> & generators() const noexcept { 59 | return generators_; 60 | } 61 | 62 | /// Sets a generator to the zone. 63 | /// @param generator a generator to be assigned to the zone. 64 | /// @remarks An existing generator which has the same key will be overwritten. 65 | void SetGenerator(SFGeneratorItem generator); 66 | 67 | /// Finds the generator which is the specified type. 68 | /// @return the position of the found generator or std::end(generators()) if no such generator is found. 69 | const std::vector>::const_iterator 70 | FindGenerator(SFGenerator op) const; 71 | 72 | /// Removes a generator from the zone. 73 | /// @param position the generator to remove. 74 | void RemoveGenerator( 75 | std::vector>::const_iterator position) { 76 | generators_.erase(position); 77 | } 78 | 79 | /// Removes generators from the zone. 80 | /// @param first the first generator to remove. 81 | /// @param last the last generator to remove. 82 | void RemoveGenerator( 83 | std::vector>::const_iterator first, 84 | std::vector>::const_iterator last) { 85 | generators_.erase(first, last); 86 | } 87 | 88 | /// Removes generators from the zone. 89 | /// @param predicate unary predicate which returns true if the generator should be removed. 90 | void RemoveGeneratorIf( 91 | std::function &)> predicate); 92 | 93 | /// Removes all of the generators. 94 | void ClearGenerators() noexcept { 95 | generators_.clear(); 96 | } 97 | 98 | /// Returns the list of modulators. 99 | /// @return the list of modulators assigned to the zone. 100 | const std::vector> & modulators() const noexcept { 101 | return modulators_; 102 | } 103 | 104 | /// Sets a modulator to the zone. 105 | /// @param modulator a modulator to be assigned to the zone. 106 | /// @remarks An existing modulator which has the same key will be overwritten. 107 | void SetModulator(SFModulatorItem modulator); 108 | 109 | /// Finds the modulator which is the specified type. 110 | /// @return the position of the found modulator or std::end(modulators()) if no such modulator is found. 111 | const std::vector>::const_iterator 112 | FindModulator(SFModulatorKey key) const; 113 | 114 | /// Removes a modulator from the zone. 115 | /// @param position the modulator to remove. 116 | void RemoveModulator( 117 | std::vector>::const_iterator position) { 118 | modulators_.erase(position); 119 | } 120 | 121 | /// Removes modulators from the zone. 122 | /// @param first the first modulator to remove. 123 | /// @param last the last modulator to remove. 124 | void RemoveModulator( 125 | std::vector>::const_iterator first, 126 | std::vector>::const_iterator last) { 127 | modulators_.erase(first, last); 128 | } 129 | 130 | /// Removes modulators from the zone. 131 | /// @param predicate unary predicate which returns true if the modulator should be removed. 132 | void RemoveModulatorIf( 133 | std::function &)> predicate); 134 | 135 | /// Removes all of the modulators. 136 | void ClearModulators() noexcept { 137 | modulators_.clear(); 138 | } 139 | 140 | protected: 141 | /// The list of generators. 142 | std::vector> generators_; 143 | 144 | /// The list of modulators. 145 | std::vector> modulators_; 146 | }; 147 | 148 | } // namespace sf2cute 149 | 150 | #endif // SF2CUTE_ZONE_HPP_ 151 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/sf2cute.autopkg: -------------------------------------------------------------------------------- 1 | configurations { 2 | Toolset { 3 | key: "PlatformToolset"; 4 | choices: { v140, v140_xp }; 5 | }; 6 | 7 | Configuration { 8 | key: "Configuration"; 9 | choices: { Release, Debug }; 10 | }; 11 | 12 | RuntimeLibrary { 13 | key: "RuntimeLibrary"; 14 | choices: { MultiThreaded, MultiThreadedDebug, MultiThreadedDLL, MultiThreadedDebugDLL }; 15 | }; 16 | } 17 | 18 | nuget { 19 | nuspec { 20 | id = sf2cute; 21 | version: 0.1.0.3; 22 | title: SF2cute C++ SoundFont Libary; 23 | authors: { gocha }; 24 | owners: { gocha }; 25 | licenseUrl: "https://github.com/gocha/sf2cute/blob/master/LICENSE"; 26 | projectUrl: "https://github.com/gocha/sf2cute"; 27 | iconUrl: "https://assets-cdn.github.com/favicon.ico"; 28 | requireLicenseAcceptance: false; 29 | summary: Modern C++ library for SoundFont 2; 30 | description: @"SF2cute is a Modern C++ library for writing SoundFont 2. 31 | 32 | This package bundles the static libraries for Visual Studio 2015."; 33 | releaseNotes: "First public beta release."; 34 | copyright: Copyright 2016 (c) gocha; 35 | tags: { C++, sf2cute, soundfont, native, CoApp, nativepackage }; 36 | }; 37 | 38 | files { 39 | include: { include\* }; 40 | 41 | nestedInclude: { 42 | #destination = ${d_include}sf2cute; 43 | include\sf2cute\* 44 | }; 45 | 46 | docs: { doc\**\* }; 47 | 48 | [v140, Win32, static, MultiThreadedDebug] { 49 | lib: { build\lib\v140\Win32\static\MultiThreadedDebug\sf2cute.lib }; 50 | symbols_: { 51 | #destination = ${d_lib}; 52 | build\lib\v140\Win32\static\MultiThreadedDebug\sf2cute.pdb 53 | }; 54 | } 55 | 56 | [v140, Win32, static, MultiThreadedDebugDLL] { 57 | lib: { build\lib\v140\Win32\static\MultiThreadedDebugDLL\sf2cute.lib }; 58 | symbols_: { 59 | #destination = ${d_lib}; 60 | build\lib\v140\Win32\static\MultiThreadedDebugDLL\sf2cute.pdb 61 | }; 62 | } 63 | 64 | [v140, Win32, static, MultiThreaded] { 65 | lib: { build\lib\v140\Win32\static\MultiThreaded\sf2cute.lib }; 66 | } 67 | 68 | [v140, Win32, static, MultiThreadedDLL] { 69 | lib: { build\lib\v140\Win32\static\MultiThreadedDLL\sf2cute.lib }; 70 | } 71 | 72 | [v140, Win32, ltcg, MultiThreaded] { 73 | lib: { build\lib\v140\Win32\ltcg\MultiThreaded\sf2cute.lib }; 74 | } 75 | 76 | [v140, Win32, ltcg, MultiThreadedDLL] { 77 | lib: { build\lib\v140\Win32\ltcg\MultiThreadedDLL\sf2cute.lib }; 78 | } 79 | 80 | [v140, x64, static, MultiThreadedDebug] { 81 | lib: { build\lib\v140\x64\static\MultiThreadedDebug\sf2cute.lib }; 82 | symbols_: { 83 | #destination = ${d_lib}; 84 | build\lib\v140\x64\static\MultiThreadedDebug\sf2cute.pdb 85 | }; 86 | } 87 | 88 | [v140, x64, static, MultiThreadedDebugDLL] { 89 | lib: { build\lib\v140\x64\static\MultiThreadedDebugDLL\sf2cute.lib }; 90 | symbols_: { 91 | #destination = ${d_lib}; 92 | build\lib\v140\x64\static\MultiThreadedDebugDLL\sf2cute.pdb 93 | }; 94 | } 95 | 96 | [v140, x64, static, MultiThreaded] { 97 | lib: { build\lib\v140\x64\static\MultiThreaded\sf2cute.lib }; 98 | } 99 | 100 | [v140, x64, static, MultiThreadedDLL] { 101 | lib: { build\lib\v140\x64\static\MultiThreadedDLL\sf2cute.lib }; 102 | } 103 | 104 | [v140, x64, ltcg, MultiThreaded] { 105 | lib: { build\lib\v140\x64\ltcg\MultiThreaded\sf2cute.lib }; 106 | } 107 | 108 | [v140, x64, ltcg, MultiThreadedDLL] { 109 | lib: { build\lib\v140\x64\ltcg\MultiThreadedDLL\sf2cute.lib }; 110 | } 111 | 112 | [v140_xp, Win32, static, MultiThreadedDebug] { 113 | lib: { build\lib\v140_xp\Win32\static\MultiThreadedDebug\sf2cute.lib }; 114 | symbols_: { 115 | #destination = ${d_lib}; 116 | build\lib\v140_xp\Win32\static\MultiThreadedDebug\sf2cute.pdb 117 | }; 118 | } 119 | 120 | [v140_xp, Win32, static, MultiThreadedDebugDLL] { 121 | lib: { build\lib\v140_xp\Win32\static\MultiThreadedDebugDLL\sf2cute.lib }; 122 | symbols_: { 123 | #destination = ${d_lib}; 124 | build\lib\v140_xp\Win32\static\MultiThreadedDebugDLL\sf2cute.pdb 125 | }; 126 | } 127 | 128 | [v140_xp, Win32, static, MultiThreaded] { 129 | lib: { build\lib\v140_xp\Win32\static\MultiThreaded\sf2cute.lib }; 130 | } 131 | 132 | [v140_xp, Win32, static, MultiThreadedDLL] { 133 | lib: { build\lib\v140_xp\Win32\static\MultiThreadedDLL\sf2cute.lib }; 134 | } 135 | 136 | [v140_xp, Win32, ltcg, MultiThreaded] { 137 | lib: { build\lib\v140_xp\Win32\ltcg\MultiThreaded\sf2cute.lib }; 138 | } 139 | 140 | [v140_xp, Win32, ltcg, MultiThreadedDLL] { 141 | lib: { build\lib\v140_xp\Win32\ltcg\MultiThreadedDLL\sf2cute.lib }; 142 | } 143 | 144 | [v140_xp, x64, static, MultiThreadedDebug] { 145 | lib: { build\lib\v140_xp\x64\static\MultiThreadedDebug\sf2cute.lib }; 146 | symbols_: { 147 | #destination = ${d_lib}; 148 | build\lib\v140_xp\x64\static\MultiThreadedDebug\sf2cute.pdb 149 | }; 150 | } 151 | 152 | [v140_xp, x64, static, MultiThreadedDebugDLL] { 153 | lib: { build\lib\v140_xp\x64\static\MultiThreadedDebugDLL\sf2cute.lib }; 154 | symbols_: { 155 | #destination = ${d_lib}; 156 | build\lib\v140_xp\x64\static\MultiThreadedDebugDLL\sf2cute.pdb 157 | }; 158 | } 159 | 160 | [v140_xp, x64, static, MultiThreaded] { 161 | lib: { build\lib\v140_xp\x64\static\MultiThreaded\sf2cute.lib }; 162 | } 163 | 164 | [v140_xp, x64, static, MultiThreadedDLL] { 165 | lib: { build\lib\v140_xp\x64\static\MultiThreadedDLL\sf2cute.lib }; 166 | } 167 | 168 | [v140_xp, x64, ltcg, MultiThreaded] { 169 | lib: { build\lib\v140_xp\x64\ltcg\MultiThreaded\sf2cute.lib }; 170 | } 171 | 172 | [v140_xp, x64, ltcg, MultiThreadedDLL] { 173 | lib: { build\lib\v140_xp\x64\ltcg\MultiThreadedDLL\sf2cute.lib }; 174 | } 175 | }; 176 | } 177 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/byteio.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// Byte I/O templates. 3 | /// 4 | /// @author gocha 5 | 6 | #ifndef SF2CUTE_BYTEIO_HPP_ 7 | #define SF2CUTE_BYTEIO_HPP_ 8 | 9 | #include 10 | 11 | namespace sf2cute { 12 | 13 | /// Writes an 8-bit integer. 14 | /// @param out the output iterator. 15 | /// @param value the number to be written. 16 | /// @return the output iterator that points to the next element of the written data. 17 | /// @tparam OutputIterator an Iterator that can write to the pointed-to element. 18 | template 19 | OutputIterator WriteInt8(OutputIterator out, uint8_t value) { 20 | static_assert(sizeof(*out) == 1, "Element size of OutputIterator must be 1."); 21 | 22 | *out = static_cast(value); 23 | out = std::next(out, 1); 24 | 25 | return out; 26 | } 27 | 28 | /// Writes a 16-bit integer in little-endian order. 29 | /// @param out the output iterator. 30 | /// @param value the number to be written. 31 | /// @return the output iterator that points to the next element of the written data. 32 | /// @tparam OutputIterator an Iterator that can write to the pointed-to element. 33 | template 34 | OutputIterator WriteInt16L(OutputIterator out, uint16_t value) { 35 | static_assert(sizeof(*out) == 1, "Element size of OutputIterator must be 1."); 36 | 37 | *out = value & 0xff; 38 | out = std::next(out, 1); 39 | *out = static_cast((value >> 8) & 0xff); 40 | out = std::next(out, 1); 41 | 42 | return out; 43 | } 44 | 45 | /// Writes a 32-bit integer in little-endian order. 46 | /// @param out the output iterator. 47 | /// @param value the number to be written. 48 | /// @return the output iterator that points to the next element of the written data. 49 | /// @tparam OutputIterator an Iterator that can write to the pointed-to element. 50 | template 51 | OutputIterator WriteInt32L(OutputIterator out, uint32_t value) { 52 | static_assert(sizeof(*out) == 1, "Element size of OutputIterator must be 1."); 53 | 54 | *out = static_cast(value & 0xff); 55 | out = std::next(out, 1); 56 | *out = static_cast((value >> 8) & 0xff); 57 | out = std::next(out, 1); 58 | *out = static_cast((value >> 16) & 0xff); 59 | out = std::next(out, 1); 60 | *out = static_cast((value >> 24) & 0xff); 61 | out = std::next(out, 1); 62 | 63 | return out; 64 | } 65 | 66 | /// Writes an 8-bit integer. 67 | /// @param out the output destination object. 68 | /// @param value the number to be written. 69 | /// @tparam Insertable an object that implements an insertion operator for char value. 70 | template 71 | void InsertInt8(Insertable & out, uint8_t value) { 72 | out << static_cast(value); 73 | } 74 | 75 | /// Writes a 16-bit integer in little-endian order. 76 | /// @param out the output destination object. 77 | /// @param value the number to be written. 78 | /// @tparam Insertable an object that implements an insertion operator for char value. 79 | template 80 | void InsertInt16L(Insertable & out, uint16_t value) { 81 | out << static_cast(value & 0xff); 82 | out << static_cast((value >> 8) & 0xff); 83 | } 84 | 85 | /// Writes a 32-bit integer in little-endian order. 86 | /// @param out the output destination object. 87 | /// @param value the number to be written. 88 | /// @tparam Insertable an object that implements an insertion operator for char value. 89 | template 90 | void InsertInt32L(Insertable & out, uint32_t value) { 91 | out << static_cast(value & 0xff); 92 | out << static_cast((value >> 8) & 0xff); 93 | out << static_cast((value >> 16) & 0xff); 94 | out << static_cast((value >> 24) & 0xff); 95 | } 96 | 97 | } // namespace sf2cute 98 | 99 | #endif // SF2CUTE_BYTEIO_HPP_ 100 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/file_writer.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont 2 File writer class implementation. 3 | /// 4 | /// @author gocha 5 | 6 | #include "file_writer.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include "byteio.hpp" 17 | #include "riff.hpp" 18 | #include "riff_smpl_chunk.hpp" 19 | #include "riff_phdr_chunk.hpp" 20 | #include "riff_pbag_chunk.hpp" 21 | #include "riff_pmod_chunk.hpp" 22 | #include "riff_pgen_chunk.hpp" 23 | #include "riff_inst_chunk.hpp" 24 | #include "riff_ibag_chunk.hpp" 25 | #include "riff_imod_chunk.hpp" 26 | #include "riff_igen_chunk.hpp" 27 | #include "riff_shdr_chunk.hpp" 28 | 29 | namespace sf2cute { 30 | 31 | /// Constructs a new empty SoundFontWriter. 32 | SoundFontWriter::SoundFontWriter() : 33 | file_(nullptr) { 34 | } 35 | 36 | /// Constructs a new SoundFontWriter using specified file. 37 | SoundFontWriter::SoundFontWriter(const SoundFont & file) : 38 | file_(&file) { 39 | } 40 | 41 | /// Writes the SoundFont to a file. 42 | void SoundFontWriter::Write(const std::string & filename) { 43 | std::ofstream out; 44 | 45 | out.exceptions(std::ios::badbit | std::ios::failbit); 46 | out.open(filename, std::ios::binary); 47 | 48 | Write(out); 49 | } 50 | 51 | /// Writes the SoundFont to an output stream. 52 | void SoundFontWriter::Write(std::ostream & out) { 53 | RIFF riff("sfbk"); 54 | riff.AddChunk(MakeInfoListChunk()); 55 | riff.AddChunk(MakeSdtaListChunk()); 56 | riff.AddChunk(MakePdtaListChunk()); 57 | riff.Write(out); 58 | } 59 | 60 | /// Writes the SoundFont to an output stream. 61 | void SoundFontWriter::Write(std::ostream && out) { 62 | Write(out); 63 | } 64 | 65 | /// Make an INFO chunk. 66 | std::unique_ptr SoundFontWriter::MakeInfoListChunk() { 67 | std::unique_ptr info = std::make_unique("INFO"); 68 | 69 | // Mandatory chunks: 70 | 71 | info->AddSubchunk(MakeVersionChunk("ifil", SFVersionTag(2, 1))); 72 | 73 | info->AddSubchunk(MakeZSTRChunk("isng", file().sound_engine().substr(0, SoundFont::kInfoTextMaxLength))); 74 | 75 | info->AddSubchunk(MakeZSTRChunk("INAM", file().bank_name().substr(0, SoundFont::kInfoTextMaxLength))); 76 | 77 | // Optional chunks: 78 | 79 | if (file().has_rom_name()) { 80 | info->AddSubchunk(MakeZSTRChunk("irom", file().rom_name().substr(0, SoundFont::kInfoTextMaxLength))); 81 | } 82 | 83 | if (file().has_rom_version()) { 84 | info->AddSubchunk(MakeVersionChunk("iver", file().rom_version())); 85 | } 86 | 87 | if (file().has_creation_date()) { 88 | info->AddSubchunk(MakeZSTRChunk("ICRD", file().creation_date().substr(0, SoundFont::kInfoTextMaxLength))); 89 | } 90 | 91 | if (file().has_engineers()) { 92 | info->AddSubchunk(MakeZSTRChunk("IENG", file().engineers().substr(0, SoundFont::kInfoTextMaxLength))); 93 | } 94 | 95 | if (file().has_product()) { 96 | info->AddSubchunk(MakeZSTRChunk("IPRD", file().product().substr(0, SoundFont::kInfoTextMaxLength))); 97 | } 98 | 99 | if (file().has_copyright()) { 100 | info->AddSubchunk(MakeZSTRChunk("ICOP", file().copyright().substr(0, SoundFont::kInfoTextMaxLength))); 101 | } 102 | 103 | if (file().has_comment()) { 104 | info->AddSubchunk(MakeZSTRChunk("ICMT", file().comment().substr(0, SoundFont::kInfoTextMaxLength))); 105 | } 106 | 107 | if (file().has_software()) { 108 | info->AddSubchunk(MakeZSTRChunk("ISFT", file().software().substr(0, SoundFont::kInfoTextMaxLength))); 109 | } 110 | 111 | return std::move(info); 112 | } 113 | 114 | /// Make a sdta chunk. 115 | std::unique_ptr SoundFontWriter::MakeSdtaListChunk() { 116 | std::unique_ptr sdta = std::make_unique("sdta"); 117 | sdta->AddSubchunk(std::make_unique(file().samples())); 118 | return std::move(sdta); 119 | } 120 | 121 | /// Make a pdta chunk. 122 | std::unique_ptr SoundFontWriter::MakePdtaListChunk() { 123 | // Constructs a map for indexing each instruments. 124 | std::unordered_map instrument_index_map; 125 | for (uint16_t index = 0; index < file().instruments().size(); index++) { 126 | instrument_index_map.insert(std::make_pair(file().instruments().at(index).get(), index)); 127 | } 128 | 129 | // Constructs a map for indexing each samples. 130 | std::unordered_map sample_index_map; 131 | for (uint16_t index = 0; index < file().samples().size(); index++) { 132 | sample_index_map.insert(std::make_pair(file().samples().at(index).get(), index)); 133 | } 134 | 135 | // Constructs the pdta chunk and its subchunks. 136 | std::unique_ptr pdta = std::make_unique("pdta"); 137 | pdta->AddSubchunk(std::make_unique(file().presets())); 138 | pdta->AddSubchunk(std::make_unique(file().presets())); 139 | pdta->AddSubchunk(std::make_unique(file().presets())); 140 | pdta->AddSubchunk(std::make_unique(file().presets(), instrument_index_map)); 141 | pdta->AddSubchunk(std::make_unique(file().instruments())); 142 | pdta->AddSubchunk(std::make_unique(file().instruments())); 143 | pdta->AddSubchunk(std::make_unique(file().instruments())); 144 | pdta->AddSubchunk(std::make_unique(file().instruments(), sample_index_map)); 145 | pdta->AddSubchunk(std::make_unique(file().samples(), sample_index_map)); 146 | return std::move(pdta); 147 | } 148 | 149 | /// Make a chunk with a version number. 150 | std::unique_ptr SoundFontWriter::MakeVersionChunk(std::string name, SFVersionTag version) { 151 | std::vector data(4); 152 | WriteInt16L(&data[0], version.major_version); 153 | WriteInt16L(&data[2], version.minor_version); 154 | return std::make_unique(std::move(name), std::move(data)); 155 | } 156 | 157 | /// Make a chunk with a string. 158 | std::unique_ptr SoundFontWriter::MakeZSTRChunk(std::string name, std::string data) { 159 | std::vector zstr((data.size() + 1 + 1) & ~1); 160 | std::copy(data.begin(), data.end(), zstr.begin()); 161 | std::fill(std::next(zstr.begin(), data.size()), zstr.end(), 0); 162 | return std::make_unique(std::move(name), std::move(zstr)); 163 | } 164 | 165 | } // namespace sf2cute 166 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/file_writer.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont 2 File writer class header. 3 | /// 4 | /// @author gocha 5 | 6 | #ifndef SF2CUTE_FILE_WRITER_HPP_ 7 | #define SF2CUTE_FILE_WRITER_HPP_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | namespace sf2cute { 18 | 19 | class SFSample; 20 | class SFInstrumentZone; 21 | class SFInstrument; 22 | class SFPresetZone; 23 | class SFPreset; 24 | class SoundFont; 25 | 26 | class RIFFChunkInterface; 27 | 28 | /// The SoundFontWriter class represents a SoundFont writer. 29 | class SoundFontWriter { 30 | public: 31 | /// Constructs a new empty SoundFontWriter. 32 | SoundFontWriter(); 33 | 34 | /// Constructs a new SoundFontWriter using specified file. 35 | /// @param file the input SoundFont object. 36 | SoundFontWriter(const SoundFont & file); 37 | 38 | /// Constructs a new copy of specified SoundFontWriter. 39 | /// @param origin a SoundFontWriter object. 40 | SoundFontWriter(const SoundFontWriter & origin) = default; 41 | 42 | /// Copy-assigns a new value to the SoundFontWriter, replacing its current contents. 43 | /// @param origin a SoundFontWriter object. 44 | SoundFontWriter & operator=(const SoundFontWriter & origin) = default; 45 | 46 | /// Acquires the contents of specified SoundFontWriter. 47 | /// @param origin a SoundFontWriter object. 48 | SoundFontWriter(SoundFontWriter && origin) = default; 49 | 50 | /// Move-assigns a new value to the SoundFontWriter, replacing its current contents. 51 | /// @param origin a SoundFontWriter object. 52 | SoundFontWriter & operator=(SoundFontWriter && origin) = default; 53 | 54 | /// Destructs the SoundFontWriter. 55 | ~SoundFontWriter() = default; 56 | 57 | /// Returns the input SoundFont object. 58 | /// @return the input SoundFont object. 59 | const SoundFont & file() const noexcept { 60 | return *file_; 61 | } 62 | 63 | /// Sets the input SoundFont object. 64 | /// @param file the input SoundFont object. 65 | void set_file(const SoundFont & file) { 66 | file_ = &file; 67 | } 68 | 69 | /// Writes the SoundFont to a file. 70 | /// @param filename the name of the file to write to. 71 | void Write(const std::string & filename); 72 | 73 | /// Writes the SoundFont to an output stream. 74 | /// @param out the output stream to write to. 75 | void Write(std::ostream & out); 76 | 77 | /// @copydoc SoundFontWriter::Write(std::ostream &) 78 | void Write(std::ostream && out); 79 | 80 | private: 81 | /// Make an INFO chunk. 82 | /// @return the INFO chunk. 83 | std::unique_ptr MakeInfoListChunk(); 84 | 85 | /// Make a sdta chunk. 86 | /// @return the sdta chunk. 87 | std::unique_ptr MakeSdtaListChunk(); 88 | 89 | /// Make a pdta chunk. 90 | /// @return the pdta chunk. 91 | std::unique_ptr MakePdtaListChunk(); 92 | 93 | /// Make a chunk with a version number. 94 | /// @param name the name of the chunk. 95 | /// @param version the version number. 96 | static std::unique_ptr MakeVersionChunk(std::string name, SFVersionTag version); 97 | 98 | /// Make a chunk with a string. 99 | /// @param name the name of the chunk. 100 | /// @param data the data string. 101 | static std::unique_ptr MakeZSTRChunk(std::string name, std::string data); 102 | 103 | /// The input SoundFont object. 104 | const SoundFont * file_; 105 | }; 106 | 107 | } // namespace sf2cute 108 | 109 | #endif // SF2CUTE_FILE_WRITER_HPP_ 110 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/generator_item.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont 2 Generator class implementation. 3 | /// 4 | /// @author gocha 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | namespace sf2cute { 12 | 13 | /// Constructs a new SFGeneratorItem. 14 | SFGeneratorItem::SFGeneratorItem() : 15 | op_(SFGenerator(0)), 16 | amount_(0) { 17 | } 18 | 19 | /// Constructs a new SFGeneratorItem using the specified properties. 20 | SFGeneratorItem::SFGeneratorItem(SFGenerator op, GenAmountType amount) : 21 | op_(std::move(op)), 22 | amount_(std::move(amount)) { 23 | } 24 | 25 | /// Indicates a SFGenerator object is "less than" the other one. 26 | bool SFGeneratorItem::Compare(const SFGenerator & x, const SFGenerator & y) noexcept { 27 | std::array firstElements{ SFGenerator::kKeyRange, SFGenerator::kVelRange }; 28 | std::array lastElements{ SFGenerator::kSampleID, SFGenerator::kInstrument }; 29 | 30 | if (x == y) { 31 | return false; 32 | } 33 | 34 | for (const SFGenerator & first : firstElements) { 35 | if (x == first) { 36 | return true; 37 | } 38 | else if (y == first) { 39 | return false; 40 | } 41 | } 42 | 43 | for (const SFGenerator & last : lastElements) { 44 | if (x == last) { 45 | return false; 46 | } 47 | else if (y == last) { 48 | return true; 49 | } 50 | } 51 | 52 | return x < y; 53 | } 54 | 55 | } // namespace sf2cute 56 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/instrument_zone.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont 2 Instrument Zone class implementation. 3 | /// 4 | /// @author gocha 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace sf2cute { 12 | 13 | /// Constructs a new empty SFInstrumentZone. 14 | SFInstrumentZone::SFInstrumentZone() : 15 | parent_instrument_(nullptr) { 16 | } 17 | 18 | /// Constructs a new SFInstrumentZone with a sample. 19 | SFInstrumentZone::SFInstrumentZone(std::weak_ptr sample) : 20 | sample_(std::move(sample)), 21 | parent_instrument_(nullptr) { 22 | } 23 | 24 | /// Constructs a new SFInstrumentZone with a sample, using the specified generators and modulators. 25 | SFInstrumentZone::SFInstrumentZone(std::weak_ptr sample, 26 | std::vector generators, 27 | std::vector modulators) : 28 | SFZone(std::move(generators), std::move(modulators)), 29 | sample_(std::move(sample)), 30 | parent_instrument_(nullptr) { 31 | } 32 | 33 | /// Constructs a new copy of specified SFInstrumentZone. 34 | SFInstrumentZone::SFInstrumentZone(const SFInstrumentZone & origin) : 35 | SFZone(origin), 36 | sample_(origin.sample_), 37 | parent_instrument_(nullptr) { 38 | } 39 | 40 | /// Copy-assigns a new value to the SFInstrumentZone, replacing its current contents. 41 | SFInstrumentZone & SFInstrumentZone::operator=(const SFInstrumentZone & origin) { 42 | *static_cast(this) = origin; 43 | sample_ = origin.sample_; 44 | parent_instrument_ = nullptr; 45 | return *this; 46 | } 47 | 48 | /// Sets the associated sample. 49 | void SFInstrumentZone::set_sample(std::weak_ptr sample) { 50 | if (has_parent_file() && !sample.expired()) { 51 | parent_file().AddSample(sample.lock()); 52 | } 53 | sample_ = std::move(sample); 54 | } 55 | 56 | /// Returns true if the zone has a parent file. 57 | bool SFInstrumentZone::has_parent_file() const noexcept { 58 | return has_parent_instrument() && parent_instrument_->has_parent_file(); 59 | } 60 | 61 | /// Returns the parent file. 62 | SoundFont & SFInstrumentZone::parent_file() const noexcept { 63 | return parent_instrument_->parent_file(); 64 | } 65 | 66 | /// Returns the parent instrument. 67 | SFInstrument & SFInstrumentZone::parent_instrument() const noexcept { 68 | return *parent_instrument_; 69 | } 70 | 71 | /// Sets the parent instrument. 72 | void SFInstrumentZone::set_parent_instrument( 73 | SFInstrument & parent_instrument) noexcept { 74 | parent_instrument_ = &parent_instrument; 75 | } 76 | 77 | } // namespace sf2cute 78 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/modulator.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont 2 Modulator's Controller class implementation. 3 | /// 4 | /// @author gocha 5 | 6 | #include 7 | 8 | #include 9 | 10 | namespace sf2cute { 11 | 12 | /// Constructs a new SFModulator with no controller. 13 | SFModulator::SFModulator() : 14 | controller_(0), 15 | controller_palette_(SFControllerPalette(0)), 16 | direction_(SFControllerDirection(0)), 17 | polarity_(SFControllerPolarity(0)), 18 | type_(SFControllerType(0)) { 19 | } 20 | 21 | /// Constructs a new SFModulator from a pre-encoded integer. 22 | SFModulator::SFModulator(uint16_t value) : 23 | controller_(value & 0x7f), 24 | controller_palette_(SFControllerPalette((value >> 7) & 1)), 25 | direction_(SFControllerDirection((value >> 8) & 1)), 26 | polarity_(SFControllerPolarity((value >> 9) & 1)), 27 | type_(SFControllerType((value >> 10) & 0x3f)) { 28 | } 29 | 30 | /// Constructs a new SFModulator with a general controller. 31 | SFModulator::SFModulator(SFGeneralController controller, 32 | SFControllerDirection direction, 33 | SFControllerPolarity polarity, 34 | SFControllerType type) : 35 | controller_(uint8_t(controller)), 36 | controller_palette_(SFControllerPalette::kGeneralController), 37 | direction_(direction), 38 | polarity_(polarity), 39 | type_(type) { 40 | } 41 | 42 | /// Constructs a new SFModulator with a MIDI controller. 43 | SFModulator::SFModulator(SFMidiController controller, 44 | SFControllerDirection direction, 45 | SFControllerPolarity polarity, 46 | SFControllerType type) : 47 | controller_(uint8_t(controller)), 48 | controller_palette_(SFControllerPalette::kMidiController), 49 | direction_(direction), 50 | polarity_(polarity), 51 | type_(type) { 52 | } 53 | 54 | } // namespace sf2cute 55 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/modulator_item.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont 2 Modulator class implementation. 3 | /// 4 | /// @author gocha 5 | 6 | #include 7 | 8 | namespace sf2cute { 9 | 10 | /// Constructs a new SFModulatorItem. 11 | SFModulatorItem::SFModulatorItem() : 12 | key_(SFModulator(0), SFGenerator(0), SFModulator(0)), 13 | amount_(0), 14 | transform_op_(SFTransform(0)) { 15 | } 16 | 17 | /// Constructs a new SFModulatorItem using the specified controllers. 18 | SFModulatorItem::SFModulatorItem(SFModulator source_op, 19 | SFGenerator destination_op, 20 | int16_t amount, 21 | SFModulator amount_source_op, 22 | SFTransform transform_op) : 23 | key_(std::move(source_op), std::move(destination_op), std::move(amount_source_op)), 24 | amount_(amount), 25 | transform_op_(transform_op) { 26 | } 27 | 28 | } // namespace sf2cute 29 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/modulator_key.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont 2 Key members of Modulator class implementation. 3 | /// 4 | /// @author gocha 5 | 6 | #include 7 | 8 | #include 9 | 10 | namespace sf2cute { 11 | 12 | /// Constructs a new SFModulatorKey. 13 | SFModulatorKey::SFModulatorKey() : 14 | source_op_(SFModulator(0)), 15 | destination_op_(SFGenerator(0)), 16 | amount_source_op_(SFModulator(0)) { 17 | } 18 | 19 | /// Constructs a new SFModulatorKey using the specified controllers. 20 | SFModulatorKey::SFModulatorKey(SFModulator source_op, 21 | SFGenerator destination_op, 22 | SFModulator amount_source_op) : 23 | source_op_(std::move(source_op)), 24 | destination_op_(std::move(destination_op)), 25 | amount_source_op_(std::move(amount_source_op)) { 26 | } 27 | 28 | } // namespace sf2cute 29 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/preset_zone.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont 2 Preset Zone class implementation. 3 | /// 4 | /// @author gocha 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace sf2cute { 13 | 14 | /// Constructs a new empty SFPresetZone. 15 | SFPresetZone::SFPresetZone() : 16 | parent_preset_(nullptr) { 17 | } 18 | 19 | /// Constructs a new SFPresetZone with an instrument. 20 | SFPresetZone::SFPresetZone(std::weak_ptr instrument) : 21 | instrument_(std::move(instrument)), 22 | parent_preset_(nullptr) { 23 | } 24 | 25 | /// Constructs a new SFPresetZone with an instrument, using the specified generators and modulators. 26 | SFPresetZone::SFPresetZone(std::weak_ptr instrument, 27 | std::vector generators, 28 | std::vector modulators) : 29 | SFZone(std::move(generators), std::move(modulators)), 30 | instrument_(std::move(instrument)), 31 | parent_preset_(nullptr) { 32 | } 33 | 34 | /// Constructs a new copy of specified SFPresetZone. 35 | SFPresetZone::SFPresetZone(const SFPresetZone & origin) : 36 | SFZone(origin), 37 | instrument_(origin.instrument_), 38 | parent_preset_(nullptr) { 39 | } 40 | 41 | /// Copy-assigns a new value to the SFPresetZone, replacing its current contents. 42 | SFPresetZone & SFPresetZone::operator=(const SFPresetZone & origin) { 43 | *static_cast(this) = origin; 44 | instrument_ = origin.instrument_; 45 | parent_preset_ = nullptr; 46 | return *this; 47 | } 48 | 49 | /// Sets the associated instrument. 50 | void SFPresetZone::set_instrument(std::weak_ptr instrument) { 51 | if (has_parent_file() && !instrument.expired()) { 52 | parent_file().AddInstrument(instrument.lock()); 53 | } 54 | instrument_ = std::move(instrument); 55 | } 56 | 57 | /// Returns true if the zone has a parent file. 58 | bool SFPresetZone::has_parent_file() const noexcept { 59 | return has_parent_preset() && parent_preset_->has_parent_file(); 60 | } 61 | 62 | /// Returns the parent file. 63 | SoundFont & SFPresetZone::parent_file() const noexcept { 64 | return parent_preset_->parent_file(); 65 | } 66 | 67 | /// Returns the parent preset. 68 | SFPreset & SFPresetZone::parent_preset() const noexcept { 69 | return *parent_preset_; 70 | } 71 | 72 | /// Sets the parent preset. 73 | void SFPresetZone::set_parent_preset(SFPreset & parent_preset) noexcept { 74 | parent_preset_ = &parent_preset; 75 | } 76 | 77 | } // namespace sf2cute 78 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/riff_ibag_chunk.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont "ibag" RIFF chunk implementation 3 | /// 4 | /// @author gocha 5 | 6 | #include "riff_ibag_chunk.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include "byteio.hpp" 19 | 20 | namespace sf2cute { 21 | 22 | /// Constructs a new empty SFRIFFIbagChunk. 23 | SFRIFFIbagChunk::SFRIFFIbagChunk() : 24 | size_(0), 25 | instruments_(nullptr) { 26 | } 27 | 28 | /// Constructs a new SFRIFFIbagChunk using the specified instruments. 29 | SFRIFFIbagChunk::SFRIFFIbagChunk( 30 | const std::vector> & instruments) : 31 | instruments_(&instruments) { 32 | size_ = kItemSize * NumItems(); 33 | } 34 | 35 | /// Writes this chunk to the specified output stream. 36 | void SFRIFFIbagChunk::Write(std::ostream & out) const { 37 | // Save exception bits of output stream. 38 | const std::ios_base::iostate old_exception_bits = out.exceptions(); 39 | // Set exception bits to get output error as an exception. 40 | out.exceptions(std::ios::badbit | std::ios::failbit); 41 | 42 | try { 43 | // Write the chunk header. 44 | RIFFChunk::WriteHeader(out, name(), size_); 45 | 46 | // Instruments: 47 | size_t generator_index = 0; 48 | size_t modulator_index = 0; 49 | for (const auto & instrument : instruments()) { 50 | // Global instrument zone: 51 | if (instrument->has_global_zone()) { 52 | // Write the global zone. 53 | WriteItem(out, uint16_t(generator_index), uint16_t(modulator_index)); 54 | 55 | // Increment the generator index and the modulator index. 56 | generator_index += instrument->global_zone().generators().size(); 57 | modulator_index += instrument->global_zone().modulators().size(); 58 | } 59 | 60 | // Instrument zones: 61 | for (const auto & zone : instrument->zones()) { 62 | // Write the instrument zone. 63 | WriteItem(out, uint16_t(generator_index), uint16_t(modulator_index)); 64 | 65 | // Increment the generator index and the modulator index. 66 | generator_index += (zone->has_sample() ? 1 : 0) + zone->generators().size(); 67 | modulator_index += zone->modulators().size(); 68 | } 69 | } 70 | 71 | // Write the last terminator item. 72 | WriteItem(out, uint16_t(generator_index), uint16_t(modulator_index)); 73 | 74 | // Write a padding byte if necessary. 75 | if (size_ % 2 != 0) { 76 | InsertInt8(out, 0); 77 | } 78 | } 79 | catch (const std::exception &) { 80 | // Recover exception bits of output stream. 81 | out.exceptions(old_exception_bits); 82 | 83 | // Rethrow the exception. 84 | throw; 85 | } 86 | } 87 | 88 | /// Returns the number of instrument zone items. 89 | uint16_t SFRIFFIbagChunk::NumItems() const { 90 | size_t num_zones = 1; // 1 = terminator 91 | for (const auto & instrument : instruments()) { 92 | // Count the global zone. 93 | if (instrument->has_global_zone()) { 94 | num_zones++; 95 | } 96 | 97 | // Count the instrument zones. 98 | num_zones += instrument->zones().size(); 99 | 100 | // Check the range of the number of zones. 101 | if (num_zones > UINT16_MAX) { 102 | throw std::length_error("Too many instrument zones."); 103 | } 104 | } 105 | return static_cast(num_zones); 106 | } 107 | 108 | /// Writes an item of ibag chunk. 109 | std::ostream & SFRIFFIbagChunk::WriteItem(std::ostream & out, 110 | uint16_t generator_index, 111 | uint16_t modulator_index) { 112 | // struct sfInstBag: 113 | // uint16_t wInstGenNdx; 114 | InsertInt16L(out, generator_index); 115 | 116 | // uint16_t wInstModNdx; 117 | InsertInt16L(out, modulator_index); 118 | 119 | return out; 120 | } 121 | 122 | } // namespace sf2cute 123 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/riff_ibag_chunk.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont "ibag" RIFF chunk header 3 | /// 4 | /// @author gocha 5 | 6 | #ifndef SF2CUTE_RIFF_IBAG_CHUNK_HPP_ 7 | #define SF2CUTE_RIFF_IBAG_CHUNK_HPP_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "riff.hpp" 16 | 17 | namespace sf2cute { 18 | 19 | class SFInstrument; 20 | 21 | /// The SFRIFFIbagChunk class represents a SoundFont 2 "ibag" chunk. 22 | class SFRIFFIbagChunk : public RIFFChunkInterface { 23 | public: 24 | /// Unsigned integer type for the chunk size. 25 | using size_type = RIFFChunkInterface::size_type; 26 | 27 | /// The item size of ibag chunk, in terms of bytes. 28 | static constexpr size_type kItemSize = 4; 29 | 30 | /// Constructs a new empty SFRIFFIbagChunk. 31 | SFRIFFIbagChunk(); 32 | 33 | /// Constructs a new SFRIFFIbagChunk using the specified instruments. 34 | /// @param instruments The instruments of the chunk. 35 | /// @throws std::length_error Too many instrument zones. 36 | SFRIFFIbagChunk( 37 | const std::vector> & instruments); 38 | 39 | /// Constructs a new copy of specified SFRIFFIbagChunk. 40 | /// @param origin a SFRIFFIbagChunk object. 41 | SFRIFFIbagChunk(const SFRIFFIbagChunk & origin) = default; 42 | 43 | /// Copy-assigns a new value to the SFRIFFIbagChunk, replacing its current contents. 44 | /// @param origin a SFRIFFIbagChunk object. 45 | SFRIFFIbagChunk & operator=(const SFRIFFIbagChunk & origin) = default; 46 | 47 | /// Acquires the contents of specified SFRIFFIbagChunk. 48 | /// @param origin a SFRIFFIbagChunk object. 49 | SFRIFFIbagChunk(SFRIFFIbagChunk && origin) = default; 50 | 51 | /// Move-assigns a new value to the SFRIFFIbagChunk, replacing its current contents. 52 | /// @param origin a SFRIFFIbagChunk object. 53 | SFRIFFIbagChunk & operator=(SFRIFFIbagChunk && origin) = default; 54 | 55 | /// Destructs the SFRIFFIbagChunk. 56 | virtual ~SFRIFFIbagChunk() = default; 57 | 58 | /// @copydoc RIFFChunkInterface::name() 59 | virtual std::string name() const override { 60 | return "ibag"; 61 | } 62 | 63 | /// Returns the instruments of this chunk. 64 | /// @return the instruments of this chunk. 65 | const std::vector> & 66 | instruments() const { 67 | return *instruments_; 68 | } 69 | 70 | /// Sets the instruments of this chunk. 71 | /// @param instruments the instruments of this chunk. 72 | /// @throws std::length_error Too many instrument zones. 73 | void set_instruments( 74 | const std::vector> & instruments) { 75 | instruments_ = &instruments; 76 | size_ = kItemSize * NumItems(); 77 | } 78 | 79 | /// Returns the whole length of this chunk. 80 | /// @return the length of this chunk including a chunk header, in terms of bytes. 81 | virtual size_type size() const noexcept override { 82 | return 8 + size_; 83 | } 84 | 85 | /// Writes this chunk to the specified output stream. 86 | /// @param out the output stream. 87 | /// @throws std::length_error The chunk size exceeds the maximum. 88 | /// @throws std::ios_base::failure An I/O error occurred. 89 | virtual void Write(std::ostream & out) const override; 90 | 91 | private: 92 | /// Returns the number of instrument zone items. 93 | /// @return the number of instrument zone items, including the terminator item. 94 | /// @throws std::length_error Too many instrument zones. 95 | uint16_t NumItems() const; 96 | 97 | /// Writes an item of ibag chunk. 98 | /// @param out the output stream. 99 | /// @param generator_index the generator index starting from 0. 100 | /// @param modulator_index the modulator index starting from 0. 101 | /// @return the output stream. 102 | /// @throws std::ios_base::failure An I/O error occurred. 103 | static std::ostream & WriteItem(std::ostream & out, 104 | uint16_t generator_index, 105 | uint16_t modulator_index); 106 | 107 | /// The size of the chunk (excluding header). 108 | size_type size_; 109 | 110 | /// The instruments of the chunk. 111 | const std::vector> * instruments_; 112 | }; 113 | 114 | } // namespace sf2cute 115 | 116 | #endif // SF2CUTE_RIFF_IBAG_CHUNK_HPP_ 117 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/riff_igen_chunk.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont "igen" RIFF chunk implementation 3 | /// 4 | /// @author gocha 5 | 6 | #include "riff_igen_chunk.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | #include "byteio.hpp" 21 | 22 | namespace sf2cute { 23 | 24 | /// Constructs a new empty SFRIFFIgenChunk. 25 | SFRIFFIgenChunk::SFRIFFIgenChunk() : 26 | size_(0), 27 | instruments_(nullptr), 28 | sample_index_map_() { 29 | } 30 | 31 | /// Constructs a new SFRIFFIgenChunk using the specified instruments. 32 | SFRIFFIgenChunk::SFRIFFIgenChunk( 33 | const std::vector> & instruments, 34 | std::unordered_map sample_index_map) : 35 | instruments_(&instruments), 36 | sample_index_map_(std::move(sample_index_map)) { 37 | size_ = kItemSize * NumItems(); 38 | } 39 | 40 | /// Writes this chunk to the specified output stream. 41 | void SFRIFFIgenChunk::Write(std::ostream & out) const { 42 | // Save exception bits of output stream. 43 | const std::ios_base::iostate old_exception_bits = out.exceptions(); 44 | // Set exception bits to get output error as an exception. 45 | out.exceptions(std::ios::badbit | std::ios::failbit); 46 | 47 | try { 48 | // Write the chunk header. 49 | RIFFChunk::WriteHeader(out, name(), size_); 50 | 51 | // Instruments: 52 | for (const auto & instrument : instruments()) { 53 | // Global zone: 54 | if (instrument->has_global_zone()) { 55 | // Check the sample for the global zone. 56 | if (instrument->global_zone().has_sample()) { 57 | // Throw exception if the global zone has a link to a sample. 58 | throw std::invalid_argument("Global instrument zone cannot have a link to a sample."); 59 | } 60 | 61 | // Write all the generators in the global zone. 62 | for (const auto & generator : SortGenerators(instrument->global_zone().generators())) { 63 | WriteItem(out, generator->op(), generator->amount()); 64 | } 65 | } 66 | 67 | // Instrument zones: 68 | for (const auto & zone : instrument->zones()) { 69 | // Write all the generators in the instrument zone. 70 | for (const auto & generator : SortGenerators(zone->generators())) { 71 | WriteItem(out, generator->op(), generator->amount()); 72 | } 73 | 74 | // Check the sample for the zone. 75 | if (zone->has_sample()) { 76 | // Find the index number for the sample. 77 | const auto & sample = zone->sample(); 78 | if (sample_index_map().count(sample.get()) != 0) { 79 | // Write the sampleID generator. 80 | GenAmountType sample_index(sample_index_map().at(sample.get())); 81 | WriteItem(out, SFGenerator::kSampleID, sample_index); 82 | } 83 | else { 84 | // Throw exception if the sample could not be found in the index map. 85 | throw std::out_of_range("Instrument zone points to an unknown sample."); 86 | } 87 | } 88 | else { 89 | // Throw exception if the instrument zone does not have a link to a sample. 90 | throw std::invalid_argument("Instrument zone must have a link to a sample."); 91 | } 92 | } 93 | } 94 | 95 | // Write the last terminator item. 96 | WriteItem(out, SFGenerator(0), GenAmountType(0)); 97 | 98 | // Write a padding byte if necessary. 99 | if (size_ % 2 != 0) { 100 | InsertInt8(out, 0); 101 | } 102 | } 103 | catch (const std::exception &) { 104 | // Recover exception bits of output stream. 105 | out.exceptions(old_exception_bits); 106 | 107 | // Rethrow the exception. 108 | throw; 109 | } 110 | } 111 | 112 | /// Returns the number of instrument generator items. 113 | uint16_t SFRIFFIgenChunk::NumItems() const { 114 | size_t num_generators = 1; // 1 = terminator 115 | for (const auto & instrument : instruments()) { 116 | // Count the generators in the global zone. 117 | if (instrument->has_global_zone()) { 118 | num_generators += instrument->global_zone().generators().size(); 119 | if (num_generators > UINT16_MAX) { 120 | throw std::length_error("Too many instrument generators."); 121 | } 122 | } 123 | 124 | // Count the generators in the instrument zones. 125 | for (const auto & zone : instrument->zones()) { 126 | num_generators += (zone->has_sample() ? 1 : 0) + zone->generators().size(); 127 | if (num_generators > UINT16_MAX) { 128 | throw std::length_error("Too many instrument generators."); 129 | } 130 | } 131 | } 132 | return static_cast(num_generators); 133 | } 134 | 135 | /// Writes an item of igen chunk. 136 | std::ostream & SFRIFFIgenChunk::WriteItem(std::ostream & out, 137 | SFGenerator op, 138 | GenAmountType amount) { 139 | // struct sfInstGenList: 140 | // SFGenerator sfGenOper; 141 | InsertInt16L(out, static_cast(op)); 142 | 143 | // GenAmountType genAmount; 144 | InsertInt16L(out, amount.value); 145 | 146 | return out; 147 | } 148 | 149 | /// Sort generators based on the ordering requirements of the generator chunk. 150 | std::vector SFRIFFIgenChunk::SortGenerators( 151 | const std::vector> & generators) { 152 | // Make a copy of generator pointers. 153 | std::vector sorted_generators; 154 | sorted_generators.reserve(generators.size()); 155 | for (const auto & generator : generators) { 156 | sorted_generators.push_back(generator.get()); 157 | } 158 | 159 | // Sort the generator pointers. 160 | std::sort(sorted_generators.begin(), sorted_generators.end(), 161 | [](const SFGeneratorItem * x, const SFGeneratorItem * y) { 162 | return SFGeneratorItem::Compare(x->op(), y->op()); 163 | }); 164 | 165 | // Return the sorted pointers. 166 | return sorted_generators; 167 | } 168 | 169 | } // namespace sf2cute 170 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/riff_igen_chunk.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont "igen" RIFF chunk header 3 | /// 4 | /// @author gocha 5 | 6 | #ifndef SF2CUTE_RIFF_IGEN_CHUNK_HPP_ 7 | #define SF2CUTE_RIFF_IGEN_CHUNK_HPP_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include "riff.hpp" 19 | 20 | namespace sf2cute { 21 | 22 | class SFInstrument; 23 | class SFSample; 24 | class SFGeneratorItem; 25 | 26 | /// The SFRIFFIgenChunk class represents a SoundFont 2 "igen" chunk. 27 | class SFRIFFIgenChunk : public RIFFChunkInterface { 28 | public: 29 | /// Unsigned integer type for the chunk size. 30 | using size_type = RIFFChunkInterface::size_type; 31 | 32 | /// The item size of igen chunk, in terms of bytes. 33 | static constexpr size_type kItemSize = 4; 34 | 35 | /// Constructs a new empty SFRIFFIgenChunk. 36 | SFRIFFIgenChunk(); 37 | 38 | /// Constructs a new SFRIFFIgenChunk using the specified instruments. 39 | /// @param instruments The instruments of the chunk. 40 | /// @param sample_index_map the map containing the samples as keys and their indices as map values. 41 | /// @throws std::length_error Too many instrument generators. 42 | SFRIFFIgenChunk( 43 | const std::vector> & instruments, 44 | std::unordered_map sample_index_map); 45 | 46 | /// Constructs a new copy of specified SFRIFFIgenChunk. 47 | /// @param origin a SFRIFFIgenChunk object. 48 | SFRIFFIgenChunk(const SFRIFFIgenChunk & origin) = default; 49 | 50 | /// Copy-assigns a new value to the SFRIFFIgenChunk, replacing its current contents. 51 | /// @param origin a SFRIFFIgenChunk object. 52 | SFRIFFIgenChunk & operator=(const SFRIFFIgenChunk & origin) = default; 53 | 54 | /// Acquires the contents of specified SFRIFFIgenChunk. 55 | /// @param origin a SFRIFFIgenChunk object. 56 | SFRIFFIgenChunk(SFRIFFIgenChunk && origin) = default; 57 | 58 | /// Move-assigns a new value to the SFRIFFIgenChunk, replacing its current contents. 59 | /// @param origin a SFRIFFIgenChunk object. 60 | SFRIFFIgenChunk & operator=(SFRIFFIgenChunk && origin) = default; 61 | 62 | /// Destructs the SFRIFFIgenChunk. 63 | virtual ~SFRIFFIgenChunk() = default; 64 | 65 | /// @copydoc RIFFChunkInterface::name() 66 | virtual std::string name() const override { 67 | return "igen"; 68 | } 69 | 70 | /// Returns the instruments of this chunk. 71 | /// @return the instruments of this chunk. 72 | const std::vector> & 73 | instruments() const { 74 | return *instruments_; 75 | } 76 | 77 | /// Sets the instruments of this chunk. 78 | /// @param instruments the instruments of this chunk. 79 | /// @throws std::length_error Too many instrument generators. 80 | void set_instruments( 81 | const std::vector> & instruments) { 82 | instruments_ = &instruments; 83 | size_ = kItemSize * NumItems(); 84 | } 85 | 86 | /// Returns the map containing the samples as keys and their indices as map values. 87 | /// @return the map containing the samples as keys and their indices as map values. 88 | const std::unordered_map & 89 | sample_index_map() const { 90 | return sample_index_map_; 91 | } 92 | 93 | /// Sets the map containing the samples as keys and their indices as map values. 94 | /// @param sample_index_map the map containing the samples as keys and their indices as map values. 95 | void set_sample_index_map( 96 | std::unordered_map sample_index_map) { 97 | sample_index_map_ = std::move(sample_index_map); 98 | } 99 | 100 | /// Returns the whole length of this chunk. 101 | /// @return the length of this chunk including a chunk header, in terms of bytes. 102 | virtual size_type size() const noexcept override { 103 | return 8 + size_; 104 | } 105 | 106 | /// Writes this chunk to the specified output stream. 107 | /// @param out the output stream. 108 | /// @throws std::invalid_argument Global instrument zone has a sample. 109 | /// @throws std::invalid_argument Instrument zone does not have a sample. 110 | /// @throws std::length_error The chunk size exceeds the maximum. 111 | /// @throws std::out_of_range Instrument zone points to an unknown sample. 112 | /// @throws std::ios_base::failure An I/O error occurred. 113 | virtual void Write(std::ostream & out) const override; 114 | 115 | private: 116 | /// Returns the number of instrument generator items. 117 | /// @return the number of instrument generator items, including the terminator item. 118 | /// @throws std::length_error Too many instrument generators. 119 | uint16_t NumItems() const; 120 | 121 | /// Writes an item of igen chunk. 122 | /// @param out the output stream. 123 | /// @param op the type of the generator. 124 | /// @param amount the amount of the generator. 125 | /// @return the output stream. 126 | /// @throws std::ios_base::failure An I/O error occurred. 127 | static std::ostream & WriteItem(std::ostream & out, 128 | SFGenerator op, 129 | GenAmountType amount); 130 | 131 | /// Sort generators based on the ordering requirements of the generator chunk. 132 | /// @param generators the generators. 133 | /// @return the sorted collection of the generator pointers. 134 | static std::vector SortGenerators( 135 | const std::vector> & generators); 136 | 137 | /// The size of the chunk (excluding header). 138 | size_type size_; 139 | 140 | /// The instruments of the chunk. 141 | const std::vector> * instruments_; 142 | 143 | /// The map containing the samples as keys and their indices as map values. 144 | std::unordered_map sample_index_map_; 145 | }; 146 | 147 | } // namespace sf2cute 148 | 149 | #endif // SF2CUTE_RIFF_IGEN_CHUNK_HPP_ 150 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/riff_imod_chunk.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont "imod" RIFF chunk implementation 3 | /// 4 | /// @author gocha 5 | 6 | #include "riff_imod_chunk.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include "byteio.hpp" 19 | 20 | namespace sf2cute { 21 | 22 | /// Constructs a new empty SFRIFFImodChunk. 23 | SFRIFFImodChunk::SFRIFFImodChunk() : 24 | size_(0), 25 | instruments_(nullptr) { 26 | } 27 | 28 | /// Constructs a new SFRIFFImodChunk using the specified instruments. 29 | SFRIFFImodChunk::SFRIFFImodChunk( 30 | const std::vector> & instruments) : 31 | instruments_(&instruments) { 32 | size_ = kItemSize * NumItems(); 33 | } 34 | 35 | /// Writes this chunk to the specified output stream. 36 | void SFRIFFImodChunk::Write(std::ostream & out) const { 37 | // Save exception bits of output stream. 38 | const std::ios_base::iostate old_exception_bits = out.exceptions(); 39 | // Set exception bits to get output error as an exception. 40 | out.exceptions(std::ios::badbit | std::ios::failbit); 41 | 42 | try { 43 | // Write the chunk header. 44 | RIFFChunk::WriteHeader(out, name(), size_); 45 | 46 | // Instruments: 47 | for (const auto & instrument : instruments()) { 48 | // Global zone: 49 | if (instrument->has_global_zone()) { 50 | // Write all the modulators in the global zone. 51 | for (const auto & modulator : instrument->global_zone().modulators()) { 52 | WriteItem(out, modulator->source_op(), modulator->destination_op(), 53 | modulator->amount(), modulator->amount_source_op(), modulator->transform_op()); 54 | } 55 | } 56 | 57 | // Instrument zones: 58 | for (const auto & zone : instrument->zones()) { 59 | // Write all the modulators in the instrument zone. 60 | for (const auto & modulator : zone->modulators()) { 61 | WriteItem(out, modulator->source_op(), modulator->destination_op(), 62 | modulator->amount(), modulator->amount_source_op(), modulator->transform_op()); 63 | } 64 | } 65 | } 66 | 67 | // Write the last terminator item. 68 | WriteItem(out, SFModulator(0), SFGenerator(0), 0, SFModulator(0), SFTransform(0)); 69 | 70 | // Write a padding byte if necessary. 71 | if (size_ % 2 != 0) { 72 | InsertInt8(out, 0); 73 | } 74 | } 75 | catch (const std::exception &) { 76 | // Recover exception bits of output stream. 77 | out.exceptions(old_exception_bits); 78 | 79 | // Rethrow the exception. 80 | throw; 81 | } 82 | } 83 | 84 | /// Returns the number of instrument modulator items. 85 | uint16_t SFRIFFImodChunk::NumItems() const { 86 | size_t num_modulators = 1; // 1 = terminator 87 | for (const auto & instrument : instruments()) { 88 | // Count the modulators in the global zone. 89 | if (instrument->has_global_zone()) { 90 | num_modulators += instrument->global_zone().modulators().size(); 91 | if (num_modulators > UINT16_MAX) { 92 | throw std::length_error("Too many instrument modulators."); 93 | } 94 | } 95 | 96 | // Count the modulators in the instrument zones. 97 | for (const auto & zone : instrument->zones()) { 98 | num_modulators += zone->modulators().size(); 99 | if (num_modulators > UINT16_MAX) { 100 | throw std::length_error("Too many instrument modulators."); 101 | } 102 | } 103 | } 104 | return static_cast(num_modulators); 105 | } 106 | 107 | /// Writes an item of imod chunk. 108 | std::ostream & SFRIFFImodChunk::WriteItem(std::ostream & out, 109 | SFModulator source_op, 110 | SFGenerator destination_op, 111 | int16_t amount, 112 | SFModulator amount_source_op, 113 | SFTransform transform_op) { 114 | // struct sfInstModList: 115 | // SFModulator sfModSrcOper; 116 | InsertInt16L(out, uint16_t(source_op)); 117 | 118 | // SFGenerator sfModDestOper; 119 | InsertInt16L(out, uint16_t(destination_op)); 120 | 121 | // int16_t modAmount; 122 | InsertInt16L(out, amount); 123 | 124 | // SFModulator sfModAmtSrcOper; 125 | InsertInt16L(out, uint16_t(amount_source_op)); 126 | 127 | // SFTransform sfModTransOper; 128 | InsertInt16L(out, uint16_t(transform_op)); 129 | 130 | return out; 131 | } 132 | 133 | } // namespace sf2cute 134 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/riff_imod_chunk.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont "imod" RIFF chunk header 3 | /// 4 | /// @author gocha 5 | 6 | #ifndef SF2CUTE_RIFF_IMOD_CHUNK_HPP_ 7 | #define SF2CUTE_RIFF_IMOD_CHUNK_HPP_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include "riff.hpp" 19 | 20 | namespace sf2cute { 21 | 22 | class SFInstrument; 23 | 24 | /// The SFRIFFImodChunk class represents a SoundFont 2 "imod" chunk. 25 | class SFRIFFImodChunk : public RIFFChunkInterface { 26 | public: 27 | /// Unsigned integer type for the chunk size. 28 | using size_type = RIFFChunkInterface::size_type; 29 | 30 | /// The item size of imod chunk, in terms of bytes. 31 | static constexpr size_type kItemSize = 10; 32 | 33 | /// Constructs a new empty SFRIFFImodChunk. 34 | SFRIFFImodChunk(); 35 | 36 | /// Constructs a new SFRIFFImodChunk using the specified instruments. 37 | /// @param instruments The instruments of the chunk. 38 | /// @throws std::length_error Too many instrument modulators. 39 | SFRIFFImodChunk( 40 | const std::vector> & instruments); 41 | 42 | /// Constructs a new copy of specified SFRIFFImodChunk. 43 | /// @param origin a SFRIFFImodChunk object. 44 | SFRIFFImodChunk(const SFRIFFImodChunk & origin) = default; 45 | 46 | /// Copy-assigns a new value to the SFRIFFImodChunk, replacing its current contents. 47 | /// @param origin a SFRIFFImodChunk object. 48 | SFRIFFImodChunk & operator=(const SFRIFFImodChunk & origin) = default; 49 | 50 | /// Acquires the contents of specified SFRIFFImodChunk. 51 | /// @param origin a SFRIFFImodChunk object. 52 | SFRIFFImodChunk(SFRIFFImodChunk && origin) = default; 53 | 54 | /// Move-assigns a new value to the SFRIFFImodChunk, replacing its current contents. 55 | /// @param origin a SFRIFFImodChunk object. 56 | SFRIFFImodChunk & operator=(SFRIFFImodChunk && origin) = default; 57 | 58 | /// Destructs the SFRIFFImodChunk. 59 | virtual ~SFRIFFImodChunk() = default; 60 | 61 | /// @copydoc RIFFChunkInterface::name() 62 | virtual std::string name() const override { 63 | return "imod"; 64 | } 65 | 66 | /// Returns the instruments of this chunk. 67 | /// @return the instruments of this chunk. 68 | const std::vector> & 69 | instruments() const { 70 | return *instruments_; 71 | } 72 | 73 | /// Sets the instruments of this chunk. 74 | /// @param instruments the instruments of this chunk. 75 | /// @throws std::length_error Too many instrument modulators. 76 | void set_instruments( 77 | const std::vector> & instruments) { 78 | instruments_ = &instruments; 79 | size_ = kItemSize * NumItems(); 80 | } 81 | 82 | /// Returns the whole length of this chunk. 83 | /// @return the length of this chunk including a chunk header, in terms of bytes. 84 | virtual size_type size() const noexcept override { 85 | return 8 + size_; 86 | } 87 | 88 | /// Writes this chunk to the specified output stream. 89 | /// @param out the output stream. 90 | /// @throws std::length_error The chunk size exceeds the maximum. 91 | /// @throws std::ios_base::failure An I/O error occurred. 92 | virtual void Write(std::ostream & out) const override; 93 | 94 | private: 95 | /// Returns the number of instrument modulator items. 96 | /// @return the number of instrument modulator items, including the terminator item. 97 | /// @throws std::length_error Too many instrument modulators. 98 | uint16_t NumItems() const; 99 | 100 | /// Writes an item of imod chunk. 101 | /// @param out the output stream. 102 | /// @param source_op the source of data for the modulator. 103 | /// @param destination_op the destination of the modulator. 104 | /// @param amount the degree to which the source modulates the destination. 105 | /// @param amount_source_op the modulation source to be applied to the modulation amount. 106 | /// @param transform_op the transform type to be applied to the modulation source. 107 | /// @return the output stream. 108 | /// @throws std::ios_base::failure An I/O error occurred. 109 | static std::ostream & WriteItem(std::ostream & out, 110 | SFModulator source_op, 111 | SFGenerator destination_op, 112 | int16_t amount, 113 | SFModulator amount_source_op, 114 | SFTransform transform_op); 115 | 116 | /// The size of the chunk (excluding header). 117 | size_type size_; 118 | 119 | /// The instruments of the chunk. 120 | const std::vector> * instruments_; 121 | }; 122 | 123 | } // namespace sf2cute 124 | 125 | #endif // SF2CUTE_RIFF_IMOD_CHUNK_HPP_ 126 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/riff_inst_chunk.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont "inst" RIFF chunk implementation 3 | /// 4 | /// @author gocha 5 | 6 | #include "riff_inst_chunk.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include "byteio.hpp" 19 | 20 | namespace sf2cute { 21 | 22 | /// Constructs a new empty SFRIFFInstChunk. 23 | SFRIFFInstChunk::SFRIFFInstChunk() : 24 | size_(0), 25 | instruments_(nullptr) { 26 | } 27 | 28 | /// Constructs a new SFRIFFInstChunk using the specified instruments. 29 | SFRIFFInstChunk::SFRIFFInstChunk( 30 | const std::vector> & instruments) : 31 | instruments_(&instruments) { 32 | size_ = kItemSize * NumItems(); 33 | } 34 | 35 | /// Writes this chunk to the specified output stream. 36 | void SFRIFFInstChunk::Write(std::ostream & out) const { 37 | // Save exception bits of output stream. 38 | const std::ios_base::iostate old_exception_bits = out.exceptions(); 39 | // Set exception bits to get output error as an exception. 40 | out.exceptions(std::ios::badbit | std::ios::failbit); 41 | 42 | try { 43 | // Write the chunk header. 44 | RIFFChunk::WriteHeader(out, name(), size_); 45 | 46 | // Instruments: 47 | size_t inst_bag_index = 0; 48 | for (const auto & instrument : instruments()) { 49 | // Write the instrument header. 50 | WriteItem(out, instrument->name(), uint16_t(inst_bag_index)); 51 | 52 | // Count the number of instrument zones. 53 | size_t num_zones = 0; 54 | if (instrument->has_global_zone()) { 55 | num_zones++; 56 | } 57 | num_zones += instrument->zones().size(); 58 | 59 | // Increment the instrument bag index. 60 | inst_bag_index += num_zones; 61 | } 62 | 63 | // Write the last terminator item. 64 | WriteItem(out, "EOI", uint16_t(inst_bag_index)); 65 | 66 | // Write a padding byte if necessary. 67 | if (size_ % 2 != 0) { 68 | InsertInt8(out, 0); 69 | } 70 | } 71 | catch (const std::exception &) { 72 | // Recover exception bits of output stream. 73 | out.exceptions(old_exception_bits); 74 | 75 | // Rethrow the exception. 76 | throw; 77 | } 78 | } 79 | 80 | /// Returns the number of instrument items. 81 | uint16_t SFRIFFInstChunk::NumItems() const { 82 | size_t num_instrument_items = instruments().size() + 1; 83 | if (num_instrument_items > UINT16_MAX) { 84 | throw std::length_error("Too many instruments."); 85 | } 86 | return static_cast(num_instrument_items); 87 | } 88 | 89 | /// Writes an item of inst chunk. 90 | std::ostream & SFRIFFInstChunk::WriteItem(std::ostream & out, 91 | const std::string & name, 92 | uint16_t inst_bag_index) { 93 | // struct sfInst: 94 | // char achInstName[20]; 95 | std::string instrument_name(name.substr(0, SFInstrument::kMaxNameLength)); 96 | out.write(instrument_name.data(), instrument_name.size()); 97 | for (std::string::size_type i = 0; i < SFInstrument::kMaxNameLength + 1 - instrument_name.size(); i++) { 98 | out.put(0); 99 | } 100 | 101 | // uint16_t wInstBagNdx; 102 | InsertInt16L(out, inst_bag_index); 103 | 104 | return out; 105 | } 106 | 107 | } // namespace sf2cute 108 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/riff_inst_chunk.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont "inst" RIFF chunk header 3 | /// 4 | /// @author gocha 5 | 6 | #ifndef SF2CUTE_RIFF_INST_CHUNK_HPP_ 7 | #define SF2CUTE_RIFF_INST_CHUNK_HPP_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "riff.hpp" 16 | 17 | namespace sf2cute { 18 | 19 | class SFInstrument; 20 | 21 | /// The SFRIFFInstChunk class represents a SoundFont 2 "inst" chunk. 22 | class SFRIFFInstChunk : public RIFFChunkInterface { 23 | public: 24 | /// Unsigned integer type for the chunk size. 25 | using size_type = RIFFChunkInterface::size_type; 26 | 27 | /// The item size of inst chunk, in terms of bytes. 28 | static constexpr size_type kItemSize = 22; 29 | 30 | /// Constructs a new empty SFRIFFInstChunk. 31 | SFRIFFInstChunk(); 32 | 33 | /// Constructs a new SFRIFFInstChunk using the specified instruments. 34 | /// @param instruments The instruments of the chunk. 35 | /// @throws std::length_error Too many instruments. 36 | SFRIFFInstChunk( 37 | const std::vector> & instruments); 38 | 39 | /// Constructs a new copy of specified SFRIFFInstChunk. 40 | /// @param origin a SFRIFFInstChunk object. 41 | SFRIFFInstChunk(const SFRIFFInstChunk & origin) = default; 42 | 43 | /// Copy-assigns a new value to the SFRIFFInstChunk, replacing its current contents. 44 | /// @param origin a SFRIFFInstChunk object. 45 | SFRIFFInstChunk & operator=(const SFRIFFInstChunk & origin) = default; 46 | 47 | /// Acquires the contents of specified SFRIFFInstChunk. 48 | /// @param origin a SFRIFFInstChunk object. 49 | SFRIFFInstChunk(SFRIFFInstChunk && origin) = default; 50 | 51 | /// Move-assigns a new value to the SFRIFFInstChunk, replacing its current contents. 52 | /// @param origin a SFRIFFInstChunk object. 53 | SFRIFFInstChunk & operator=(SFRIFFInstChunk && origin) = default; 54 | 55 | /// Destructs the SFRIFFInstChunk. 56 | virtual ~SFRIFFInstChunk() = default; 57 | 58 | /// @copydoc RIFFChunkInterface::name() 59 | virtual std::string name() const override { 60 | return "inst"; 61 | } 62 | 63 | /// Returns the instruments of this chunk. 64 | /// @return the instruments of this chunk. 65 | const std::vector> & 66 | instruments() const { 67 | return *instruments_; 68 | } 69 | 70 | /// Sets the instruments of this chunk. 71 | /// @param instruments the instruments of this chunk. 72 | /// @throws std::length_error Too many instruments. 73 | void set_instruments( 74 | const std::vector> & instruments) { 75 | instruments_ = &instruments; 76 | size_ = kItemSize * NumItems(); 77 | } 78 | 79 | /// Returns the whole length of this chunk. 80 | /// @return the length of this chunk including a chunk header, in terms of bytes. 81 | virtual size_type size() const noexcept override { 82 | return 8 + size_; 83 | } 84 | 85 | /// Writes this chunk to the specified output stream. 86 | /// @param out the output stream. 87 | /// @throws std::length_error The chunk size exceeds the maximum. 88 | /// @throws std::ios_base::failure An I/O error occurred. 89 | virtual void Write(std::ostream & out) const override; 90 | 91 | private: 92 | /// Returns the number of instrument items. 93 | /// @return the number of instrument items, including the terminator item. 94 | /// @throws std::length_error Too many instruments. 95 | uint16_t NumItems() const; 96 | 97 | /// Writes an item of inst chunk. 98 | /// @param out the output stream. 99 | /// @param name the name of instrument. 100 | /// @param inst_bag_index the instrument bag index starting from 0. 101 | /// @return the output stream. 102 | /// @throws std::ios_base::failure An I/O error occurred. 103 | static std::ostream & WriteItem(std::ostream & out, 104 | const std::string & name, 105 | uint16_t inst_bag_index); 106 | 107 | /// The size of the chunk (excluding header). 108 | size_type size_; 109 | 110 | /// The instruments of the chunk. 111 | const std::vector> * instruments_; 112 | }; 113 | 114 | } // namespace sf2cute 115 | 116 | #endif // SF2CUTE_RIFF_INST_CHUNK_HPP_ 117 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/riff_pbag_chunk.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont "pbag" RIFF chunk implementation 3 | /// 4 | /// @author gocha 5 | 6 | #include "riff_pbag_chunk.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include "byteio.hpp" 19 | 20 | namespace sf2cute { 21 | 22 | /// Constructs a new empty SFRIFFPbagChunk. 23 | SFRIFFPbagChunk::SFRIFFPbagChunk() : 24 | size_(0), 25 | presets_(nullptr) { 26 | } 27 | 28 | /// Constructs a new SFRIFFPbagChunk using the specified presets. 29 | SFRIFFPbagChunk::SFRIFFPbagChunk( 30 | const std::vector> & presets) : 31 | presets_(&presets) { 32 | size_ = kItemSize * NumItems(); 33 | } 34 | 35 | /// Writes this chunk to the specified output stream. 36 | void SFRIFFPbagChunk::Write(std::ostream & out) const { 37 | // Save exception bits of output stream. 38 | const std::ios_base::iostate old_exception_bits = out.exceptions(); 39 | // Set exception bits to get output error as an exception. 40 | out.exceptions(std::ios::badbit | std::ios::failbit); 41 | 42 | try { 43 | // Write the chunk header. 44 | RIFFChunk::WriteHeader(out, name(), size_); 45 | 46 | // Presets: 47 | size_t generator_index = 0; 48 | size_t modulator_index = 0; 49 | for (const auto & preset : presets()) { 50 | // Global preset zone: 51 | if (preset->has_global_zone()) { 52 | // Write the global zone. 53 | WriteItem(out, uint16_t(generator_index), uint16_t(modulator_index)); 54 | 55 | // Increment the generator index and the modulator index. 56 | generator_index += preset->global_zone().generators().size(); 57 | modulator_index += preset->global_zone().modulators().size(); 58 | } 59 | 60 | // Preset zones: 61 | for (const auto & zone : preset->zones()) { 62 | // Write the preset zone. 63 | WriteItem(out, uint16_t(generator_index), uint16_t(modulator_index)); 64 | 65 | // Increment the generator index and the modulator index. 66 | generator_index += (zone->has_instrument() ? 1 : 0) + zone->generators().size(); 67 | modulator_index += zone->modulators().size(); 68 | } 69 | } 70 | 71 | // Write the last terminator item. 72 | WriteItem(out, uint16_t(generator_index), uint16_t(modulator_index)); 73 | 74 | // Write a padding byte if necessary. 75 | if (size_ % 2 != 0) { 76 | InsertInt8(out, 0); 77 | } 78 | } 79 | catch (const std::exception &) { 80 | // Recover exception bits of output stream. 81 | out.exceptions(old_exception_bits); 82 | 83 | // Rethrow the exception. 84 | throw; 85 | } 86 | } 87 | 88 | /// Returns the number of preset zone items. 89 | uint16_t SFRIFFPbagChunk::NumItems() const { 90 | size_t num_zones = 1; // 1 = terminator 91 | for (const auto & preset : presets()) { 92 | // Count the global zone. 93 | if (preset->has_global_zone()) { 94 | num_zones++; 95 | } 96 | 97 | // Count the preset zones. 98 | num_zones += preset->zones().size(); 99 | 100 | // Check the range of the number of zones. 101 | if (num_zones > UINT16_MAX) { 102 | throw std::length_error("Too many preset zones."); 103 | } 104 | } 105 | return static_cast(num_zones); 106 | } 107 | 108 | /// Writes an item of pbag chunk. 109 | std::ostream & SFRIFFPbagChunk::WriteItem(std::ostream & out, 110 | uint16_t generator_index, 111 | uint16_t modulator_index) { 112 | // struct sfPresetBag: 113 | // uint16_t wGenNdx; 114 | InsertInt16L(out, generator_index); 115 | 116 | // uint16_t wModNdx; 117 | InsertInt16L(out, modulator_index); 118 | 119 | return out; 120 | } 121 | 122 | } // namespace sf2cute 123 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/riff_pbag_chunk.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont "pbag" RIFF chunk header 3 | /// 4 | /// @author gocha 5 | 6 | #ifndef SF2CUTE_RIFF_PBAG_CHUNK_HPP_ 7 | #define SF2CUTE_RIFF_PBAG_CHUNK_HPP_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "riff.hpp" 16 | 17 | namespace sf2cute { 18 | 19 | class SFPreset; 20 | 21 | /// The SFRIFFPbagChunk class represents a SoundFont 2 "pbag" chunk. 22 | class SFRIFFPbagChunk : public RIFFChunkInterface { 23 | public: 24 | /// Unsigned integer type for the chunk size. 25 | using size_type = RIFFChunkInterface::size_type; 26 | 27 | /// The item size of pbag chunk, in terms of bytes. 28 | static constexpr size_type kItemSize = 4; 29 | 30 | /// Constructs a new empty SFRIFFPbagChunk. 31 | SFRIFFPbagChunk(); 32 | 33 | /// Constructs a new SFRIFFPbagChunk using the specified presets. 34 | /// @param presets The presets of the chunk. 35 | /// @throws std::length_error Too many preset zones. 36 | SFRIFFPbagChunk( 37 | const std::vector> & presets); 38 | 39 | /// Constructs a new copy of specified SFRIFFPbagChunk. 40 | /// @param origin a SFRIFFPbagChunk object. 41 | SFRIFFPbagChunk(const SFRIFFPbagChunk & origin) = default; 42 | 43 | /// Copy-assigns a new value to the SFRIFFPbagChunk, replacing its current contents. 44 | /// @param origin a SFRIFFPbagChunk object. 45 | SFRIFFPbagChunk & operator=(const SFRIFFPbagChunk & origin) = default; 46 | 47 | /// Acquires the contents of specified SFRIFFPbagChunk. 48 | /// @param origin a SFRIFFPbagChunk object. 49 | SFRIFFPbagChunk(SFRIFFPbagChunk && origin) = default; 50 | 51 | /// Move-assigns a new value to the SFRIFFPbagChunk, replacing its current contents. 52 | /// @param origin a SFRIFFPbagChunk object. 53 | SFRIFFPbagChunk & operator=(SFRIFFPbagChunk && origin) = default; 54 | 55 | /// Destructs the SFRIFFPbagChunk. 56 | virtual ~SFRIFFPbagChunk() = default; 57 | 58 | /// @copydoc RIFFChunkInterface::name() 59 | virtual std::string name() const override { 60 | return "pbag"; 61 | } 62 | 63 | /// Returns the presets of this chunk. 64 | /// @return the presets of this chunk. 65 | const std::vector> & 66 | presets() const { 67 | return *presets_; 68 | } 69 | 70 | /// Sets the presets of this chunk. 71 | /// @param presets the presets of this chunk. 72 | /// @throws std::length_error Too many preset zones. 73 | void set_presets( 74 | const std::vector> & presets) { 75 | presets_ = &presets; 76 | size_ = kItemSize * NumItems(); 77 | } 78 | 79 | /// Returns the whole length of this chunk. 80 | /// @return the length of this chunk including a chunk header, in terms of bytes. 81 | virtual size_type size() const noexcept override { 82 | return 8 + size_; 83 | } 84 | 85 | /// Writes this chunk to the specified output stream. 86 | /// @param out the output stream. 87 | /// @throws std::length_error The chunk size exceeds the maximum. 88 | /// @throws std::ios_base::failure An I/O error occurred. 89 | virtual void Write(std::ostream & out) const override; 90 | 91 | private: 92 | /// Returns the number of preset zone items. 93 | /// @return the number of preset zone items, including the terminator item. 94 | /// @throws std::length_error Too many preset zones. 95 | uint16_t NumItems() const; 96 | 97 | /// Writes an item of pbag chunk. 98 | /// @param out the output stream. 99 | /// @param generator_index the generator index starting from 0. 100 | /// @param modulator_index the modulator index starting from 0. 101 | /// @return the output stream. 102 | /// @throws std::ios_base::failure An I/O error occurred. 103 | static std::ostream & WriteItem(std::ostream & out, 104 | uint16_t generator_index, 105 | uint16_t modulator_index); 106 | 107 | /// The size of the chunk (excluding header). 108 | size_type size_; 109 | 110 | /// The presets of the chunk. 111 | const std::vector> * presets_; 112 | }; 113 | 114 | } // namespace sf2cute 115 | 116 | #endif // SF2CUTE_RIFF_PBAG_CHUNK_HPP_ 117 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/riff_pgen_chunk.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont "pgen" RIFF chunk implementation 3 | /// 4 | /// @author gocha 5 | 6 | #include "riff_pgen_chunk.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | #include "byteio.hpp" 21 | 22 | namespace sf2cute { 23 | 24 | /// Constructs a new empty SFRIFFPgenChunk. 25 | SFRIFFPgenChunk::SFRIFFPgenChunk() : 26 | size_(0), 27 | presets_(nullptr), 28 | instrument_index_map_() { 29 | } 30 | 31 | /// Constructs a new SFRIFFPgenChunk using the specified presets. 32 | SFRIFFPgenChunk::SFRIFFPgenChunk( 33 | const std::vector> & presets, 34 | std::unordered_map instrument_index_map) : 35 | presets_(&presets), 36 | instrument_index_map_(std::move(instrument_index_map)) { 37 | size_ = kItemSize * NumItems(); 38 | } 39 | 40 | /// Writes this chunk to the specified output stream. 41 | void SFRIFFPgenChunk::Write(std::ostream & out) const { 42 | // Save exception bits of output stream. 43 | const std::ios_base::iostate old_exception_bits = out.exceptions(); 44 | // Set exception bits to get output error as an exception. 45 | out.exceptions(std::ios::badbit | std::ios::failbit); 46 | 47 | try { 48 | // Write the chunk header. 49 | RIFFChunk::WriteHeader(out, name(), size_); 50 | 51 | // Presets: 52 | for (const auto & preset : presets()) { 53 | // Global zone: 54 | if (preset->has_global_zone()) { 55 | // Check the instrument for the global zone. 56 | if (preset->global_zone().has_instrument()) { 57 | // Throw exception if the global zone has a link to an instrument. 58 | throw std::invalid_argument("Global preset zone cannot have a link to an instrument."); 59 | } 60 | 61 | // Write all the generators in the global zone. 62 | for (const auto & generator : SortGenerators(preset->global_zone().generators())) { 63 | WriteItem(out, generator->op(), generator->amount()); 64 | } 65 | } 66 | 67 | // Preset zones: 68 | for (const auto & zone : preset->zones()) { 69 | // Write all the generators in the preset zone. 70 | for (const auto & generator : SortGenerators(zone->generators())) { 71 | WriteItem(out, generator->op(), generator->amount()); 72 | } 73 | 74 | // Check the sample for the zone. 75 | if (zone->has_instrument()) { 76 | // Find the index number for the instrument. 77 | const auto & instrument = zone->instrument(); 78 | if (instrument_index_map().count(instrument.get()) != 0) { 79 | // Write the instrument generator. 80 | GenAmountType instrument_index(instrument_index_map().at(instrument.get())); 81 | WriteItem(out, SFGenerator::kInstrument, instrument_index); 82 | } 83 | else { 84 | // Throw exception if the instrument could not be found in the index map. 85 | throw std::out_of_range("Preset zone points to an unknown instrument."); 86 | } 87 | } 88 | else { 89 | // Throw exception if the preset zone does not have a link to an instrument. 90 | throw std::invalid_argument("Preset zone must have a link to an instrument."); 91 | } 92 | } 93 | } 94 | 95 | // Write the last terminator item. 96 | WriteItem(out, SFGenerator(0), GenAmountType(0)); 97 | 98 | // Write a padding byte if necessary. 99 | if (size_ % 2 != 0) { 100 | InsertInt8(out, 0); 101 | } 102 | } 103 | catch (const std::exception &) { 104 | // Recover exception bits of output stream. 105 | out.exceptions(old_exception_bits); 106 | 107 | // Rethrow the exception. 108 | throw; 109 | } 110 | } 111 | 112 | /// Returns the number of preset generator items. 113 | uint16_t SFRIFFPgenChunk::NumItems() const { 114 | size_t num_generators = 1; // 1 = terminator 115 | for (const auto & preset : presets()) { 116 | // Count the generators in the global zone. 117 | if (preset->has_global_zone()) { 118 | num_generators += preset->global_zone().generators().size(); 119 | if (num_generators > UINT16_MAX) { 120 | throw std::length_error("Too many preset generators."); 121 | } 122 | } 123 | 124 | // Count the generators in the preset zones. 125 | for (const auto & zone : preset->zones()) { 126 | num_generators += (zone->has_instrument() ? 1 : 0) + zone->generators().size(); 127 | if (num_generators > UINT16_MAX) { 128 | throw std::length_error("Too many preset generators."); 129 | } 130 | } 131 | } 132 | return static_cast(num_generators); 133 | } 134 | 135 | /// Writes an item of pgen chunk. 136 | std::ostream & SFRIFFPgenChunk::WriteItem(std::ostream & out, 137 | SFGenerator op, 138 | GenAmountType amount) { 139 | // struct sfGenList: 140 | // SFGenerator sfGenOper; 141 | InsertInt16L(out, static_cast(op)); 142 | 143 | // GenAmountType genAmount; 144 | InsertInt16L(out, amount.value); 145 | 146 | return out; 147 | } 148 | 149 | /// Sort generators based on the ordering requirements of the generator chunk. 150 | std::vector SFRIFFPgenChunk::SortGenerators( 151 | const std::vector> & generators) { 152 | // Make a copy of generator pointers. 153 | std::vector sorted_generators; 154 | sorted_generators.reserve(generators.size()); 155 | for (const auto & generator : generators) { 156 | sorted_generators.push_back(generator.get()); 157 | } 158 | 159 | // Sort the generator pointers. 160 | std::sort(sorted_generators.begin(), sorted_generators.end(), 161 | [](const SFGeneratorItem * x, const SFGeneratorItem * y) { 162 | return SFGeneratorItem::Compare(x->op(), y->op()); 163 | }); 164 | 165 | // Return the sorted pointers. 166 | return sorted_generators; 167 | } 168 | 169 | } // namespace sf2cute 170 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/riff_pgen_chunk.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont "pgen" RIFF chunk header 3 | /// 4 | /// @author gocha 5 | 6 | #ifndef SF2CUTE_RIFF_PGEN_CHUNK_HPP_ 7 | #define SF2CUTE_RIFF_PGEN_CHUNK_HPP_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include "riff.hpp" 19 | 20 | namespace sf2cute { 21 | 22 | class SFPreset; 23 | class SFInstrument; 24 | class SFGeneratorItem; 25 | 26 | /// The SFRIFFPgenChunk class represents a SoundFont 2 "pgen" chunk. 27 | class SFRIFFPgenChunk : public RIFFChunkInterface { 28 | public: 29 | /// Unsigned integer type for the chunk size. 30 | using size_type = RIFFChunkInterface::size_type; 31 | 32 | /// The item size of pgen chunk, in terms of bytes. 33 | static constexpr size_type kItemSize = 4; 34 | 35 | /// Constructs a new empty SFRIFFPgenChunk. 36 | SFRIFFPgenChunk(); 37 | 38 | /// Constructs a new SFRIFFPgenChunk using the specified presets. 39 | /// @param presets the presets of the chunk. 40 | /// @param instrument_index_map map containing the instruments as keys and their indices as map values. 41 | /// @throws std::length_error Too many preset generators. 42 | SFRIFFPgenChunk( 43 | const std::vector> & presets, 44 | std::unordered_map instrument_index_map); 45 | 46 | /// Constructs a new copy of specified SFRIFFPgenChunk. 47 | /// @param origin a SFRIFFPgenChunk object. 48 | SFRIFFPgenChunk(const SFRIFFPgenChunk & origin) = default; 49 | 50 | /// Copy-assigns a new value to the SFRIFFPgenChunk, replacing its current contents. 51 | /// @param origin a SFRIFFPgenChunk object. 52 | SFRIFFPgenChunk & operator=(const SFRIFFPgenChunk & origin) = default; 53 | 54 | /// Acquires the contents of specified SFRIFFPgenChunk. 55 | /// @param origin a SFRIFFPgenChunk object. 56 | SFRIFFPgenChunk(SFRIFFPgenChunk && origin) = default; 57 | 58 | /// Move-assigns a new value to the SFRIFFPgenChunk, replacing its current contents. 59 | /// @param origin a SFRIFFPgenChunk object. 60 | SFRIFFPgenChunk & operator=(SFRIFFPgenChunk && origin) = default; 61 | 62 | /// Destructs the SFRIFFPgenChunk. 63 | virtual ~SFRIFFPgenChunk() = default; 64 | 65 | /// @copydoc RIFFChunkInterface::name() 66 | virtual std::string name() const override { 67 | return "pgen"; 68 | } 69 | 70 | /// Returns the presets of this chunk. 71 | /// @return the presets of this chunk. 72 | const std::vector> & 73 | presets() const { 74 | return *presets_; 75 | } 76 | 77 | /// Sets the presets of this chunk. 78 | /// @param presets the presets of this chunk. 79 | /// @throws std::length_error Too many preset generators. 80 | void set_presets( 81 | const std::vector> & presets) { 82 | presets_ = &presets; 83 | size_ = kItemSize * NumItems(); 84 | } 85 | 86 | /// Returns the map containing the instruments as keys and their indices as map values. 87 | /// @return the map containing the instruments as keys and their indices as map values. 88 | const std::unordered_map & 89 | instrument_index_map() const { 90 | return instrument_index_map_; 91 | } 92 | 93 | /// Sets the map containing the instruments as keys and their indices as map values. 94 | /// @param instrument_index_map the map containing the instruments as keys and their indices as map values. 95 | void set_instrument_index_map( 96 | std::unordered_map instrument_index_map) { 97 | instrument_index_map_ = std::move(instrument_index_map); 98 | } 99 | 100 | /// Returns the whole length of this chunk. 101 | /// @return the length of this chunk including a chunk header, in terms of bytes. 102 | virtual size_type size() const noexcept override { 103 | return 8 + size_; 104 | } 105 | 106 | /// Writes this chunk to the specified output stream. 107 | /// @param out the output stream. 108 | /// @throws std::invalid_argument Global preset zone has an instrument. 109 | /// @throws std::invalid_argument Instrument zone does not have an instrument. 110 | /// @throws std::length_error The chunk size exceeds the maximum. 111 | /// @throws std::out_of_range Preset zone points to an unknown instrument. 112 | /// @throws std::ios_base::failure An I/O error occurred. 113 | virtual void Write(std::ostream & out) const override; 114 | 115 | private: 116 | /// Returns the number of preset generator items. 117 | /// @return the number of preset generator items, including the terminator item. 118 | /// @throws std::length_error Too many preset generators. 119 | uint16_t NumItems() const; 120 | 121 | /// Writes an item of pgen chunk. 122 | /// @param out the output stream. 123 | /// @param op the type of the generator. 124 | /// @param amount the amount of the generator. 125 | /// @return the output stream. 126 | /// @throws std::ios_base::failure An I/O error occurred. 127 | static std::ostream & WriteItem(std::ostream & out, 128 | SFGenerator op, 129 | GenAmountType amount); 130 | 131 | /// Sort generators based on the ordering requirements of the generator chunk. 132 | /// @param generators the generators. 133 | /// @return the sorted collection of the generator pointers. 134 | static std::vector SortGenerators( 135 | const std::vector> & generators); 136 | 137 | /// The size of the chunk (excluding header). 138 | size_type size_; 139 | 140 | /// The presets of the chunk. 141 | const std::vector> * presets_; 142 | 143 | /// The map containing the instruments as keys and their indices as map values. 144 | std::unordered_map instrument_index_map_; 145 | }; 146 | 147 | } // namespace sf2cute 148 | 149 | #endif // SF2CUTE_RIFF_PGEN_CHUNK_HPP_ 150 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/riff_phdr_chunk.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont "phdr" RIFF chunk implementation 3 | /// 4 | /// @author gocha 5 | 6 | #include "riff_phdr_chunk.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include "byteio.hpp" 18 | 19 | namespace sf2cute { 20 | 21 | /// Constructs a new empty SFRIFFPhdrChunk. 22 | SFRIFFPhdrChunk::SFRIFFPhdrChunk() : 23 | size_(0), 24 | presets_(nullptr) { 25 | } 26 | 27 | /// Constructs a new SFRIFFPhdrChunk using the specified presets. 28 | SFRIFFPhdrChunk::SFRIFFPhdrChunk( 29 | const std::vector> & presets) : 30 | presets_(&presets) { 31 | size_ = kItemSize * NumItems(); 32 | } 33 | 34 | /// Writes this chunk to the specified output stream. 35 | void SFRIFFPhdrChunk::Write(std::ostream & out) const { 36 | // Save exception bits of output stream. 37 | const std::ios_base::iostate old_exception_bits = out.exceptions(); 38 | // Set exception bits to get output error as an exception. 39 | out.exceptions(std::ios::badbit | std::ios::failbit); 40 | 41 | try { 42 | // Write the chunk header. 43 | RIFFChunk::WriteHeader(out, name(), size_); 44 | 45 | // Presets: 46 | size_t preset_bag_index = 0; 47 | for (const auto & preset : presets()) { 48 | // Write the preset header. 49 | WriteItem(out, preset->name(), 50 | preset->preset_number(), preset->bank(), uint16_t(preset_bag_index), 51 | preset->library(), preset->genre(), preset->morphology()); 52 | 53 | // Count the number of preset zones. 54 | size_t num_zones = 0; 55 | if (preset->has_global_zone()) { 56 | num_zones++; 57 | } 58 | num_zones += preset->zones().size(); 59 | 60 | // Increment the preset bag index. 61 | preset_bag_index += num_zones; 62 | } 63 | 64 | // Write the last terminator item. 65 | WriteItem(out, "EOP", 0, 0, uint16_t(preset_bag_index), 0, 0, 0); 66 | 67 | // Write a padding byte if necessary. 68 | if (size_ % 2 != 0) { 69 | InsertInt8(out, 0); 70 | } 71 | } 72 | catch (const std::exception &) { 73 | // Recover exception bits of output stream. 74 | out.exceptions(old_exception_bits); 75 | 76 | // Rethrow the exception. 77 | throw; 78 | } 79 | } 80 | 81 | /// Returns the number of preset items. 82 | uint16_t SFRIFFPhdrChunk::NumItems() const { 83 | size_t num_preset_items = presets().size() + 1; 84 | if (num_preset_items > UINT16_MAX) { 85 | throw std::length_error("Too many presets."); 86 | } 87 | return static_cast(num_preset_items); 88 | } 89 | 90 | /// Writes an item of phdr chunk. 91 | std::ostream & SFRIFFPhdrChunk::WriteItem(std::ostream & out, 92 | const std::string & name, 93 | uint16_t preset_number, 94 | uint16_t bank, 95 | uint16_t preset_bag_index, 96 | uint32_t library, 97 | uint32_t genre, 98 | uint32_t morphology) { 99 | // struct sfPresetHeader: 100 | // char achPresetName[20]; 101 | std::string preset_name(name.substr(0, SFPreset::kMaxNameLength)); 102 | out.write(preset_name.data(), preset_name.size()); 103 | for (std::string::size_type i = 0; i < SFPreset::kMaxNameLength + 1 - preset_name.size(); i++) { 104 | out.put(0); 105 | } 106 | 107 | // uint16_t wPreset; 108 | InsertInt16L(out, preset_number); 109 | 110 | // uint16_t wBank; 111 | InsertInt16L(out, bank); 112 | 113 | // uint16_t wPresetBagNdx; 114 | InsertInt16L(out, preset_bag_index); 115 | 116 | // uint32_t dwLibrary; 117 | InsertInt32L(out, library); 118 | 119 | // uint32_t dwGenre; 120 | InsertInt32L(out, genre); 121 | 122 | // uint32_t dwMorphology; 123 | InsertInt32L(out, morphology); 124 | 125 | return out; 126 | } 127 | 128 | } // namespace sf2cute 129 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/riff_phdr_chunk.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont "phdr" RIFF chunk header 3 | /// 4 | /// @author gocha 5 | 6 | #ifndef SF2CUTE_RIFF_PHDR_CHUNK_HPP_ 7 | #define SF2CUTE_RIFF_PHDR_CHUNK_HPP_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "riff.hpp" 16 | 17 | namespace sf2cute { 18 | 19 | class SFPreset; 20 | 21 | /// The SFRIFFPhdrChunk class represents a SoundFont 2 "phdr" chunk. 22 | class SFRIFFPhdrChunk : public RIFFChunkInterface { 23 | public: 24 | /// Unsigned integer type for the chunk size. 25 | using size_type = RIFFChunkInterface::size_type; 26 | 27 | /// The item size of phdr chunk, in terms of bytes. 28 | static constexpr size_type kItemSize = 38; 29 | 30 | /// Constructs a new empty SFRIFFPhdrChunk. 31 | SFRIFFPhdrChunk(); 32 | 33 | /// Constructs a new SFRIFFPhdrChunk using the specified presets. 34 | /// @param presets The presets of the chunk. 35 | /// @throws std::length_error Too many presets. 36 | SFRIFFPhdrChunk( 37 | const std::vector> & presets); 38 | 39 | /// Constructs a new copy of specified SFRIFFPhdrChunk. 40 | /// @param origin a SFRIFFPhdrChunk object. 41 | SFRIFFPhdrChunk(const SFRIFFPhdrChunk & origin) = default; 42 | 43 | /// Copy-assigns a new value to the SFRIFFPhdrChunk, replacing its current contents. 44 | /// @param origin a SFRIFFPhdrChunk object. 45 | SFRIFFPhdrChunk & operator=(const SFRIFFPhdrChunk & origin) = default; 46 | 47 | /// Acquires the contents of specified SFRIFFPhdrChunk. 48 | /// @param origin a SFRIFFPhdrChunk object. 49 | SFRIFFPhdrChunk(SFRIFFPhdrChunk && origin) = default; 50 | 51 | /// Move-assigns a new value to the SFRIFFPhdrChunk, replacing its current contents. 52 | /// @param origin a SFRIFFPhdrChunk object. 53 | SFRIFFPhdrChunk & operator=(SFRIFFPhdrChunk && origin) = default; 54 | 55 | /// Destructs the SFRIFFPhdrChunk. 56 | virtual ~SFRIFFPhdrChunk() = default; 57 | 58 | /// @copydoc RIFFChunkInterface::name() 59 | virtual std::string name() const override { 60 | return "phdr"; 61 | } 62 | 63 | /// Returns the presets of this chunk. 64 | /// @return the presets of this chunk. 65 | const std::vector> & 66 | presets() const { 67 | return *presets_; 68 | } 69 | 70 | /// Sets the presets of this chunk. 71 | /// @param presets the presets of this chunk. 72 | /// @throws std::length_error Too many presets. 73 | void set_presets( 74 | const std::vector> & presets) { 75 | presets_ = &presets; 76 | size_ = kItemSize * NumItems(); 77 | } 78 | 79 | /// Returns the whole length of this chunk. 80 | /// @return the length of this chunk including a chunk header, in terms of bytes. 81 | virtual size_type size() const noexcept override { 82 | return 8 + size_; 83 | } 84 | 85 | /// Writes this chunk to the specified output stream. 86 | /// @param out the output stream. 87 | /// @throws std::length_error The chunk size exceeds the maximum. 88 | /// @throws std::ios_base::failure An I/O error occurred. 89 | virtual void Write(std::ostream & out) const override; 90 | 91 | private: 92 | /// Returns the number of preset items. 93 | /// @return the number of preset items, including the terminator item. 94 | /// @throws std::length_error Too many presets. 95 | uint16_t NumItems() const; 96 | 97 | /// Writes an item of phdr chunk. 98 | /// @param out the output stream. 99 | /// @param name the name of preset. 100 | /// @param preset_number the preset number. 101 | /// @param bank the bank number. 102 | /// @param preset_bag_index the preset bag index starting from 0. 103 | /// @param library the library. 104 | /// @param genre the genre. 105 | /// @param morphology the morphology. 106 | /// @return the output stream. 107 | /// @throws std::ios_base::failure An I/O error occurred. 108 | static std::ostream & WriteItem(std::ostream & out, 109 | const std::string & name, 110 | uint16_t preset_number, 111 | uint16_t bank, 112 | uint16_t preset_bag_index, 113 | uint32_t library, 114 | uint32_t genre, 115 | uint32_t morphology); 116 | 117 | /// The name of the chunk. 118 | std::string name_; 119 | 120 | /// The size of the chunk (excluding header). 121 | size_type size_; 122 | 123 | /// The presets of the chunk. 124 | const std::vector> * presets_; 125 | }; 126 | 127 | } // namespace sf2cute 128 | 129 | #endif // SF2CUTE_RIFF_PHDR_CHUNK_HPP_ 130 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/riff_pmod_chunk.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont "pmod" RIFF chunk implementation 3 | /// 4 | /// @author gocha 5 | 6 | #include "riff_pmod_chunk.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include "byteio.hpp" 19 | 20 | namespace sf2cute { 21 | 22 | /// Constructs a new empty SFRIFFPmodChunk. 23 | SFRIFFPmodChunk::SFRIFFPmodChunk() : 24 | size_(0), 25 | presets_(nullptr) { 26 | } 27 | 28 | /// Constructs a new SFRIFFPmodChunk using the specified presets. 29 | SFRIFFPmodChunk::SFRIFFPmodChunk( 30 | const std::vector> & presets) : 31 | presets_(&presets) { 32 | size_ = kItemSize * NumItems(); 33 | } 34 | 35 | /// Writes this chunk to the specified output stream. 36 | void SFRIFFPmodChunk::Write(std::ostream & out) const { 37 | // Save exception bits of output stream. 38 | const std::ios_base::iostate old_exception_bits = out.exceptions(); 39 | // Set exception bits to get output error as an exception. 40 | out.exceptions(std::ios::badbit | std::ios::failbit); 41 | 42 | try { 43 | // Write the chunk header. 44 | RIFFChunk::WriteHeader(out, name(), size_); 45 | 46 | // Presets: 47 | for (const auto & preset : presets()) { 48 | // Global zone: 49 | if (preset->has_global_zone()) { 50 | // Write all the modulators in the global zone. 51 | for (const auto & modulator : preset->global_zone().modulators()) { 52 | WriteItem(out, modulator->source_op(), modulator->destination_op(), 53 | modulator->amount(), modulator->amount_source_op(), modulator->transform_op()); 54 | } 55 | } 56 | 57 | // Preset zones: 58 | for (const auto & zone : preset->zones()) { 59 | // Write all the modulators in the preset zone. 60 | for (const auto & modulator : zone->modulators()) { 61 | WriteItem(out, modulator->source_op(), modulator->destination_op(), 62 | modulator->amount(), modulator->amount_source_op(), modulator->transform_op()); 63 | } 64 | } 65 | } 66 | 67 | // Write the last terminator item. 68 | WriteItem(out, SFModulator(0), SFGenerator(0), 0, SFModulator(0), SFTransform(0)); 69 | 70 | // Write a padding byte if necessary. 71 | if (size_ % 2 != 0) { 72 | InsertInt8(out, 0); 73 | } 74 | } 75 | catch (const std::exception &) { 76 | // Recover exception bits of output stream. 77 | out.exceptions(old_exception_bits); 78 | 79 | // Rethrow the exception. 80 | throw; 81 | } 82 | } 83 | 84 | /// Returns the number of preset modulator items. 85 | uint16_t SFRIFFPmodChunk::NumItems() const { 86 | size_t num_modulators = 1; // 1 = terminator 87 | for (const auto & preset : presets()) { 88 | // Count the modulators in the global zone. 89 | if (preset->has_global_zone()) { 90 | num_modulators += preset->global_zone().modulators().size(); 91 | if (num_modulators > UINT16_MAX) { 92 | throw std::length_error("Too many preset modulators."); 93 | } 94 | } 95 | 96 | // Count the modulators in the instrument zones. 97 | for (const auto & zone : preset->zones()) { 98 | num_modulators += zone->modulators().size(); 99 | if (num_modulators > UINT16_MAX) { 100 | throw std::length_error("Too many preset modulators."); 101 | } 102 | } 103 | } 104 | return static_cast(num_modulators); 105 | } 106 | 107 | /// Writes an item of pmod chunk. 108 | std::ostream & SFRIFFPmodChunk::WriteItem(std::ostream & out, 109 | SFModulator source_op, 110 | SFGenerator destination_op, 111 | int16_t amount, 112 | SFModulator amount_source_op, 113 | SFTransform transform_op) { 114 | // struct sfModList: 115 | // SFModulator sfModSrcOper; 116 | InsertInt16L(out, uint16_t(source_op)); 117 | 118 | // SFGenerator sfModDestOper; 119 | InsertInt16L(out, uint16_t(destination_op)); 120 | 121 | // int16_t modAmount; 122 | InsertInt16L(out, amount); 123 | 124 | // SFModulator sfModAmtSrcOper; 125 | InsertInt16L(out, uint16_t(amount_source_op)); 126 | 127 | // SFTransform sfModTransOper; 128 | InsertInt16L(out, uint16_t(transform_op)); 129 | 130 | return out; 131 | } 132 | 133 | } // namespace sf2cute 134 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/riff_pmod_chunk.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont "pmod" RIFF chunk header 3 | /// 4 | /// @author gocha 5 | 6 | #ifndef SF2CUTE_RIFF_PMOD_CHUNK_HPP_ 7 | #define SF2CUTE_RIFF_PMOD_CHUNK_HPP_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include "riff.hpp" 19 | 20 | namespace sf2cute { 21 | 22 | class SFPreset; 23 | 24 | /// The SFRIFFPmodChunk class represents a SoundFont 2 "pmod" chunk. 25 | class SFRIFFPmodChunk : public RIFFChunkInterface { 26 | public: 27 | /// Unsigned integer type for the chunk size. 28 | using size_type = RIFFChunkInterface::size_type; 29 | 30 | /// The item size of pmod chunk, in terms of bytes. 31 | static constexpr size_type kItemSize = 10; 32 | 33 | /// Constructs a new empty SFRIFFPmodChunk. 34 | SFRIFFPmodChunk(); 35 | 36 | /// Constructs a new SFRIFFPmodChunk using the specified presets. 37 | /// @param presets The presets of the chunk. 38 | /// @throws std::length_error Too many preset modulators. 39 | SFRIFFPmodChunk( 40 | const std::vector> & presets); 41 | 42 | /// Constructs a new copy of specified SFRIFFPmodChunk. 43 | /// @param origin a SFRIFFPmodChunk object. 44 | SFRIFFPmodChunk(const SFRIFFPmodChunk & origin) = default; 45 | 46 | /// Copy-assigns a new value to the SFRIFFPmodChunk, replacing its current contents. 47 | /// @param origin a SFRIFFPmodChunk object. 48 | SFRIFFPmodChunk & operator=(const SFRIFFPmodChunk & origin) = default; 49 | 50 | /// Acquires the contents of specified SFRIFFPmodChunk. 51 | /// @param origin a SFRIFFPmodChunk object. 52 | SFRIFFPmodChunk(SFRIFFPmodChunk && origin) = default; 53 | 54 | /// Move-assigns a new value to the SFRIFFPmodChunk, replacing its current contents. 55 | /// @param origin a SFRIFFPmodChunk object. 56 | SFRIFFPmodChunk & operator=(SFRIFFPmodChunk && origin) = default; 57 | 58 | /// Destructs the SFRIFFPmodChunk. 59 | virtual ~SFRIFFPmodChunk() = default; 60 | 61 | /// @copydoc RIFFChunkInterface::name() 62 | virtual std::string name() const override { 63 | return "pmod"; 64 | } 65 | 66 | /// Returns the presets of this chunk. 67 | /// @return the presets of this chunk. 68 | const std::vector> & 69 | presets() const { 70 | return *presets_; 71 | } 72 | 73 | /// Sets the presets of this chunk. 74 | /// @param presets the presets of this chunk. 75 | /// @throws std::length_error Too many preset modulators. 76 | void set_presets( 77 | const std::vector> & presets) { 78 | presets_ = &presets; 79 | size_ = kItemSize * NumItems(); 80 | } 81 | 82 | /// Returns the whole length of this chunk. 83 | /// @return the length of this chunk including a chunk header, in terms of bytes. 84 | virtual size_type size() const noexcept override { 85 | return 8 + size_; 86 | } 87 | 88 | /// Writes this chunk to the specified output stream. 89 | /// @param out the output stream. 90 | /// @throws std::length_error The chunk size exceeds the maximum. 91 | /// @throws std::ios_base::failure An I/O error occurred. 92 | virtual void Write(std::ostream & out) const override; 93 | 94 | private: 95 | /// Returns the number of preset modulator items. 96 | /// @return the number of preset modulator items, including the terminator item. 97 | /// @throws std::length_error Too many preset modulators. 98 | uint16_t NumItems() const; 99 | 100 | /// Writes an item of pmod chunk. 101 | /// @param out the output stream. 102 | /// @param source_op the source of data for the modulator. 103 | /// @param destination_op the destination of the modulator. 104 | /// @param amount the degree to which the source modulates the destination. 105 | /// @param amount_source_op the modulation source to be applied to the modulation amount. 106 | /// @param transform_op the transform type to be applied to the modulation source. 107 | /// @return the output stream. 108 | /// @throws std::ios_base::failure An I/O error occurred. 109 | static std::ostream & WriteItem(std::ostream & out, 110 | SFModulator source_op, 111 | SFGenerator destination_op, 112 | int16_t amount, 113 | SFModulator amount_source_op, 114 | SFTransform transform_op); 115 | 116 | /// The size of the chunk (excluding header). 117 | size_type size_; 118 | 119 | /// The presets of the chunk. 120 | const std::vector> * presets_; 121 | }; 122 | 123 | } // namespace sf2cute 124 | 125 | #endif // SF2CUTE_RIFF_PMOD_CHUNK_HPP_ 126 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/riff_shdr_chunk.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont "shdr" RIFF chunk implementation 3 | /// 4 | /// @author gocha 5 | 6 | #include "riff_shdr_chunk.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include "byteio.hpp" 19 | 20 | namespace sf2cute { 21 | 22 | /// Constructs a new empty SFRIFFShdrChunk. 23 | SFRIFFShdrChunk::SFRIFFShdrChunk() : 24 | size_(0), 25 | samples_(nullptr), 26 | sample_index_map_() { 27 | } 28 | 29 | /// Constructs a new SFRIFFShdrChunk using the specified samples. 30 | SFRIFFShdrChunk::SFRIFFShdrChunk(const std::vector> & samples, 31 | std::unordered_map sample_index_map) : 32 | samples_(&samples), 33 | sample_index_map_(std::move(sample_index_map)) { 34 | size_ = kItemSize * NumItems(); 35 | } 36 | 37 | /// Writes this chunk to the specified output stream. 38 | void SFRIFFShdrChunk::Write(std::ostream & out) const { 39 | // Save exception bits of output stream. 40 | const std::ios_base::iostate old_exception_bits = out.exceptions(); 41 | // Set exception bits to get output error as an exception. 42 | out.exceptions(std::ios::badbit | std::ios::failbit); 43 | 44 | try { 45 | // Write the chunk header. 46 | RIFFChunk::WriteHeader(out, name(), size_); 47 | 48 | // Sample headers: 49 | size_t start_sample = 0; 50 | for (const auto & sample : samples()) { 51 | // Find the linked sample. 52 | uint16_t link_index = 0; 53 | if (sample->has_link()) { 54 | const auto & link = sample->link(); 55 | if (sample_index_map().count(link.get()) != 0) { 56 | link_index = sample_index_map().at(link.get()); 57 | } 58 | else { 59 | throw std::out_of_range("Sample has a link to an unknown sample."); 60 | } 61 | } 62 | 63 | // Calculate the sample indices. 64 | size_t end_sample = start_sample + sample->data().size(); 65 | size_t start_loop = start_sample + sample->start_loop(); 66 | size_t end_loop = start_sample + sample->end_loop(); 67 | 68 | // Check the range of indices. 69 | if (start_sample > UINT32_MAX || end_sample > UINT32_MAX || 70 | start_loop > UINT32_MAX || end_loop > UINT32_MAX) { 71 | throw std::length_error("Too many sample datapoints."); 72 | } 73 | 74 | // Write the sample header. 75 | WriteItem(out, 76 | sample->name(), 77 | uint32_t(start_sample), 78 | uint32_t(end_sample), 79 | uint32_t(start_loop), 80 | uint32_t(end_loop), 81 | sample->sample_rate(), 82 | sample->original_key(), 83 | sample->correction(), 84 | link_index, 85 | sample->type()); 86 | 87 | // Calculate the next sample index. 88 | start_sample += sample->data().size() + SFSample::kTerminatorSampleLength; 89 | } 90 | 91 | // Write the last terminator item. 92 | WriteItem(out, "EOS", 0, 0, 0, 0, 0, 0, 0, 0, SFSampleLink(0)); 93 | 94 | // Write a padding byte if necessary. 95 | if (size_ % 2 != 0) { 96 | InsertInt8(out, 0); 97 | } 98 | } 99 | catch (const std::exception &) { 100 | // Recover exception bits of output stream. 101 | out.exceptions(old_exception_bits); 102 | 103 | // Rethrow the exception. 104 | throw; 105 | } 106 | } 107 | 108 | /// Returns the number of sample header items. 109 | uint16_t SFRIFFShdrChunk::NumItems() const { 110 | auto num_sample_items = samples().size() + 1; 111 | if (num_sample_items > UINT16_MAX) { 112 | throw std::length_error("Too many samples."); 113 | } 114 | return static_cast(num_sample_items); 115 | } 116 | 117 | /// Writes an item of shdr chunk. 118 | std::ostream & SFRIFFShdrChunk::WriteItem(std::ostream & out, 119 | const std::string & name, uint32_t start, uint32_t end, 120 | uint32_t start_loop, uint32_t end_loop, uint32_t sample_rate, 121 | uint8_t original_key, int8_t correction, uint16_t link, SFSampleLink type) { 122 | // struct sfSample: 123 | // char achSampleName[20]; 124 | std::string sample_name(name.substr(0, SFSample::kMaxNameLength)); 125 | out.write(sample_name.data(), sample_name.size()); 126 | for (std::string::size_type i = 0; i < SFSample::kMaxNameLength + 1 - sample_name.size(); i++) { 127 | out.put(0); 128 | } 129 | 130 | // uint32_t dwStart; 131 | InsertInt32L(out, start); 132 | 133 | // uint32_t dwEnd; 134 | InsertInt32L(out, end); 135 | 136 | // uint32_t dwStartloop; 137 | InsertInt32L(out, start_loop); 138 | 139 | // uint32_t dwEndloop; 140 | InsertInt32L(out, end_loop); 141 | 142 | // uint32_t dwSampleRate; 143 | InsertInt32L(out, sample_rate); 144 | 145 | // uint8_t byOriginalKey; 146 | InsertInt8(out, original_key); 147 | 148 | // int8_t chCorrection; 149 | InsertInt8(out, correction); 150 | 151 | // uint16_t wSampleLink; 152 | InsertInt16L(out, link); 153 | 154 | // SFSampleLink sfSampleType; 155 | InsertInt16L(out, uint16_t(type)); 156 | 157 | return out; 158 | } 159 | 160 | } // namespace sf2cute 161 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/riff_shdr_chunk.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont "shdr" RIFF chunk header 3 | /// 4 | /// @author gocha 5 | 6 | #ifndef SF2CUTE_RIFF_SHDR_CHUNK_HPP_ 7 | #define SF2CUTE_RIFF_SHDR_CHUNK_HPP_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | #include "riff.hpp" 20 | 21 | namespace sf2cute { 22 | 23 | class SFSample; 24 | 25 | /// The SFRIFFShdrChunk class represents a SoundFont 2 "shdr" chunk. 26 | class SFRIFFShdrChunk : public RIFFChunkInterface { 27 | public: 28 | /// Unsigned integer type for the chunk size. 29 | using size_type = RIFFChunkInterface::size_type; 30 | 31 | /// The item size of shdr chunk, in terms of bytes. 32 | static constexpr size_type kItemSize = 46; 33 | 34 | /// Constructs a new empty SFRIFFShdrChunk. 35 | SFRIFFShdrChunk(); 36 | 37 | /// Constructs a new SFRIFFShdrChunk using the specified samples. 38 | /// @param samples The samples of the chunk. 39 | /// @param sample_index_map the map containing the samples as keys and their indices as map values. 40 | /// @throws std::length_error Too many samples. 41 | SFRIFFShdrChunk(const std::vector> & samples, 42 | std::unordered_map sample_index_map); 43 | 44 | /// Constructs a new copy of specified SFRIFFShdrChunk. 45 | /// @param origin a SFRIFFShdrChunk object. 46 | SFRIFFShdrChunk(const SFRIFFShdrChunk & origin) = default; 47 | 48 | /// Copy-assigns a new value to the SFRIFFShdrChunk, replacing its current contents. 49 | /// @param origin a SFRIFFShdrChunk object. 50 | SFRIFFShdrChunk & operator=(const SFRIFFShdrChunk & origin) = default; 51 | 52 | /// Acquires the contents of specified SFRIFFShdrChunk. 53 | /// @param origin a SFRIFFShdrChunk object. 54 | SFRIFFShdrChunk(SFRIFFShdrChunk && origin) = default; 55 | 56 | /// Move-assigns a new value to the SFRIFFShdrChunk, replacing its current contents. 57 | /// @param origin a SFRIFFShdrChunk object. 58 | SFRIFFShdrChunk & operator=(SFRIFFShdrChunk && origin) = default; 59 | 60 | /// Destructs the SFRIFFShdrChunk. 61 | virtual ~SFRIFFShdrChunk() = default; 62 | 63 | /// @copydoc RIFFChunkInterface::name() 64 | virtual std::string name() const override { 65 | return "shdr"; 66 | } 67 | 68 | /// Returns the samples of this chunk. 69 | /// @return the samples of this chunk. 70 | const std::vector> & samples() const { 71 | return *samples_; 72 | } 73 | 74 | /// Sets the samples of this chunk. 75 | /// @param samples the samples of this chunk. 76 | /// @throws std::length_error Too many samples. 77 | void set_samples(const std::vector> & samples) { 78 | samples_ = &samples; 79 | size_ = kItemSize * NumItems(); 80 | } 81 | 82 | /// Returns the map containing the samples as keys and their indices as map values. 83 | /// @return the map containing the samples as keys and their indices as map values. 84 | const std::unordered_map & sample_index_map() const { 85 | return sample_index_map_; 86 | } 87 | 88 | /// Sets the map containing the samples as keys and their indices as map values. 89 | /// @param sample_index_map the map containing the samples as keys and their indices as map values. 90 | void set_sample_index_map(std::unordered_map sample_index_map) { 91 | sample_index_map_ = std::move(sample_index_map); 92 | } 93 | 94 | /// Returns the whole length of this chunk. 95 | /// @return the length of this chunk including a chunk header, in terms of bytes. 96 | virtual size_type size() const noexcept override { 97 | return 8 + size_; 98 | } 99 | 100 | /// Writes this chunk to the specified output stream. 101 | /// @param out the output stream. 102 | /// @throws std::length_error The chunk size exceeds the maximum. 103 | /// @throws std::out_of_range Sample has a link to an unknown sample. 104 | /// @throws std::ios_base::failure An I/O error occurred. 105 | virtual void Write(std::ostream & out) const override; 106 | 107 | private: 108 | /// Returns the number of sample header items. 109 | /// @return the number of sample header items, including the terminator item. 110 | /// @throws std::length_error Too many samples. 111 | uint16_t NumItems() const; 112 | 113 | /// Writes an item of shdr chunk. 114 | /// @param out the output stream. 115 | /// @param name the name of sample. 116 | /// @param start the beginning index of the sample, in sample data points, inclusive. 117 | /// @param end the ending index of the sample, in sample data points, exclusive. 118 | /// @param start_loop the beginning index of the loop, in sample data points, inclusive. 119 | /// @param end_loop the ending index of the loop, in sample data points, exclusive. 120 | /// @param sample_rate the sample rate, in hertz. 121 | /// @param original_key the MIDI key number of the recorded pitch of the sample. 122 | /// @param correction the pitch correction that should be applied to the sample, in cents. 123 | /// @param link the associated right or left stereo sample. nullptr is allowed. 124 | /// @param type both the type of sample and the whether the sample is located in RAM or ROM memory. 125 | /// @return the output stream. 126 | /// @throws std::ios_base::failure An I/O error occurred. 127 | static std::ostream & WriteItem(std::ostream & out, 128 | const std::string & name, uint32_t start, uint32_t end, 129 | uint32_t start_loop, uint32_t end_loop, uint32_t sample_rate, 130 | uint8_t original_key, int8_t correction, uint16_t link, SFSampleLink type); 131 | 132 | /// The size of the chunk (excluding header). 133 | size_type size_; 134 | 135 | /// The samples of the chunk. 136 | const std::vector> * samples_; 137 | 138 | /// The map containing the samples as keys and their indices as map values. 139 | std::unordered_map sample_index_map_; 140 | }; 141 | 142 | } // namespace sf2cute 143 | 144 | #endif // SF2CUTE_RIFF_SHDR_CHUNK_HPP_ 145 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/riff_smpl_chunk.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont "smpl" RIFF chunk implementation 3 | /// 4 | /// @author gocha 5 | 6 | #include "riff_smpl_chunk.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include "byteio.hpp" 17 | 18 | namespace sf2cute { 19 | 20 | /// Constructs a new empty SFRIFFSmplChunk. 21 | SFRIFFSmplChunk::SFRIFFSmplChunk() : 22 | size_(0), 23 | samples_(nullptr) { 24 | } 25 | 26 | /// Constructs a new SFRIFFSmplChunk using the specified samples. 27 | SFRIFFSmplChunk::SFRIFFSmplChunk( 28 | const std::vector> & samples) : 29 | samples_(&samples) { 30 | size_ = GetSamplePoolSize(); 31 | } 32 | 33 | /// Writes this chunk to the specified output stream. 34 | void SFRIFFSmplChunk::Write(std::ostream & out) const { 35 | // Save exception bits of output stream. 36 | const std::ios_base::iostate old_exception_bits = out.exceptions(); 37 | // Set exception bits to get output error as an exception. 38 | out.exceptions(std::ios::badbit | std::ios::failbit); 39 | 40 | try { 41 | // Write the chunk header. 42 | RIFFChunk::WriteHeader(out, name(), size_); 43 | 44 | // Write the chunk data. 45 | for (const auto & sample : samples()) { 46 | // Write the samples. 47 | for (int16_t value : sample->data()) { 48 | InsertInt16L(out, value); 49 | } 50 | 51 | // Write terminator samples. 52 | for (uint32_t index = 0; index < SFSample::kTerminatorSampleLength; index++) { 53 | InsertInt16L(out, 0); 54 | } 55 | } 56 | 57 | // Write a padding byte if necessary. 58 | if (size_ % 2 != 0) { 59 | InsertInt8(out, 0); 60 | } 61 | } 62 | catch (const std::exception &) { 63 | // Recover exception bits of output stream. 64 | out.exceptions(old_exception_bits); 65 | 66 | // Rethrow the exception. 67 | throw; 68 | } 69 | } 70 | 71 | /// Returns the total sample pool size. 72 | SFRIFFSmplChunk::size_type SFRIFFSmplChunk::GetSamplePoolSize() const { 73 | SFRIFFSmplChunk::size_type size = 0; 74 | for (const auto & sample : samples()) { 75 | size += sizeof(int16_t) * 76 | (sample->data().size() + SFSample::kTerminatorSampleLength); 77 | if (size > UINT32_MAX) { 78 | throw std::length_error("The sample pool size exceeds the maximum."); 79 | } 80 | } 81 | return size; 82 | } 83 | 84 | } // namespace sf2cute 85 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/riff_smpl_chunk.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont "smpl" RIFF chunk header 3 | /// 4 | /// @author gocha 5 | 6 | #ifndef SF2CUTE_RIFF_SMPL_CHUNK_HPP_ 7 | #define SF2CUTE_RIFF_SMPL_CHUNK_HPP_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "riff.hpp" 15 | 16 | namespace sf2cute { 17 | 18 | class SFSample; 19 | 20 | /// The SFRIFFSmplChunk class represents a SoundFont 2 "smpl" chunk. 21 | class SFRIFFSmplChunk : public RIFFChunkInterface { 22 | public: 23 | /// Unsigned integer type for the chunk size. 24 | using size_type = RIFFChunkInterface::size_type; 25 | 26 | /// Constructs a new empty SFRIFFSmplChunk. 27 | SFRIFFSmplChunk(); 28 | 29 | /// Constructs a new SFRIFFSmplChunk using the specified samples. 30 | /// @param samples The samples of the chunk. 31 | /// @throws std::length_error The sample pool size exceeds the maximum. 32 | SFRIFFSmplChunk(const std::vector> & samples); 33 | 34 | /// Constructs a new copy of specified SFRIFFSmplChunk. 35 | /// @param origin a SFRIFFSmplChunk object. 36 | SFRIFFSmplChunk(const SFRIFFSmplChunk & origin) = default; 37 | 38 | /// Copy-assigns a new value to the SFRIFFSmplChunk, replacing its current contents. 39 | /// @param origin a SFRIFFSmplChunk object. 40 | SFRIFFSmplChunk & operator=(const SFRIFFSmplChunk & origin) = default; 41 | 42 | /// Acquires the contents of specified SFRIFFSmplChunk. 43 | /// @param origin a SFRIFFSmplChunk object. 44 | SFRIFFSmplChunk(SFRIFFSmplChunk && origin) = default; 45 | 46 | /// Move-assigns a new value to the SFRIFFSmplChunk, replacing its current contents. 47 | /// @param origin a SFRIFFSmplChunk object. 48 | SFRIFFSmplChunk & operator=(SFRIFFSmplChunk && origin) = default; 49 | 50 | /// Destructs the SFRIFFSmplChunk. 51 | virtual ~SFRIFFSmplChunk() = default; 52 | 53 | /// @copydoc RIFFChunkInterface::name() 54 | virtual std::string name() const override { 55 | return "smpl"; 56 | } 57 | 58 | /// Returns the samples of this chunk. 59 | /// @return the samples of this chunk. 60 | const std::vector> & samples() const { 61 | return *samples_; 62 | } 63 | 64 | /// Sets the samples of this chunk. 65 | /// @param samples the samples of this chunk. 66 | /// @throws std::length_error The sample pool size exceeds the maximum. 67 | void set_samples(const std::vector> & samples) { 68 | samples_ = &samples; 69 | size_ = GetSamplePoolSize(); 70 | } 71 | 72 | /// Returns the whole length of this chunk. 73 | /// @return the length of this chunk including a chunk header, in terms of bytes. 74 | virtual size_type size() const noexcept override { 75 | return 8 + size_; 76 | } 77 | 78 | /// Writes this chunk to the specified output stream. 79 | /// @param out the output stream. 80 | /// @throws std::length_error The chunk size exceeds the maximum. 81 | /// @throws std::ios_base::failure An I/O error occurred. 82 | virtual void Write(std::ostream & out) const override; 83 | 84 | private: 85 | /// Returns the total sample pool size. 86 | /// @return the total sample pool size. 87 | /// @throws std::length_error The sample pool size exceeds the maximum. 88 | size_type GetSamplePoolSize() const; 89 | 90 | /// The size of the chunk (excluding header). 91 | size_type size_; 92 | 93 | /// The samples of the chunk. 94 | const std::vector> * samples_; 95 | }; 96 | 97 | } // namespace sf2cute 98 | 99 | #endif // SF2CUTE_RIFF_SMPL_CHUNK_HPP_ 100 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/sample.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont 2 Sample class implementation. 3 | /// 4 | /// @author gocha 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace sf2cute { 15 | 16 | /// Constructs a new empty SFSample. 17 | SFSample::SFSample() : 18 | start_loop_(0), 19 | end_loop_(0), 20 | sample_rate_(0), 21 | original_key_(0), 22 | correction_(0), 23 | link_(), 24 | type_(SFSampleLink::kMonoSample), 25 | parent_file_(nullptr) { 26 | } 27 | 28 | /// Constructs a new empty SFSample using the specified name. 29 | SFSample::SFSample(std::string name) : 30 | name_(std::move(name)), 31 | start_loop_(0), 32 | end_loop_(0), 33 | sample_rate_(0), 34 | original_key_(0), 35 | correction_(0), 36 | link_(), 37 | type_(SFSampleLink::kMonoSample), 38 | parent_file_(nullptr) { 39 | } 40 | 41 | /// Constructs a new SFSample. 42 | SFSample::SFSample(std::string name, 43 | std::vector data, 44 | uint32_t start_loop, 45 | uint32_t end_loop, 46 | uint32_t sample_rate, 47 | uint8_t original_key, 48 | int8_t correction) : 49 | name_(std::move(name)), 50 | data_(std::move(data)), 51 | start_loop_(std::move(start_loop)), 52 | end_loop_(std::move(end_loop)), 53 | sample_rate_(std::move(sample_rate)), 54 | original_key_(std::move(original_key)), 55 | correction_(std::move(correction)), 56 | link_(), 57 | type_(SFSampleLink::kMonoSample), 58 | parent_file_(nullptr) { 59 | } 60 | 61 | /// Constructs a new SFSample with a sample link. 62 | SFSample::SFSample(std::string name, 63 | std::vector data, 64 | uint32_t start_loop, 65 | uint32_t end_loop, 66 | uint32_t sample_rate, 67 | uint8_t original_key, 68 | int8_t correction, 69 | std::weak_ptr link, 70 | SFSampleLink type) : 71 | name_(std::move(name)), 72 | data_(std::move(data)), 73 | start_loop_(std::move(start_loop)), 74 | end_loop_(std::move(end_loop)), 75 | sample_rate_(std::move(sample_rate)), 76 | original_key_(std::move(original_key)), 77 | correction_(std::move(correction)), 78 | link_(std::move(link)), 79 | type_(std::move(type)), 80 | parent_file_(nullptr) { 81 | } 82 | 83 | /// Constructs a new copy of specified SFSample. 84 | SFSample::SFSample(const SFSample & origin) : 85 | name_(origin.name_), 86 | data_(origin.data_), 87 | start_loop_(origin.start_loop_), 88 | end_loop_(origin.end_loop_), 89 | sample_rate_(origin.sample_rate_), 90 | original_key_(origin.original_key_), 91 | correction_(origin.correction_), 92 | link_(origin.link_), 93 | type_(origin.type_), 94 | parent_file_(nullptr) { 95 | } 96 | 97 | /// Copy-assigns a new value to the SFSample, replacing its current contents. 98 | SFSample & SFSample::operator=(const SFSample & origin) { 99 | name_ = origin.name_; 100 | data_ = origin.data_; 101 | start_loop_ = origin.start_loop_; 102 | end_loop_ = origin.end_loop_; 103 | sample_rate_ = origin.sample_rate_; 104 | original_key_ = origin.original_key_; 105 | correction_ = origin.correction_; 106 | link_ = origin.link_; 107 | type_ = origin.type_; 108 | parent_file_ = nullptr; 109 | return *this; 110 | } 111 | 112 | } // namespace sf2cute 113 | -------------------------------------------------------------------------------- /src/sf2cute-0.2/src/sf2cute/zone.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// SoundFont 2 Zone class implemantation. 3 | /// 4 | /// @author gocha 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | namespace sf2cute { 17 | 18 | /// Constructs a new empty SFZone. 19 | SFZone::SFZone() { 20 | } 21 | 22 | /// Constructs a empty SFZone using the specified generators and modulators. 23 | SFZone::SFZone( 24 | std::vector generators, 25 | std::vector modulators) { 26 | // Set generators. 27 | generators_.reserve(generators.size()); 28 | for (auto && generator : generators) { 29 | SetGenerator(std::move(generator)); 30 | } 31 | 32 | // Set modulators. 33 | modulators_.reserve(modulators.size()); 34 | for (auto && modulator : modulators) { 35 | SetModulator(std::move(modulator)); 36 | } 37 | } 38 | 39 | /// Constructs a new copy of specified SFZone. 40 | SFZone::SFZone(const SFZone & origin) { 41 | // Copy generators. 42 | generators_.reserve(origin.generators().size()); 43 | for (const auto & generator : origin.generators()) { 44 | generators_.push_back(std::make_unique(*generator)); 45 | } 46 | 47 | // Copy modulators. 48 | modulators_.reserve(origin.modulators().size()); 49 | for (const auto & modulator : origin.modulators()) { 50 | modulators_.push_back(std::make_unique(*modulator)); 51 | } 52 | } 53 | 54 | /// Copy-assigns a new value to the SFZone, replacing its current contents. 55 | SFZone & SFZone::operator=(const SFZone & origin) { 56 | // Copy generators. 57 | generators_.clear(); 58 | generators_.reserve(origin.generators().size()); 59 | for (const auto & generator : origin.generators()) { 60 | generators_.push_back(std::make_unique(*generator)); 61 | } 62 | 63 | // Copy modulators. 64 | modulators_.clear(); 65 | modulators_.reserve(origin.modulators().size()); 66 | for (const auto & modulator : origin.modulators()) { 67 | modulators_.push_back(std::make_unique(*modulator)); 68 | } 69 | 70 | return *this; 71 | } 72 | 73 | /// Sets a generator to the zone. 74 | void SFZone::SetGenerator(SFGeneratorItem generator) { 75 | // Find the generator. 76 | const auto it = FindGenerator(generator.op()); 77 | if (it == generators_.end()) { 78 | generators_.push_back(std::make_unique(std::move(generator))); 79 | } 80 | else { 81 | const std::unique_ptr & old_generator = *it; 82 | *old_generator = std::move(generator); 83 | } 84 | } 85 | 86 | /// Finds the generator which is the specified type. 87 | const std::vector>::const_iterator 88 | SFZone::FindGenerator(SFGenerator op) const { 89 | return std::find_if(generators_.begin(), generators_.end(), 90 | [&op](const std::unique_ptr & generator) { 91 | return generator->op() == op; 92 | }); 93 | } 94 | 95 | /// Removes generators from the zone. 96 | void SFZone::RemoveGeneratorIf( 97 | std::function &)> predicate) { 98 | generators_.erase(std::remove_if(generators_.begin(), generators_.end(), 99 | [&predicate](const std::unique_ptr & generator) -> bool { 100 | if (predicate(generator)) { 101 | return true; 102 | } 103 | else { 104 | return false; 105 | } 106 | }), generators_.end()); 107 | } 108 | 109 | /// Sets a modulator to the zone. 110 | void SFZone::SetModulator(SFModulatorItem modulator) { 111 | // Find the modulator. 112 | const auto it = FindModulator(modulator.key()); 113 | if (it == modulators_.end()) { 114 | modulators_.push_back(std::make_unique(std::move(modulator))); 115 | } 116 | else { 117 | const std::unique_ptr & old_modulator = *it; 118 | *old_modulator = std::move(modulator); 119 | } 120 | } 121 | 122 | /// Finds the modulator which is the specified type. 123 | const std::vector>::const_iterator 124 | SFZone::FindModulator(SFModulatorKey key) const { 125 | return std::find_if(modulators_.begin(), modulators_.end(), 126 | [&key](const std::unique_ptr & modulator) { 127 | return modulator->key() == key; 128 | }); 129 | } 130 | 131 | /// Removes modulators from the zone. 132 | void SFZone::RemoveModulatorIf( 133 | std::function &)> predicate) { 134 | modulators_.erase(std::remove_if(modulators_.begin(), modulators_.end(), 135 | [&predicate](const std::unique_ptr & modulator) -> bool { 136 | if (predicate(modulator)) { 137 | return true; 138 | } 139 | else { 140 | return false; 141 | } 142 | }), modulators_.end()); 143 | } 144 | 145 | } // namespace sf2cute 146 | --------------------------------------------------------------------------------