├── FlacMyGame.bat ├── README.md ├── deltarune1+2.csv ├── flac.exe ├── lame.exe ├── oggdec.exe ├── oggenc2.exe ├── spectr.png ├── undertale.csv ├── wavedit.c └── wavedit.exe /FlacMyGame.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal disabledelayedexpansion 3 | setlocal 4 | rem (c) SoBiT 2019-2021 5 | set out=fmg_out 6 | set bkp=fmg_bkp 7 | set decode=flac:flac.exe:--totally-silent`-dfo`@fd@`@fs@:con,ogg:oggdec.exe:-qw`@fd@`@fs@:nul,mp3:lame.exe:--decode`--quiet`@fs@`@fd@:con,wav:@copy:/y`@fs@`@fd@:nul 8 | set encode=flac:flac.exe:@oqc@`-esfo`@fd@`@fs@:con,ogg:oggenc2.exe:@oqc@`-Qo`@fd@`@fs@:nul,mp3:lame.exe:@oqc@`@fs@`@fd@:con 9 | set edit=wavedit.exe 10 | set ftmp=~mmtmp.wav 11 | set tempdir=. 12 | set copybat=flacMyGame_install.bat 13 | set locase=for %%n in (1 2) do if %%n==2 ( for %%# in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do set "lcres=!lcres:%%#=%%#!") else set lcres= 14 | setlocal enableextensions enabledelayedexpansion 15 | 16 | set cfg= 17 | set select= 18 | set aexts= 19 | set bext= 20 | set bexts= 21 | set bdir= 22 | set bdirs= 23 | set bids= 24 | set aodir= 25 | set name= 26 | set updirchk= 27 | set title= 28 | set caption= 29 | set aname= 30 | set aprefix= 31 | set bname= 32 | set bprefix= 33 | set alook= 34 | set oname= 35 | set oprefix= 36 | set oext= 37 | set oq= 38 | set oqb= 39 | set editcmd= 40 | set ct=0 41 | set cto=0 42 | set ctn=0 43 | set obits=16 44 | if "%1"=="" goto load 45 | set select=%1 46 | if .%select:~0,1%==.- goto help 47 | if .%select:~0,1%==./ goto help 48 | if .%select:~0,4%==.help goto help 49 | if not .%select%==. ( 50 | set cfg=%1 51 | set select=%2 52 | if "!cfg:.csv=!"=="!cfg!" ( 53 | set cfg=!cfg!.csv 54 | ) 55 | ) 56 | goto load 57 | 58 | :help 59 | echo Usage: flacmygame [csv config file] [name of specific single music track to create] 60 | goto end 61 | 62 | :load 63 | echo flacMyGame v1.1.0 by SoBiT 64 | setlocal disabledelayedexpansion 65 | if "%cfg%"=="" ( 66 | for %%i in ("*.csv") do set cfg=%%~fi 67 | ) 68 | if "%cfg%"=="" ( 69 | echo No configuration file found! Make sure a .csv file exists in this folder. 70 | goto pause 71 | ) 72 | set cfg="%cfg:^=^^%" 73 | set cfg=%cfg:!=^!% 74 | endlocal & set cfg=%cfg% 75 | if not exist "!cfg!" ( 76 | echo Configuration file !cfg! does not exist^^! 77 | goto pause 78 | ) 79 | echo Loading configuration !cfg!... 80 | for /f "usebackq tokens=* delims=," %%i in (!cfg!) do ( 81 | set l=%%i 82 | set l=!l: =`! 83 | if "!l:~0,1!"=="$" goto loadok 84 | if not "!l:~0,1!"=="#" ( 85 | set n=0 86 | set op= 87 | for %%j in ("!l:,="^,"!") do ( 88 | set v=%%j 89 | set v=!v:"=! 90 | if !n!==0 ( 91 | set op=!v! 92 | ) else if not .!v!==. ( 93 | if !op!==0 ( 94 | if !n!==1 set name=!v! 95 | if !n!==2 set updirchk=!v! 96 | if !n!==3 set title=!v! 97 | if !n!==4 set caption=!v! 98 | ) 99 | if !op!==1 ( 100 | if !n! GTR 2 ( set aexts=!aexts!,!v! 101 | ) else ( 102 | if !n!==1 set aname=!v! 103 | if !n!==2 set aprefix=!v! 104 | ) 105 | ) 106 | if !op!==2 ( 107 | if !n! GTR 2 ( set bexts=!bexts!,!v! 108 | ) else ( 109 | if !n!==1 set bname=!v! 110 | if !n!==2 set bprefix=!v! 111 | ) 112 | ) 113 | if !op!==3 ( 114 | if !n!==1 set oname=!v! 115 | if !n!==2 set oprefix=!v! 116 | if !n!==3 set oext=!v! 117 | if !n!==4 set oq=!v:`= ! 118 | if !n!==5 set oqb=!v:`= ! 119 | if !n!==6 set obits=!v! 120 | ) 121 | if !op!==4 set alook=!alook! "!v!" 122 | ) 123 | set /a n+=1 124 | ) 125 | ) 126 | ) 127 | 128 | :loadok 129 | if "%title%"=="" ( 130 | echo [ERR] Configuration file is malformed^^! 131 | goto pause 132 | ) 133 | color 0a 134 | set aname=!aname:`= ! 135 | set bname=!bname:`= ! 136 | set oname=!oname:`= ! 137 | if not "%alook%"=="" set alook=!alook:`= ! 138 | set aexts=!aexts:~1! 139 | set bexts=!bexts:~1! 140 | for %%i in (%decode%) do ( 141 | set l=%%i 142 | for /f "tokens=1-4 delims=:" %%a in ("!l:`= !") do ( 143 | set m=%%b 144 | set decpar%%a=%%c 145 | set decprn%%a=%%d 146 | set decct%%a=0 147 | if not "!m:@=!"=="%%b" ( 148 | set decmd%%a=!m:~1! 149 | set decnm%%a=!m:~1! 150 | ) else ( 151 | set decmd%%a= 152 | set decnm%%a=!m! 153 | for %%j in (.. .) do ( 154 | if exist %%j\%%b ( 155 | setlocal disabledelayedexpansion 156 | for /f "delims=" %%f in ("%%j\%%b") do set decmd%%a="%%~ff" 157 | setlocal enabledelayedexpansion 158 | ) 159 | ) 160 | ) 161 | ) 162 | ) 163 | for %%i in (%encode%) do ( 164 | set l=%%i 165 | for /f "tokens=1-4 delims=:" %%a in ("!l:`= !") do ( 166 | set m=%%b 167 | set encpar%%a=%%c 168 | set encprn%%a=%%d 169 | if not "!m:@=!"=="%%b" ( 170 | set encmd%%a=!m:~1! 171 | set encnm%%a=!m:~1! 172 | ) else ( 173 | set encmd%%a= 174 | set encnm%%a=!m! 175 | for %%j in (.. .) do ( 176 | if exist %%j\%%b ( 177 | setlocal disabledelayedexpansion 178 | for /f "delims=" %%f in ("%%j\%%b") do set encmd%%a="%%~ff" 179 | setlocal enabledelayedexpansion 180 | ) 181 | ) 182 | ) 183 | ) 184 | ) 185 | setlocal disabledelayedexpansion 186 | for %%i in (.. .) do ( 187 | if exist %%i\%edit% ( 188 | for /f "delims=" %%f in ("%%i\%edit%") do set editcmd="%%~ff" 189 | ) 190 | ) 191 | for /f "delims=" %%F in ("%tempdir%") do set atdir=%%~fF 192 | for /f "delims=" %%F in ("%out%") do set aodir=%%~fF 193 | setlocal enabledelayedexpansion 194 | if "!atdir:~-1!"=="\" set atdir=!atdir:~,-1! 195 | if "!aodir:~-1!"=="\" set aodir=!aodir:~,-1! 196 | del /q /f !atdir!\1!ftmp! >nul 2>&1 197 | del /q /f !atdir!\2!ftmp! >nul 2>&1 198 | del /q /f !atdir!\3!ftmp! >nul 2>&1 199 | set m=0 200 | set nbids=0 201 | for /f "usebackq tokens=* delims=," %%i in (!cfg!) do ( 202 | set l=%%i 203 | set l=!l: =`! 204 | set t= 205 | set op= 206 | if !m!==1 if not "!l:~0,1!"=="#" ( 207 | set n=0 208 | if "!l:~0,1!"=="$" goto load2 209 | for %%j in ("!l:,="^,"!") do ( 210 | set v=%%j 211 | set v=!v:"=! 212 | if !n! GTR 2 ( 213 | if not "!v!"=="" set v=!v:`= ! 214 | set t=!t!,!v! 215 | ) else ( 216 | if !n!==0 ( 217 | set op=!v! 218 | set bids=!bids!,!v! 219 | set bdir!op!= 220 | set ct!op!=0 221 | set ctn!op!=0 222 | ) 223 | if !n!==1 set bname!op!=!v:`= ! 224 | if !n!==2 set bsr!op!=!v! 225 | ) 226 | set /a n+=1 227 | ) 228 | set bdirs!op!=!t:~1! 229 | set /a nbids+=1 230 | ) 231 | if "!l:~0,1!"=="$" set /a m=m+1 232 | ) 233 | 234 | :load2 235 | set bids=!bids:~1! 236 | set tb= 237 | set m=0 238 | for /f "usebackq tokens=* delims=," %%i in (!cfg!) do ( 239 | set l=%%i 240 | set l=!l: =`! 241 | if !m!==2 if not "!l:~0,1!"=="#" ( 242 | if "!l:~0,1!"=="$" goto ready 243 | set n=0 244 | set bn=0 245 | set na=-1 246 | set /a cto+=1 247 | for %%j in ("!l:,="^,"!") do ( 248 | set v=%%j 249 | set v=!v:"=! 250 | if !na! GEQ 0 ( 251 | if !na!==0 ( 252 | if !v!==1 set /a na=-1 253 | if !v!==5 set /a na=-1 254 | if not !na! GEQ 0 ( 255 | call :findtrk "" !ta! 256 | if .!ftres!==. ( 257 | set /a ctn+=1 258 | ) else ( 259 | set /a ct+=1 260 | set /a decct!ftx!+=1 261 | ) 262 | ) 263 | ) 264 | if !na! GEQ 0 set /a na+=1 265 | set /a na%%=4 266 | ) else ( 267 | if !n!==0 ( 268 | set ta=!v! 269 | if not .!select!==. if /i not !select!==!v! set n=8 270 | ) 271 | if !n!==1 ( 272 | if !nbids! LEQ 1 ( 273 | set tc=0 274 | set /a n+=1 275 | ) else set tc=!v! 276 | ) 277 | if !n!==2 if not !tb!==!tc!!v! ( 278 | set tb=!tc!!v! 279 | call :findtrk !tc! !v! 280 | if .!ftres!==. ( 281 | set /a ctn!tc!+=1 282 | ) else ( 283 | set tc=!ftc! 284 | set /a ct!tc!+=1 285 | set /a decct!ftx!+=1 286 | ) 287 | ) 288 | if !n!==7 set /a na=0 289 | ) 290 | set /a n+=1 291 | ) 292 | ) 293 | if "!l:~0,1!"=="$" set /a m=m+1 294 | ) 295 | 296 | :ready 297 | set cta=0 298 | set ctna=0 299 | for %%m in (%bids%) do ( 300 | set /a cta=cta+!ct%%m! 301 | set /a ctna=ctna+!ctn%%m! 302 | ) 303 | rem echo !ct! !ct0! !ct1! !ct2! !ct9! :: !ctn! !ctn0! !ctn1! !ctn2! !ctn9! :: !cta! !ctna! !cto! :: !decctflac! !decctogg! !decctmp3! !decctwav! 304 | echo. 305 | echo !title:`= ! 306 | echo !caption:`= ! 307 | echo. 308 | if !cta!==0 ( 309 | if not .!select!==. ( 310 | echo [ERR] The given .csv file has no instructions for making !select!^^! 311 | echo. Please check your command-line arguments. 312 | ) else echo [ERR] !bname! ^(!bprefix!*.{!bexts!}^) not found^^! 313 | goto pause 314 | ) 315 | if !ct!==0 if not !ctn!==0 echo [WARN] !aname! ^(!aprefix!*.{!aexts!}^) not found^^! Result will sound incorrect^^! 316 | echo Using !cta! of the following !bname!: 317 | for %%m in (%bids%) do ( 318 | if not !ct%%m!==0 ( 319 | set e=!bext%%m! 320 | for %%e in (!e!) do ( 321 | echo. !ct%%m! !bname%%m! in !bdir%%m:"=!\!bprefix!*.%%e with !decnm%%e! 322 | ) 323 | ) 324 | ) 325 | echo. 326 | if not !ct!==0 ( 327 | echo Using !ct! !aname! in !bdir:"=!\!aprefix!*.!bext! with !decnm%bext%! 328 | echo. 329 | ) 330 | echo Write !cto! !oname! to !aodir!\!oprefix!*.!oext! with !encnm%oext%! quality !oq! 331 | echo. 332 | echo Using !atdir!\ as temporary directory 333 | echo. 334 | for %%i in (%decode%) do ( 335 | for /f "tokens=1-2 delims=:" %%a in ("%%i") do ( 336 | if not !decct%%a!==0 if .!decmd%%a!==. ( 337 | echo [ERR] Decoder %%b not found^^! 338 | goto download 339 | ) 340 | ) 341 | ) 342 | if .!encmd%oext%!==. ( 343 | echo [ERR] Encoder !encnm%oext%! not found^^! 344 | goto download 345 | ) 346 | if .!editcmd!==. ( 347 | echo [ERR] WAV editor !edit! not found^^! 348 | goto download 349 | ) 350 | if not !ctna!==0 ( 351 | echo [WARN] !ctna! of !cto! required !bname! not found: 352 | for %%m in (%bids%) do ( 353 | if not !ctn%%m!==0 ( 354 | echo. Missing !ctn%%m! !bname%%m! !bname!^^! 355 | ) 356 | ) 357 | ) 358 | if not !ctn!==0 ( 359 | set /a ctx=ctn+ct 360 | echo [WARN] !ctn! of !ctx! required !aname! not found^^! 361 | ) 362 | if not exist "!aodir!\" mkdir "!aodir!" 363 | if not exist "!aodir!\" ( 364 | echo [ERR] Can't create output directory !aodir! 365 | goto end 366 | ) 367 | if not exist "!atdir!\" ( 368 | echo [ERR] Temp. directory doesn't exist: !atdir!\ 369 | goto end 370 | ) 371 | echo. 372 | if "!select!"=="" ( 373 | echo Ready^^! Please verify the above info is correct. 374 | pause 375 | ) 376 | 377 | echo. 378 | set k=0 379 | set m=0 380 | set ta= 381 | set tb= 382 | for /f "usebackq tokens=* delims=," %%i in (!cfg!) do ( 383 | set l=%%i 384 | set l=!l: =`! 385 | if !m!==2 if not "!l:~0,1!"=="#" ( 386 | for %%k in (0 1) do ( 387 | if !k!==1 ( 388 | if not !na! GEQ 0 call :convinit 389 | rem !editcmd! resample "!atdir!\2!ftmp!" !sr! 390 | set fs="!atdir!\2!ftmp!" 391 | set fd="!aodir!\!oprefix!!ta:\=@!.!oext!" 392 | set tcmd=!encmd%oext%! 393 | set tpar=!encpar%oext%! 394 | set tprn=!encprn%oext%! 395 | set oqc=!oq! 396 | if %%k==1 set oqc=!oqb! 397 | call :runcmd 398 | for %%i in (!fd!) do ( 399 | if %%~zi==0 del /q /f !fd! >nul 2>&1 400 | ) 401 | if not exist !fd! ( 402 | if %%k==1 echo [ERR] Error encoding !oname:~,-1! !fd! 403 | ) else set k=0 404 | ) 405 | ) 406 | del /q /f "!atdir!\2!ftmp!" >nul 2>&1 407 | del /q /f "!atdir!\3!ftmp!" >nul 2>&1 408 | if "!l:~0,1!"=="$" goto convdone 409 | set n=0 410 | set na=-1 411 | set k=0 412 | set k2=0 413 | set wsrate=100 414 | set wamp=0 415 | set wstart=0 416 | set wlen=0 417 | for %%j in ("!l:,="^,"!") do ( 418 | set v=%%j 419 | set v=!v:"=! 420 | if !na! GEQ 0 ( 421 | if !na!==0 set weop=!v! 422 | if !na!==1 set wesrc=!v! 423 | if !na!==2 set wedst=!v! 424 | if !na!==3 ( 425 | set welen=!v! 426 | if !k2!==0 ( 427 | if !weop!==1 set k2=1 428 | if !weop!==5 set k2=1 429 | ) 430 | if !k2!==1 ( 431 | set k2=2 432 | call :findtrk "" !ta! 433 | if .!ftres!==. ( 434 | echo [WARN] !aname:~,-1! !ta! ^(!aprefix!*.{!aexts!}^) NOT FOUND^^! Result may sound incorrect^^! 435 | set n=8 436 | ) else ( 437 | set fs=!ftres! 438 | set fd="!atdir!\3!ftmp!" 439 | set tcmd=!decmd%bext%! 440 | set tpar=!decpar%bext%! 441 | set tprn=!decprn%bext%! 442 | call :runcmd 443 | for %%i in ("!atdir!\3!ftmp!") do ( 444 | if %%~zi==0 del /q /f "!atdir!\3!ftmp!" >nul 2>&1 445 | ) 446 | if not exist "!atdir!\3!ftmp!" echo [WARN] Error decoding !aname:~,-1! !fs! ^^! Result may sound incorrect^^! 447 | attrib -r "!atdir!\3!ftmp!" 448 | !editcmd! bitdepth "!atdir!\3!ftmp!" !obits! 449 | !editcmd! resample "!atdir!\3!ftmp!" !sr! 450 | ) 451 | ) 452 | if !weop!==1 !editcmd! copyext "!atdir!\2!ftmp!" "!atdir!\3!ftmp!" !wesrc! !wedst! !welen! .01 453 | if !weop!==3 !editcmd! copy "!atdir!\2!ftmp!" !wesrc! !wedst! !welen! .01 454 | if !weop!==7 !editcmd! rol "!atdir!\2!ftmp!" !wedst! !wesrc! !welen! 455 | if !weop!==8 !editcmd! ror "!atdir!\2!ftmp!" !wedst! !wesrc! !welen! 456 | if !weop!==5 ( 457 | if !k2!==2 ( 458 | set k2=3 459 | !editcmd! resamp "!atdir!\3!ftmp!" -!wsrate!%% 460 | ) 461 | !editcmd! copyext "!atdir!\2!ftmp!" "!atdir!\3!ftmp!" !wesrc! !wedst! !welen! .01 462 | ) 463 | ) 464 | if !na! GEQ 0 set /a na+=1 465 | set /a na%%=4 466 | ) else ( 467 | if !n!==0 ( 468 | set ta=!v! 469 | if not .!select!==. if /i not !select!==!v! ( 470 | set n=8 471 | set k=0 472 | ) 473 | ) 474 | if !n!==1 ( 475 | if !nbids! LEQ 1 ( 476 | set tc=0 477 | set /a n+=1 478 | ) else set tc=!v! 479 | ) 480 | if !n!==2 ( 481 | set tb=!tc!!v! 482 | for %%c in (!tc!) do ( 483 | set sr=!bsr%%c! 484 | ) 485 | del /q /f "!atdir!\1!ftmp!" >nul 2>&1 486 | call :findtrk !tc! !v! 487 | if .!ftres!==. ( 488 | for %%c in (!tc!) do ( 489 | echo [ERR] Track !v! of !bname%%e! !bname! ^(!bprefix!*.{!bexts!}^) NOT FOUND^^! 490 | ) 491 | set n=8 492 | ) else ( 493 | set tc=!ftc! 494 | set fs=!ftres! 495 | set fd="!atdir!\1!ftmp!" 496 | for %%c in (!tc!) do ( 497 | for %%e in (!bext%%c!) do ( 498 | set tcmd=!decmd%%e! 499 | set tpar=!decpar%%e! 500 | set tprn=!decprn%%e! 501 | ) 502 | ) 503 | call :runcmd 504 | for %%i in ("!atdir!\1!ftmp!") do ( 505 | if %%~zi==0 del /q /f "!atdir!\1!ftmp!" >nul 2>&1 506 | ) 507 | if not exist "!atdir!\1!ftmp!" ( 508 | echo [ERR] Error decoding !bname:~,-1! !fs! ^^! 509 | set n=8 510 | set tb= 511 | ) else set k=1 512 | ) 513 | ) 514 | if !n!==3 set wsrate=!v! 515 | if !n!==4 set wamp=!v! 516 | if !n!==5 set wstart=!v! 517 | if !n!==6 set wlen=!v! 518 | if !n!==7 call :convinit 519 | ) 520 | set /a n+=1 521 | ) 522 | ) 523 | if "!l:~0,1!"=="$" set /a m=m+1 524 | ) 525 | goto convdone 526 | :convinit 527 | echo Generating !oprefix!!ta!.!oext!... 528 | attrib -r "!atdir!\1!ftmp!" 529 | !editcmd! bitdepth "!atdir!\1!ftmp!" !obits! 530 | !editcmd! resample "!atdir!\1!ftmp!" !sr! 531 | del /q /f "!atdir!\2!ftmp!" >nul 2>&1 532 | copy /y "!atdir!\1!ftmp!" "!atdir!\2!ftmp!" >nul 533 | attrib -r "!atdir!\2!ftmp!" 534 | !editcmd! crop "!atdir!\2!ftmp!" !wstart! !wlen! 535 | !editcmd! amp "!atdir!\2!ftmp!" !wamp! 536 | !editcmd! setsamp "!atdir!\2!ftmp!" -!wsrate!%% 537 | set na=0 538 | goto end 539 | :runcmd 540 | set tpar=%tpar:@=^^!% 541 | set tpar=%tpar% 542 | setlocal disabledelayedexpansion 543 | set tpar=%tpar:?=!% 544 | %tcmd% %tpar% >%tprn% 2>&1 545 | endlocal 546 | goto end 547 | 548 | 549 | :convdone 550 | del /q /f "!atdir!\1!ftmp!" >nul 2>&1 551 | del /q /f "!atdir!\2!ftmp!" >nul 2>&1 552 | del /q /f "!atdir!\3!ftmp!" >nul 2>&1 553 | if not .!select!==. goto end 554 | set j=!copybat! 555 | set copybat=!aodir!\!copybat! 556 | echo @echo off>!copybat! 557 | echo setlocal enableextensions disabledelayedexpansion>>!copybat! 558 | echo rem Moves !oname! into !name! directory after making a backup>>!copybat! 559 | echo rem (c) SBT 2019>>!copybat! 560 | echo set ccdir=.>>!copybat! 561 | echo for /f "delims=" %%%%F in ("%%ccdir%%") do set ccdir=%%%%~fF>>!copybat! 562 | echo for %%%%i in (.. ..\.. ..\..\..) do (>>!copybat! 563 | echo if exist "%%ccdir%%\%%%%i\!updirchk!" (>>!copybat! 564 | echo for /f "delims=" %%%%F in ("%%ccdir%%\%%%%i") do set cgdir=%%%%~fF>>!copybat! 565 | echo ))>>!copybat! 566 | echo if not exist "%%cgdir%%\!updirchk!" (>>!copybat! 567 | echo echo This program must be run from a subfolder inside your !name! directory^^!>>!copybat! 568 | echo echo ^^^^(..\!updirchk! not found^^^^)>>!copybat! 569 | echo goto end>>!copybat! 570 | echo )>>!copybat! 571 | echo set cbdir="%%cgdir%%\!bkp!">>!copybat! 572 | echo for /f "delims=" %%%%F in (%%cbdir%%) do set cbdir=%%%%~fF>>!copybat! 573 | echo if not exist "%%ccdir%%\!oprefix!*.!oext!" (>>!copybat! 574 | echo echo Nothing to do.>>!copybat! 575 | echo echo ^^^^("%%ccdir%%\!oprefix!*.!oext!" not found^^^^)>>!copybat! 576 | echo goto end>>!copybat! 577 | echo )>>!copybat! 578 | echo if exist "%%cbdir%%\!oprefix!*.!oext!" (>>!copybat! 579 | echo echo Backup folder is not empty^^!>>!copybat! 580 | echo echo Please make sure there's nothing important in it, empty it and try again^^!>>!copybat! 581 | echo echo ^^^^("%%cbdir%%\!oprefix!*.!oext!" already exist^^^^)>>!copybat! 582 | echo goto end>>!copybat! 583 | echo )>>!copybat! 584 | echo setlocal enabledelayedexpansion>>!copybat! 585 | echo echo.>>!copybat! 586 | echo echo Ready to move !oname! into !name! directory.>>!copybat! 587 | echo echo A backup will first be created of any files that will be replaced.>>!copybat! 588 | echo echo.>>!copybat! 589 | echo echo Moving from: ^^!ccdir^^!\!oprefix!*.!oext!>>!copybat! 590 | echo echo Moving to: ^^!cgdir^^!\!aprefix!*.!oext!>>!copybat! 591 | echo echo Backing up existing files in: ^^!cbdir^^!\>>!copybat! 592 | echo echo.>>!copybat! 593 | echo pause>>!copybat! 594 | echo if not exist "^!cbdir^!\" mkdir "^!cbdir^!">>!copybat! 595 | echo if not exist "^!cbdir^!\" (>>!copybat! 596 | echo echo Can't create backup directory ^^!cbdir^^!>>!copybat! 597 | echo goto end>>!copybat! 598 | echo )>>!copybat! 599 | echo for %%%%i in ("^!ccdir^!\!oprefix!*.!oext!") do (>>!copybat! 600 | echo set fn=?!aprefix!%%%%~ni.!oext!>>!copybat! 601 | echo set fn=^^!fn:?%oprefix%=^^!>>!copybat! 602 | echo set fn=^^!fn:@=\^^!>>!copybat! 603 | echo move /y "^!cgdir^!\^!fn^!" "^!cbdir^!\%%%%~ni.!oext!" ^>nul 2^>^&^1>>!copybat! 604 | echo setlocal disabledelayedexpansion>>!copybat! 605 | echo set op=move /y "%%%%~fi">>!copybat! 606 | echo setlocal enabledelayedexpansion>>!copybat! 607 | echo ^^!op^^! "^!cgdir^!\^!fn^!" ^>nul>>!copybat! 608 | echo endlocal ^& endlocal>>!copybat! 609 | echo )>>!copybat! 610 | echo echo.>>!copybat! 611 | echo echo Finished^^^^^^^^^^!>>!copybat! 612 | echo :end>>!copybat! 613 | echo pause>>!copybat! 614 | echo. 615 | echo. 616 | if not exist ..\!updirchk! ( 617 | echo The !oname! are ready. 618 | echo Copy the folder !aodir! 619 | echo into your !name! directory and run !j! 620 | echo to activate the !oname!. 621 | echo. 622 | echo The !aname! will be backed up automatically. 623 | echo. 624 | goto pause 625 | ) 626 | cd !aodir! 627 | !copybat! 628 | goto end 629 | 630 | 631 | 632 | :findtrk 633 | set ftres= 634 | set ftc=%1 635 | set ftc=%ftc:"=% 636 | if .%mmdebug%==.. echo FT: %1 ^| %2 ^| %3 = !bdir%ftc%! ^| !bext%ftc%! ^| !bdirs%ftc%! 637 | 638 | if .!bdir%ftc%!==."?" ( 639 | if .%ftc% ==.0 goto end 640 | if .%ftc%==. goto end 641 | call :findtrk 0 %2 %1 642 | goto end 643 | ) 644 | if .!bdir%ftc%!==. ( 645 | call :finddir %ftc% 646 | goto findtrk 647 | ) 648 | set e=!bext%ftc%! 649 | set ftk=%bprefix% 650 | if .%ftc%==. ( 651 | set ftk=%aprefix% 652 | ) 653 | set p=!bdir%ftc%! 654 | set p=!p:"=!\%ftk% 655 | if .%ftc%==.0 if not .%3==. set p=!p!*%3 656 | setlocal disabledelayedexpansion 657 | set n= 658 | set /a n=%2 659 | if not .%n%==.%2 set n= 660 | if .%n%==. ( 661 | if exist "%p%%2.%e%" set ftres="%p%%2.%e%" 662 | goto findtrke 663 | ) 664 | if .%ftc%==.0 if .%ftres%==. for %%i in ("%p%00%n% - *%e%") do set ftres="%%~fi" 665 | if .%ftc%==.0 if .%ftres%==. for %%i in ("%p%0%n% - *%e%") do set ftres="%%~fi" 666 | if .%ftc%==.0 if .%ftres%==. for %%i in ("%p%%n% - *%e%") do set ftres="%%~fi" 667 | if .%ftc%==.0 if .%ftres%==. for %%i in ("%p%00%n%-*%e%") do set ftres="%%~fi" 668 | if .%ftc%==.0 if .%ftres%==. for %%i in ("%p%0%n%-*%e%") do set ftres="%%~fi" 669 | if .%ftc%==.0 if .%ftres%==. for %%i in ("%p%%n%-*%e%") do set ftres="%%~fi" 670 | if .%ftc%==.0 if .%ftres%==. for %%i in ("%p%00%n%. *%e%") do set ftres="%%~fi" 671 | if .%ftc%==.0 if .%ftres%==. for %%i in ("%p%0%n%. *%e%") do set ftres="%%~fi" 672 | if .%ftc%==.0 if .%ftres%==. for %%i in ("%p%%n%. *%e%") do set ftres="%%~fi" 673 | if .%ftc%==.0 if .%ftres%==. for %%i in ("%p%00%n%.*%e%") do set ftres="%%~fi" 674 | if .%ftc%==.0 if .%ftres%==. for %%i in ("%p%0%n%.*%e%") do set ftres="%%~fi" 675 | if .%ftc%==.0 if .%ftres%==. for %%i in ("%p%%n%.*%e%") do set ftres="%%~fi" 676 | if .%ftc%==.0 if .%ftres%==. for %%i in ("%p%00%n% *%e%") do set ftres="%%~fi" 677 | if .%ftc%==.0 if .%ftres%==. for %%i in ("%p%0%n% *%e%") do set ftres="%%~fi" 678 | if .%ftc%==.0 if .%ftres%==. for %%i in ("%p%%n% *%e%") do set ftres="%%~fi" 679 | if .%ftc%==.0 if .%ftres%==. for %%i in ("%p%*%n%*%e%") do set ftres="%%~fi" 680 | if .%ftres%==. for %%i in ("%p%*00%n% - *%e%") do set ftres="%%~fi" 681 | if .%ftres%==. for %%i in ("%p%*0%n% - *%e%") do set ftres="%%~fi" 682 | if .%ftres%==. for %%i in ("%p%*%n% - *%e%") do set ftres="%%~fi" 683 | if .%ftres%==. for %%i in ("%p%*00%n%-*%e%") do set ftres="%%~fi" 684 | if .%ftres%==. for %%i in ("%p%*0%n%-*%e%") do set ftres="%%~fi" 685 | if .%ftres%==. for %%i in ("%p%*%n%-*%e%") do set ftres="%%~fi" 686 | if .%ftres%==. for %%i in ("%p%*00%n%. *%e%") do set ftres="%%~fi" 687 | if .%ftres%==. for %%i in ("%p%*0%n%. *%e%") do set ftres="%%~fi" 688 | if .%ftres%==. for %%i in ("%p%*%n%. *%e%") do set ftres="%%~fi" 689 | if .%ftres%==. for %%i in ("%p%*00%n%.*%e%") do set ftres="%%~fi" 690 | if .%ftres%==. for %%i in ("%p%*0%n%.*%e%") do set ftres="%%~fi" 691 | if .%ftres%==. for %%i in ("%p%*%n%.*%e%") do set ftres="%%~fi" 692 | if .%ftres%==. for %%i in ("%p%* 0%n% *%e%") do set ftres="%%~fi" 693 | if .%ftres%==. for %%i in ("%p%*00%n% *%e%") do set ftres="%%~fi" 694 | if .%ftres%==. for %%i in ("%p%*0%n% *%e%") do set ftres="%%~fi" 695 | if .%ftres%==. for %%i in ("%p%* %n% *%e%") do set ftres="%%~fi" 696 | if .%ftres%==. for %%i in ("%p%* 0%n%*%e%") do set ftres="%%~fi" 697 | if .%ftres%==. for %%i in ("%p%*-0%n%*%e%") do set ftres="%%~fi" 698 | if .%ftres%==. for %%i in ("%p%*-%n%*%e%") do set ftres="%%~fi" 699 | if .%ftres%==. for %%i in ("%p%*%n% *%e%") do set ftres="%%~fi" 700 | if .%ftres%==. for %%i in ("%p%* %n%*%e%") do set ftres="%%~fi" 701 | if .%ftres%==. for %%i in ("%p%*%n%*%e%") do set ftres="%%~fi" 702 | :findtrke 703 | if not .%ftres%==. ( 704 | for %%i in (%ftres%) do set ftx=%%~xi 705 | set ftres=%ftres:^=^^% 706 | set ftres=%ftres:!=?% 707 | ) 708 | endlocal & set ftres=%ftres%& set ftx=%ftx% 709 | if not .%ftres%==. ( 710 | %locase%!ftx:~1! 711 | set ftx=!lcres! 712 | ) 713 | if .%mmdebug%==.. echo FTRES :: %ftres% : %ftx% 714 | goto end 715 | 716 | :finddir 717 | if .%mmdebug%==.. echo FD: %1 ^| %2 ^| %3 ^| %4 ^| %5 ^| %6 718 | 719 | set e=%bexts% 720 | set p=%bprefix% 721 | if .%1==. ( 722 | set e=%aexts% 723 | set p=%aprefix% 724 | ) 725 | set fdt=. 726 | set fdr= 727 | if not .!bdirs%1!==. set fdt="!bdirs%1:,=" "!" 728 | for %%i in (%e%) do ( 729 | for %%j in (!fdt!) do ( 730 | for /f "tokens=*" %%x in ("%%j") do ( 731 | for %%k in ("." ".." "..\.." %alook%) do ( 732 | for /f "tokens=*" %%y in (%%k) do ( 733 | set fdk=%%y\*%%x* 734 | set fdk="!fdk:"=!" 735 | if .%%j==.. set fdk=!fdk! %%y\. 736 | for /d %%l in (!fdk!) do ( 737 | if .%mmdebug%==.. echo SSS %%i ^| %%j ^| %%k ^| %%l == !fdk!: %%l\%p%*.%%i" 738 | echo "%%l"|findstr /i %%x >nul && ( 739 | setlocal disabledelayedexpansion 740 | if exist %%l\%p%*.%%i ( 741 | endlocal 742 | set u= 743 | set d=%%~fl 744 | for %%m in (%bids%) do ( 745 | if .!bdir%%m!==.!d! set u=1 746 | ) 747 | if .!bdir!==.!d! set u=1 748 | if .!u!==. ( 749 | set bext%1=%%i 750 | setlocal disabledelayedexpansion 751 | set fdr=%%~fl 752 | goto finddire 753 | ) 754 | ) else endlocal 755 | ) 756 | ) 757 | )) 758 | )) 759 | ) 760 | setlocal disabledelayedexpansion 761 | set fdr=? 762 | :finddire 763 | set fdr="%fdr:^=^^%" 764 | set fdr=%fdr:!=^!% 765 | endlocal & set bdir%1=%fdr% 766 | goto end 767 | 768 | :download 769 | echo. Please download the latest release - this file is included. 770 | echo. Visit github.com/sobitcorp/flacmygame 771 | echo. 772 | :pause 773 | pause 774 | goto end 775 | 776 | 777 | goto end 778 | 779 | :end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FlacMyGame - lossless game music patcher 2 | 3 | **Upgrade low-quality game music with lossless music from the OST!** 4 | 5 | **Compatible games:** 6 | * Undertale (any version) 7 | * Deltarune Chapter 1&2 8 | 9 | ![Comparison](/spectr.png) 10 | 11 | **Requirements:** 12 | * A compatible game 13 | * The game's Original Soundtrack (flac or mp3) 14 | 15 | **Installation:** 16 | 1. Download the latest release: 17 | * [[For Undertale](https://github.com/sobitcorp/FlacMyGame/releases/download/v1.1.0/FlacMyGame-v1.1.0-Undertale.zip)] 18 | * [[For Deltarune Chapter 1&2](https://github.com/sobitcorp/FlacMyGame/releases/download/v1.1.0/FlacMyGame-v1.1.0-DeltaruneCh1+2.zip)] 19 | 2. Extract into a new folder in your Undertale or Deltarune directory *(e.g. `C:\Undertale\flacmygame` if Undertale is in `C:\Undertale` )* 20 | 3. Prepare the Original Soundtrack. 21 | * Undertale: 22 | * If the OST is included with your game (as in the Steam version), make sure it is still in your Undertale directory and named either `Undertale soundtrack` or `ost` (case-insensitive). 23 | * Otherwise, make a copy of the soundtrack in the `flacmygame` folder *(e.g. `C:\Undertale\flacmygame\ost`)*. 24 | * Deltarune Chapter 1&2: 25 | * Copy both the Chapter 1 OST and Chapter 2 OST into the `flacmygame` folder. 26 | * Optionally copy the Undertale OST there as well (you only miss out on `gameover_short.ogg` otherwise). 27 | 4. Run `FlacMyGame.bat`. 28 | 29 | The program will generate game-compatible near-lossless music tracks using OST music and some stock game music to fill the gaps. 30 | No changes will be made to your game directory without first prompting you. 31 | 32 | # Issues 33 | 34 | Many of the OST music tracks differ quite a bit from the in-game versions. 35 | There are differing cuts, volume levels, fade in/outs, even some pitch differences. 36 | A lot of effort went into reversing or covering up all these differences to have the generated music match up with the stock music. 37 | Some noticeable looping errors in the stock game music have also been fixed. 38 | 39 | **Undertale** 40 | 41 | The following 22 tracks cannot be 100% recovered from the OST, so some (rather short) bits are taken from the stock in-game music: 42 | `ruins, undynescary, birdsong, mettmusical1, mettmusical2, mettmusical3, sansdate, coretransition, endarea_parta, endarea_partb, f_part1, f_part2, f_part3, f_6s_2, f_6s_4, f_6s_5, f_finale_1_l, f_finale_2, xpart_a, cast_2, cast_4, cast_6` 43 | 44 | The following 5 tracks differ too greatly in the OST to be replaceable: 45 | `toriel, leave, napstachords, oogloop, piano` 46 | 47 | The following 14 tracks do not exist in the OST: 48 | `dance_of_dog, dogshrine_1, dogshrine_2, f_finale_1, kingdescription, menu1, menu2, menu3, menu4, menu5, predummy, ruinspiano, st_him, star` 49 | 50 | There are also 69 non-music effect and ambient sounds that do not exist in the OST. 51 | 52 | **Deltarune Chapter 1&2** 53 | 54 | The following 8 tracks cannot be 100% recovered from the OST, so some (rather short) bits are taken from the stock in-game music: 55 | `creepydoor, forest, hip_shop, prejoker, cyber_battle_end, berdly_theme, giant_queen_appears, spamton_neo_mix_ex_wip` 56 | 57 | The following 3 tracks differ too greatly in the OST to be replaceable: 58 | `AUDIO_DARKNESS, cyber_battle, cybercity_old` 59 | 60 | The following 2 tracks are not lossless in the OST and game audio is of better quality: 61 | `acid_tunnel, noelle_normal` 62 | 63 | The following 10 tracks do not exist in the OST (some of these are not used in game): 64 | `cybercity_alt, dogcheck, honksong, noelle, flashback_excerpt, berdly_battle_heartbeat_true, thrash_rating, man, alarm_titlescreen, spamton_house` 65 | 66 | There are also 46 non-music effect and ambient sounds that do not exist in the OST. 67 | -------------------------------------------------------------------------------- /deltarune1+2.csv: -------------------------------------------------------------------------------- 1 | # (c) SoBiT 2021 2 | 0,DELTARUNE,deltarune.exe,=== DELTARUNE lossless music patcher by SoBiT ===,Upgrade low-quality game music with lossless music from the OST^^^! 3 | 1,stock music tracks,mus\,ogg 4 | 2,OST music tracks,,flac,mp3,wav 5 | 3,modded tracks,,ogg,-b500 --managed,-q10 6 | $ 7 | 1,DELTARUNE Ch.1,44100,chapter 1,chapter1,ch1,1 8 | 2,DELTARUNE Ch.2,48000,chapter 2,chapter2,ch2,2 9 | 9,UNDERTALE,44100,undertale,ut 10 | 0,OST tracks,44100,ost,soundtrack,. 11 | $ 12 | # In-game name, OST#, OST Track#, Pitch/speed (%), Amplification (dB), Start (sec), Length (sec), Notes, Splice1 opcode, Splice1 src start (sec), Splice1 dest start / offset value (sec), Splice1 length (sec), Splice2 opcode, ... 13 | # Splice opcodes: 1-copy from in-game audio; 3-copy within output file; 5-copy from in-game audio with resample; 8-right-rotate within output file 14 | AUDIO_ANOTHERHIM,1,1,100,0,0,47.99818,stock clicks on loop 15 | mus_introcar,1,2,100,0,0,0 16 | mus_school,1,3,100,1,0,0 17 | s_neo,1,4,100,0,0,0 18 | creepydoor,1,5,100,0,0,41.73893,differs significantly,1,0,0,1.25352 19 | creepylandscape,1,6,100,0,0,0 20 | creepychase,1,7,100,0,0,0 21 | legend,1,8,100,-1.2,0,0 22 | lancer,1,9,100,1.3,0,0,certain instruments have diff. ampl. 23 | battle,1,10,100,0,0,0 24 | castletown_empty,1,11,100,0,0,0 25 | bird,1,12,100,-0.7,0,0 26 | field_of_hopes,1,13,100,0,0,0,certain instruments have diff. ampl. 27 | fanfare,1,14,100,0,0,10.74358 28 | shop1,1,15,100,0,0,0,waveform/phasing differs significantly 29 | lancer_susie,1,16,100,0,0,12 30 | checkers,1,17,100,-0.4,0,0,certain instruments have diff. ampl. 31 | quiet_autumn,1,18,100,1.8,0,0,certain instruments have diff. ampl. 32 | forest,1,19,100,0,0,127.99941,waveform/phasing differs significantly,1,.002,0,.7483 33 | thrashmachine,1,20,100,0,0,54.8546,ost mastering not lossless 34 | lancerfight,1,21,100.553,1,0.66206,41.1085 35 | basement,1,22,100,-1.7,0,26.30135 36 | tense,1,23,100,0,0,0,waveform/phasing differs significantly 37 | vs_susie,1,24,100,0.1,0,0,reduced volume to avoid clipping 38 | card_castle,1,25,100,0,0,0 39 | ruruskaado,1,26,100.99,1.5,.00556,19.00244,stock clicks on loop 40 | april_2012,1,27,100,0,0,0,ost mastering not lossless 41 | hip_shop,1,28,100,0,0,0,waveform/phasing and instrument ampls. differ significantly,1,0,0,2.4832 42 | GALLERY,1,29,100,-1.8,0,12.79868,stock clicks on loop 43 | kingboss,1,30,100,0,0,106.10438,certain instruments have diff. ampl. 44 | #AUDIO_DARKNESS,1,31,100,0,0,0,pitch differs. unfixable 45 | prejoker,1,32,100,0,0,51.42612,stock clicks on loop,1,0,0,1.19798 46 | joker,1,33,100,0,0,0,waveform/phasing differs 47 | friendship,1,34,100,0,1.12499,0 48 | THE_HOLY,1,35,100,-2.9,0,47.95954,stock clicks on loop. both ver have clicks. removed one click near loop 49 | ..\snd_usefountain,1,36,100,0,0,0 50 | ..\snd_usefountain_ch1,1,36,100,0,0,0 51 | town,1,37,100,0,0,0,certain instruments have diff. ampl. 52 | home,1,38,100,0,0.00057,100.79517 53 | dontforget,1,39,100,0,0,0 54 | AUDIO_STORY,1,40,100,0,0,0,certain instruments have diff. ampl. 55 | menu,2,1,100,0,0,0 56 | noelle_school,2,2,100,-2.6,0,53.5814 57 | castletown,2,3,100,-0.3,0,126.1314 58 | queen_intro,2,4,100,-6.7,0,9.1384,exact waveform identity 59 | queen,2,5,100,-2.3,0,56.027 60 | cyber,2,6,100,-1.8,0,164.10256,ost lightly clipped 61 | boxing_game,2,7,100,-1.8,0,29.53845,waveform/phasing differs significantly 62 | cyber_battle_prelude,2,8,100,-4.65,0,16.61537,ost mastering not lossless 63 | music_guys_intro,2,9,100,-6,0,8.72727 64 | music_guys,2,10,100,0,0,5.33333 65 | #cyber_battle,2,11,100,0,0,0,half missing in ost. speed differs. unfixable 66 | cyber_battle_end,2,12,100,-0.2,0,0,,8,0.004,0,0,1,0,0,0.004 67 | cyber_shop,2,13,100,-2.8,0,66.7826 68 | berdly_theme,2,14,100,-5.8,0,44.112,,8,0.02677,0,0,1,0,0,0.02677 69 | berdly_chase,2,15,100,-0.6,0,64 70 | AUDIO_DEFEAT,2,16,100,-3.4,0,50.34783 71 | cybercity,2,17,98.33039,-1.6,0,112.403 72 | cyberhouse,2,18,100,-3.2,0,49.65516 73 | cybershop_christmas,2,19,100,-1.8,0,66.78112 74 | queen_car_radio,2,20,100,0,0,0 75 | spamton_meeting_intro,2,21,100,-0.5,0,2.36454 76 | spamton_meeting,2,22,100,-0.2,0,40.42106 77 | spamton_battle,2,23,100,-0.2,0,65.45454 78 | mansion_entrance,2,24,100,-1,0,76.8 79 | berdly_flashback,2,25,100,-3.5,0,48 80 | mansion,2,26,100,-0.8,0,97.2 81 | KEYGEN,2,27,100,-1.9,0.01498,7.61945,stock trk doesn't loop well 82 | #acid_tunnel,2,28,100,0,0,88.55768,ost not lossless 83 | rouxls_battle,2,29,100,-0.1,0,58.75862,both trks have click near end. fixed,3,58.52,58.491,.03 84 | #noelle_normal,2,30,100,-1.4,0,76.85224,ost not lossless. game audio has better quality 85 | noelle_ferriswheel,2,31,100,-0.3,0,76.85224 86 | queen_boss,2,32,100,-0.4,0,0 87 | giant_queen_appears,2,33,100,-3,0,105.60066,differs significantly,5,0.02913,0,15.36455 88 | gigaqueen_pre,2,34,100,0,0,0,stereo fx differ significantly 89 | boxing_boss,2,35,100,-0.3,0,142.76922,waveform/phasing differs significantly 90 | the_dark_truth,2,36,100,-3.3,0,67.2 91 | spamton_basement,2,37,100,0.7,0,16.91583 92 | spamton_neo_meeting,2,38,94.56,-4.6,0,31.32397 93 | spamton_neo_mix_ex_wip,2,39,100,0,0,140.57143,end part differs significantly,1,137.15173,137.14966,3.4124 94 | spamton_happy,2,40,100,-2.5,0,7.836 95 | spamton_neo_after,2,41,100,-4.2,0,0 96 | muscle,2,42,100,-4.4,0,22.5,certain instruments have diff. ampl. 97 | napsta_alarm,2,43,100,-2.4,0,0 98 | ch2_credits,2,45,100,1.2,0,61.126 99 | #cybercity_old,2,17,105.26315,0,0,0,speed differs. unfixable 100 | gameover_short,9,11,92.529,2.4,0,12.49087 101 | $ -------------------------------------------------------------------------------- /flac.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sobitcorp/FlacMyGame/e0a33f03236b0b5fa3d4f385697213d02cccbf32/flac.exe -------------------------------------------------------------------------------- /lame.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sobitcorp/FlacMyGame/e0a33f03236b0b5fa3d4f385697213d02cccbf32/lame.exe -------------------------------------------------------------------------------- /oggdec.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sobitcorp/FlacMyGame/e0a33f03236b0b5fa3d4f385697213d02cccbf32/oggdec.exe -------------------------------------------------------------------------------- /oggenc2.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sobitcorp/FlacMyGame/e0a33f03236b0b5fa3d4f385697213d02cccbf32/oggenc2.exe -------------------------------------------------------------------------------- /spectr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sobitcorp/FlacMyGame/e0a33f03236b0b5fa3d4f385697213d02cccbf32/spectr.png -------------------------------------------------------------------------------- /undertale.csv: -------------------------------------------------------------------------------- 1 | # (c) SoBiT 2019 2 | 0,UNDERTALE,undertale.exe,=== UNDERTALE lossless music patcher by SoBiT ===,Upgrade low-quality game music with lossless music from the OST^^^! 3 | 1,stock music tracks,mus_,ogg 4 | 2, OST music tracks,,flac,mp3,wav 5 | 3,modded tracks,mus_,ogg,-b500 --managed,-q10 6 | $ 7 | 0,UNDERTALE,44100,undertale soundtrack,undertale ost,soundtrack,ost,mus,. 8 | $ 9 | # In-game name, OST Track#, Pitch/speed (%), Amplification (dB), Start (sec), Length (sec), Notes, Splice1 opcode, Splice1 src start (sec), Splice1 dest start / offset value (sec), Splice1 length (sec), Splice2 opcode, ... 10 | # Splice opcodes: 1-copy from in-game audio; 3-copy within output file; 5-copy from in-game audio with resample; 8-right-rotate within output file 11 | story,1,89.5,-2.4,0,0,OST ver has lower pitch (97.9% of original). corrected at the expense of timing (barely noticeable),8,13,0.2,0,8,26.1,0.27,0 12 | menu0,2,100,1,0,0 13 | flowey,3,100,-4.92,0,0 14 | #toriel,4,92.5328,-0.94,13.0961,39.2717,! OST ver has much lower pitch (that of fallendown2). unfixable 15 | ruins,5,100,-0.75,0.005,91.302,,1,90.875,90.87,0 16 | options_fall,6,100,0,0,54.8721 17 | prebattle1,7,100,-0.03,0,10.4925 18 | tension,8,100,0,0,6.508 19 | battle1,9,100,0,0,55.08546 20 | ghostbattle,10,100,-1.8,0,51.2046 21 | gameover,11,92.529,-2.4,0,50.1 22 | house1,12,100,-2,0,0 23 | house2,13,100,0,0,0 24 | boss1,14,100,0,0,0 25 | muscle,15,100,-4.5,0,22.5058 26 | papyrus,16,100,-0.42,0,32.013 27 | snowy,17,100,-1.7,0,102.3028,slightly diff. patterns 28 | options_winter,18,100,-1.6,0,13.7143 29 | dogmeander,19,111.67,-1.6,0,0 30 | mystery,20,100,-3.5,0,42.9874 31 | dogsong,21,100,-1.3,0,36.3174 32 | town,22,100,-4,0,75.6259 33 | shop,23,100,-3.3,0,49.5528 34 | papyrusboss,24,100,-0.5,0,0 35 | date,25,100,-2.2,0,0 36 | date_tense,26,100,-3.4,0,25.6159 37 | date_fight,27,100,-1.4,0,34.3074 38 | mysteriousroom2,28,57.5,-2.5,0,29.0664,! OST ver has different pitch 39 | undynescary,29,100,-1.2,0.0003,13.736,OST ver is incorrectly mixed in the beginning,1,0,0,3.4982 40 | undynetheme,30,100,0,0.003,37.564 41 | waterfall,31,100,0,0,123.4996 42 | undynefast,32,100,-1.15,0,23.04 43 | waterquiet,33,88.96,0,0,30.022 44 | musicbox,34,100,-3.4,0,72.0123 45 | birdsong,35,100,-2.6,0,0,,1,19.4117,19.4117,0,1,0,0,0.02 46 | dummybattle,36,100,-1.42,0,0,OST ver is slightly clipped 47 | napstahouse,37,100,-3.5,0,0 48 | spoopy,38,100,-4,0,0 49 | spoopy_wave,39,100,-4.7,0,23.6234 50 | spoopy_holiday,40,100,-8.5,0,11.5896 51 | #napstachords,41,78.5,0,0,0 52 | race,42,100,-3,0,41.6174 53 | temvillage,43,100,-2.1,0,57.1458 54 | temshop,44,100,-2.2,0,40.2094 55 | undynetruetheme,45,100,0,0,80.64 56 | undyneboss,46,100,0.2,0,113.613 57 | #oogloop,47,100,0,0,13.4139 58 | lab,48,100,-1.1,0,84.4408 59 | mtgameshow,49,100,-1,0,45.18 60 | mettatonbattle,50,100,-2.6,0,62.0858 61 | anothermedium,51,100,-0.6,0,0 62 | options_summer,52,100,0,0,0 63 | battle2,53,100,-0.4,0,61.7157 64 | hotel,54,100,-0.4,0,82.5832 65 | hotel_battle,55,100,-0.05,0,60.4746 66 | confession,56,100,0,0,19.7954 67 | news,57,100,-1.8,0,15.656 68 | news_battle,58,100,-0.4,0,45.3408 69 | spider,59,100,0.2,0,100.1756 70 | wrongworld,60,100,0.8,0,57.8873 71 | mettmusical1,61,100,-3.2,0,18.014,,1,15.99,15.99,0 72 | mettmusical2,61,100,-3.1,15.999,18.014,,1,15.9913,15.992,0 73 | mettmusical3,61,100,-3,48.0019,18.014,,1,16.006,16.006,0 74 | mettmusical4,61,100,-3,64.0019,0 75 | operatile,62,100,-1.8,0,0 76 | sansdate,63,100,0.22,0,170,,1,160.806,160.806,0 77 | coretransition,64,100,-0.6,0,11.86648,,1,0.0001,0,2.8068,1,9.5428,9.5427,0 78 | core,65,100,-0.8,0,164.5884,OST ver is badly clipped 79 | mettafly,66,100,0,0,0 80 | mettaton_pretransform,67,100,0.4,0,0,! OST ver is different. compat check needed 81 | mettaton_ex,68,100,-0.8,0,132.9772,OST ver seems clipped 82 | mettsad,69,100,-1.1,0,104.6928 83 | elevator_last,70,100,0,0,18.8706 84 | endarea_parta,71,84.9414,0.1,0,211.924,,3,126.0344,142.0385,5,3,112.0309,144.0391,40,5,174.0026,174.04675,0 85 | endarea_partb,71,84.9414,0.2,169.5727,0,,5,0,0,3.015 86 | chokedup,73,100,-0.3,0,131.2086 87 | smallshock,74,100,-2,0,0 88 | barrier,75,100,3.1,0,28.34 89 | bergentruckung,76,100,1.25,0,17.385,OST ver is slightly stretched out 90 | vsasgore,77,100,-0.3,0,154.639,OST ver is slightly stretched out 91 | yourbestfriend_3,78,100,1.1,0,29.1615 92 | repeat_1,79,100,-1.8,149.05674,5.0515 93 | repeat_2,79,100,-1.8,154.10825,5.0548,,3,3.78766,0,0.2 94 | f_intro,79,100,-1.8,0,16.2902 95 | f_part1,79,100,-1.8,22.7388,30.31655,,1,25.2629,25.2629,0 96 | f_part2,79,100,-1.8,87.1618,27.79138,,1,22.7347,22.7347,0 97 | f_part3,79,100,-2,149.08344,25.27346,mostly missing in OST,1,0,0,20.4435,3,25.18,25.23,0.05 98 | f_6s_1,79,100,-1.9,54.3177,15.1567 99 | f_6s_2,79,100,-1.9,70.7384,30.3164,,3,0,15.1582,0,1,15.1578,15.1578,0.4719 100 | f_6s_3,79,100,-1.9,116.2155,15.154 101 | f_6s_4,79,100,-1.9,132.63358,30.3158,,3,0,15.1579,0,1,15.1565,15.1565,0.473 102 | f_6s_5,79,100,-1.9,175.58165,30.3146,,3,0,15.1573,0,1,15.0028,15.0028,0.4676 103 | f_6s_6,79,100,-1.9,192.002,15.1578 104 | f_finale_1_l,80,100,0.1,0,21.4788,,1,20.2032,20.19927,0 105 | f_finale_2,80,100,0,20.21052,41.7076,,1,40.41818,40.41845,0 106 | f_finale_3,80,100,0,60.63158,60.6331,,3,0.00206,40.4231,0 107 | z_ending,81,100,-3,0,0 108 | endingexcerpt1,81,100,-3,61.202,28.8095 109 | endingexcerpt2,81,100,-3,90.0115,57.59945 110 | undynepiano,82,100,-1.8,0,8.6365 111 | hereweare,83,100,1.2,0,124.9597 112 | amalgam,84,100,-1.2,0,0 113 | fallendown2,85,100,-0.3,0,0 114 | dontgiveup,86,100,0,0,120.0095,,3,87.0092,111.00908,0 115 | xpart,87,94.8219,0,0,180.0034,OST ver seems badly clipped 116 | a2,88,100,0,0,14.2261 117 | xpart_2,89,100,0,0.002,106.675,OST ver seems badly clipped 118 | xpart_a,90,100,0,0,69.3371,,1,63.9319,63.9299,0 119 | xpart_b,90,100,0,63.9997,42.6719 120 | xpart_back,91,100,1,0,17.208 121 | reunited,92,100,0.25,0,282.48 122 | menu6,93,100,2.4,0,0 123 | #leave,94,100,0,0,0,! OST ver has lots of popping 124 | cast_1,95,100,0,0,35.65957 125 | cast_2,95,100,0,35.65678,19.20067,,1,0,0,0.51886 126 | cast_3,95,100,0.2,54.85745,35.6586 127 | cast_4,95,100,0.1,90.5144,49.8808,,1,45.1575,45.1575,0 128 | cast_5,95,100,0.1,135.6773,71.2867 129 | cast_6,95,100,0,207.399,21.8195,,1,20.3965,20.3965,0 130 | cast_7,95,100,3.3,227.8059,21.23496 131 | express_myself,96,100,0,0,0,OST ver seems clipped 132 | x_undyne_pre,97,100,-0.5,1,13.71438,,8,0,0.88976,0 133 | x_undyne,98,100,0.2,0,153.6 134 | mettaton_neo,99,100,0,0,26.49012 135 | zz_megalovania,100,100,0,0,0 136 | #piano,101,100,0,0,0,! OST ver has popping 137 | $ -------------------------------------------------------------------------------- /wavedit.c: -------------------------------------------------------------------------------- 1 | #ifdef _WIN32 2 | extern int _chsize(int,long); 3 | #define ftruncate _chsize 4 | #else 5 | #include 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define ARRLEN(X) sizeof(X)/sizeof(X[0]) 15 | #define MAX(x,y) ((x)>(y)?(x):(y)) 16 | #define MIN(x,y) ((x)<(y)?(x):(y)) 17 | #define CLAMP(x,a,b) ((x)<(a)?(a):((x)>(b)?(b):(x))) 18 | 19 | typedef struct { 20 | int mriff; //RIFF 21 | int size; //file size minus 8 22 | int mwave; //WAVE 23 | int mfmt; //"fmt " 24 | int hdrSz; 25 | short fmt; //1 == PCM 26 | short chans; 27 | int samprate; 28 | int byterate; //== samprate * chans * bitdepth/8 29 | short bytesPerSamp; //== chans * bitdepth/8 30 | short bitdepth; 31 | } wavhdr; 32 | 33 | void help(){ 34 | puts("wavedit v1.0.1 by SBT - make simple edits to WAV sound files 35 | 36 | Usage: wavedit [] 37 | 38 | The following operations are supported. All positions are given in seconds. 39 | For all length values, if it is less than 0, it is relative to end of file. 40 | If it is not given or equal to 0, range spans to end of file. 41 | 42 | trim 43 | Remove all samples past the given length value. 44 | 45 | crop [] 46 | Remove all samples outside the given range. 47 | If range is outside of the file's bounds, new samples will be zero-filled. 48 | 49 | setsample [%] 50 | Directly set the file's sampling rate. 51 | The value is in hertz unless given as a percentage (ends with % sign). 52 | 53 | resample [%] [] 54 | Perform resampling. See above. 55 | Interpolation methods: 0-none 1-linear (default) 56 | 57 | amp [%] [ []] 58 | Perform amplification. Can be limited to a given region. 59 | The amount value is in decibels unless followed by a % sign. 60 | 61 | rol [ [ []]] 62 | ror [ [ []]] 63 | Rotate samples to the left or right by the given amount in seconds. 64 | Can be limited to a given region. 65 | 66 | copy [ []] 67 | Copy samples from one position of the file into another. 68 | Transition (in seconds) softens the copy bounds to avoid popping. 69 | 70 | copyext [ [ []]] 71 | Same as above, but use another file as source. 72 | If dest-pos not given, it will equal source-pos. 73 | 74 | bitdepth 75 | Convert file's bit depth to the given value. 76 | "); 77 | exit(0); 78 | } 79 | 80 | void* kmalloc(int n){ 81 | void *p = malloc(n); 82 | if(!p) { 83 | puts("[ERR] Out of memory!"); 84 | exit(-1); 85 | } 86 | return p; 87 | } 88 | 89 | double readDbl(char* s){ 90 | char* p; 91 | double val = strtod(s, &p); 92 | if (*p != 0) { 93 | printf("[ERR] Bad argument: %s is not a number or out of valid range!\n", s); 94 | exit(-2); 95 | } 96 | return val; 97 | } 98 | int readIntRng(char* s, int min, int max){ 99 | char* p; 100 | long val = strtol(s, &p, 0); 101 | if (*p != 0 || val < min || val > max || val < INT_MIN || val > INT_MAX) { 102 | printf("[ERR] Bad argument: %s is not a number or out of valid range!\n", s); 103 | exit(-2); 104 | } 105 | return (int)val; 106 | } 107 | int readInt(char* s){ readIntRng(s, INT_MIN+1, INT_MAX-1); } 108 | 109 | 110 | FILE* openFile(char* path, int readonly){ 111 | FILE* fp = fopen(path, readonly ? "rb" : "rb+"); 112 | if (!fp) { 113 | printf("[ERR] Can't open %s: %s\n", path, strerror(errno)); 114 | exit(-3); 115 | } 116 | return fp; 117 | } 118 | 119 | int readWav(FILE* fp, wavhdr* hdr, unsigned char** data, int* datalen, int bitop){ 120 | int ret = 0; 121 | int l, hl = sizeof(wavhdr), dl; 122 | if (hl != fread(hdr, 1, hl, fp)){ 123 | printf("[ERR] Can't read WAV header: %s\n", strerror(errno)); 124 | exit(-4); 125 | } 126 | fseek(fp, 0, SEEK_END); 127 | l = (int)ftell(fp); 128 | if (ftell(fp) >= INT_MAX) { 129 | printf("[ERR] File is too big!\n"); 130 | exit(-6); 131 | } 132 | if (hdr->mriff != 0x46464952 || hdr->mwave != 0x45564157 || hdr->mfmt != 0x20746d66) { 133 | printf("[ERR] File is not a WAV file!\n"); 134 | exit(-6); 135 | } 136 | if (hdr->bitdepth != 8 && hdr->bitdepth != 16 && hdr->bitdepth != 32 && (hdr->bitdepth != 24 || !bitop)){ 137 | printf("[ERR] File has unsupported bit depth: %d\n", hdr->bitdepth); 138 | exit(-6); 139 | } 140 | if (hdr->fmt != 1) { 141 | printf("[WARN] File does not contain PCM data: %d\n", hdr->fmt); 142 | ret = 1; 143 | } 144 | dl = l - 0x1c - hdr->hdrSz; 145 | dl -= dl % (hdr->chans * (hdr->bitdepth/8)); 146 | *data = kmalloc(dl); 147 | *datalen = dl; 148 | fseek(fp, l - dl, SEEK_SET); 149 | if (dl != fread(*data, 1, dl, fp)) { 150 | printf("[ERR] Can't read WAV data: %s\n", strerror(errno)); 151 | exit(-4); 152 | } 153 | return ret; 154 | } 155 | int writeWav(FILE* fp, wavhdr hdr, unsigned char* data, int datalen) { 156 | int hl = sizeof(wavhdr), mdata = 0x61746164; 157 | hdr.mriff = 0x46464952; 158 | hdr.mwave = 0x45564157; 159 | hdr.mfmt = 0x20746d66; 160 | if (!hdr.fmt) hdr.fmt = 1; 161 | hdr.bytesPerSamp = hdr.chans * (hdr.bitdepth/8); 162 | hdr.byterate = hdr.bytesPerSamp * hdr.samprate; 163 | if (!hdr.hdrSz) hdr.hdrSz = hl - 0x14; 164 | if (data) hdr.size = hdr.hdrSz + 0x14 + datalen; 165 | fseek(fp, 0, SEEK_SET); 166 | if (hl != fwrite(&hdr, 1, hl, fp)){ 167 | printf("[ERR] Can't write WAV header: %s\n", strerror(errno)); 168 | exit(-5); 169 | } 170 | if (data) { 171 | fseek(fp, hdr.hdrSz + 0x14, SEEK_SET); 172 | fwrite(&mdata, 4, 1, fp); 173 | fwrite(&datalen, 4, 1, fp); 174 | if (datalen != fwrite(data, 1, datalen, fp)) { 175 | printf("[ERR] Can't write WAV data: %s\n", strerror(errno)); 176 | exit(-5); 177 | } 178 | ftruncate(fileno(fp), hl + datalen + 8); 179 | } 180 | return 0; 181 | } 182 | void transition(unsigned char *ndp, unsigned char *odp, unsigned char *odi, unsigned char *odl, int len, int bps){ 183 | signed char *n8, *o8, *t8, *d8; 184 | signed short *n16, *o16, *t16, *d16; 185 | signed int *n32, *o32, *t32, *d32; 186 | double t, inc; 187 | if (len == 0) return; 188 | len *= 2; 189 | if (len < 0) { 190 | ndp+=len; 191 | odp+=len; 192 | } 193 | d8 = n8 = (signed char*)ndp; 194 | o8 = (signed char*)odp; 195 | d16 = n16 = (signed short*)ndp; 196 | o16 = (signed short*)odp; 197 | d32 = n32 = (signed int*)ndp; 198 | o32 = (signed int*)odp; 199 | if (len < 0) { 200 | len=-len; 201 | t8 = n8; n8=o8; o8=t8; 202 | t16 = n16; n16=o16; o16=t16; 203 | t32 = n32; n32=o32; o32=t32; 204 | } 205 | if (odp - odi < len/4) return; 206 | if ((odl - odp) - len < len/4) return; 207 | //printf("TR %d (of %d) len %d odp=%x odi=%x odl=%x\n", odp-odi, odl-odi, len, odp, odi, odl); 208 | len /= bps; 209 | for (t = 0, inc = (double)1/len; t < 1 && odp < odl; t += inc, ndp+=bps, odp+=bps) 210 | if (odp >= odi) 211 | switch(bps){ 212 | case 1: *d8++ = (signed char)((float)*o8++ * (1-t) + (float)*n8++ * t + .5f); break; 213 | case 2: *d16++ = (signed short)((float)*o16++ * (1-t) + (float)*n16++ * t + .5f); break; 214 | case 4: *d32++ = (signed int)((float)*o32++ * (1-t) + (float)*n32++ * t + .5f); break; 215 | } 216 | } 217 | 218 | 219 | 220 | int main(int argc, char** argv){ 221 | const char* ops[] = {"trim","crop","setsamp","resamp","amp","rol","ror","copyex","copy","bitdepth"}; 222 | const char opcs[] = {10,11,20,21,30,40,41,51,50,60}; 223 | 224 | int op, ival1, ival2; 225 | char *file1, *file2 = 0; 226 | double spos, dpos, len, val1, vtrans=0, t; 227 | int i, j, l, tb, tc, ts; 228 | int ssp, sdp, slen, strans; 229 | FILE *fp, *fpe; 230 | wavhdr wh, whe; 231 | unsigned char *wd, *wde, *nd = 0, *od; 232 | int wdl, wdle, wbps, wbpse, ndl; 233 | signed char *rwd8, *rnd8; 234 | signed short *rwd16, *rnd16; 235 | signed int *rwd32, *rnd32; 236 | float tf; 237 | 238 | if (argc < 4) help(); //read arguments 239 | file1 = argv[2]; 240 | for (i=0, l=strlen(argv[1]); i 4 ? readDbl(argv[op == 10 ? 3 : 4]) : 0); 253 | break; 254 | case 21: //setsample/resample 255 | ival2 = (argc > 4 ? readIntRng(argv[4], 0, 1) : 1); 256 | case 20: 257 | if ((i = strlen(argv[3])) > 0 && argv[3][i-1] == '%'){ 258 | ival1 = -1; 259 | argv[3][i-1] = '\0'; 260 | val1 = readDbl(argv[3]) / 100; 261 | if (val1 < 0) val1 = 1 / -val1; 262 | } else 263 | ival1 = readIntRng(argv[3], 1, INT_MAX - 1); 264 | break; 265 | case 30: //amp 266 | if ((i = strlen(argv[3])) > 0 && argv[3][i-1] == '%'){ 267 | j = 1; 268 | argv[3][i-1] = '\0'; 269 | } 270 | val1 = readDbl(argv[3]); 271 | if (j) val1 /= 100; 272 | else val1 = pow(10, val1/20); 273 | spos = (argc > 4 ? readDbl(argv[4]) : 0); 274 | len = (argc > 5 ? readDbl(argv[5]) : 0); 275 | vtrans = (argc > 6 ? readDbl(argv[6]) : 0); 276 | break; 277 | case 40: //rol/ror 278 | case 41: 279 | val1 = readDbl(argv[3]); 280 | if (val1 < 0) { 281 | op ^= 1; 282 | val1 = -val1; 283 | } 284 | spos = (argc > 4 ? readDbl(argv[4]) : 0); 285 | len = (argc > 5 ? readDbl(argv[5]) : 0); 286 | vtrans = (argc > 6 ? readDbl(argv[6]) : 0); 287 | break; 288 | case 51: //copy/copyext 289 | file2 = argv[3]; 290 | j = 1; 291 | case 50: 292 | if (argc < 5) help(); 293 | spos = readDbl(argv[3+j]); 294 | dpos = (argc > 4+j ? readDbl(argv[4+j]) : spos); 295 | len = (argc > 5+j ? readDbl(argv[5+j]) : 0); 296 | vtrans = (argc > 6+j ? readDbl(argv[6+j]) : 0); 297 | break; 298 | case 60: //convert bitdepth 299 | ival1 = readIntRng(argv[3], 8, 32); 300 | if (ival1%8) { 301 | printf("[ERR] Bad arguments: Bit depth must be a multiple of 8!\n"); 302 | return -2; 303 | } 304 | break; 305 | } 306 | 307 | fp = openFile(file1, 0); //get ready 308 | readWav(fp, &wh, &wd, &wdl, op==60?1:0); 309 | if (file2) { 310 | fpe = openFile(file2, 1); 311 | readWav(fpe, &whe, &wde, &wdle, 0); 312 | } 313 | wbps = wh.chans * (wh.bitdepth/8); 314 | wbpse = whe.chans * (whe.bitdepth/8); 315 | ssp = (int)(spos * wh.samprate) * wbps; 316 | sdp = (int)(dpos * wh.samprate) * wbps; 317 | slen = (int)(len * wh.samprate) * wbps; 318 | strans = (int)((vtrans / 2) * wh.samprate) * wbps; 319 | if (op == 51){ 320 | ssp = (int)(spos * whe.samprate) * wbpse; 321 | if (slen < 0) slen = wdl + slen - sdp; 322 | else if (slen == 0) slen = MIN(wdl - sdp, wdle - ssp); 323 | if (wh.samprate != whe.samprate) printf("[WARN] Sample rate mismatch: %d vs %d!\n", whe.samprate, wh.samprate); 324 | if (wh.bitdepth != whe.bitdepth) printf("[WARN] Bit depth mismatch: %d vs %d!\n", whe.bitdepth, wh.bitdepth); 325 | if (wh.chans != whe.chans) printf("[WARN] Channel count mismatch: %d vs %d!\n", whe.chans, wh.chans); 326 | } else { 327 | if (slen < 0) slen = wdl + slen - ssp; 328 | else if (slen == 0) slen = wdl - ssp; 329 | } 330 | if (slen <= 0) { 331 | printf("[ERR] Bad arguments: Selected region is empty or negative!\n"); 332 | return -2; 333 | } else if (slen > INT_MAX - 0x40) { 334 | printf("[ERR] Bad arguments: Selected region is too big!\n"); 335 | return -2; 336 | } 337 | switch (op) { 338 | case 10: 339 | case 11: 340 | if (ssp == 0 && slen == wdl) return 1; 341 | break; 342 | case 20: 343 | case 21: 344 | if (ival1 <= 0) ival1 = (.5f + wh.samprate * val1); 345 | if (ival1 <= 0) { 346 | printf("[ERR] Bad arguments: Sample rate cannot be zero or negative!\n"); 347 | return -2; 348 | } 349 | val1 = (double)wh.samprate / ival1; 350 | if (wh.samprate == ival1) return 1; 351 | break; 352 | case 30: 353 | if (val1 == 1) return 1; 354 | tf = (float)val1; 355 | case 40: 356 | case 41: 357 | if (ssp < 0) ssp = 0; 358 | if (ssp + slen > wdl) slen = wdl - ssp; 359 | break; 360 | case 60: 361 | if (ival1 == wh.bitdepth) return 1; 362 | break; 363 | } 364 | tc = wh.chans; 365 | tb = wh.bitdepth/8; 366 | ts = wh.samprate; 367 | rwd8 = (signed char*)wd; 368 | rwd16 = (signed short*)wd; 369 | rwd32 = (signed int*)wd; 370 | 371 | if (strans < 0) strans = 0; 372 | if (strans > 0) { 373 | if (strans > slen) strans = slen; 374 | od = kmalloc(wdl); 375 | memcpy(od, wd, wdl); 376 | ssp -= strans; 377 | sdp -= strans; 378 | slen += strans*2; 379 | } 380 | switch (op) { //perform op 381 | case 10: //trim/crop 382 | case 11: 383 | if (ssp >= 0 && (slen + ssp) <= wdl) 384 | nd = wd + ssp; 385 | else { //if any samples outside original range 386 | nd = kmalloc(slen); 387 | memset(nd, 0, slen); 388 | if ((slen + ssp) >= 0 && ssp < wdl) { 389 | i = (ssp >= 0 ? ssp : 0); 390 | j = (ssp >= 0 ? 0 : -ssp); 391 | memcpy(nd + j, wd + i, MIN(slen - j, wdl - i)); 392 | } 393 | } 394 | ndl = slen; 395 | break; 396 | case 21: //resample 397 | if ((double)wdl * ival1 / wh.samprate >= INT_MAX - 1) { 398 | printf("[ERR] Resulting output file too big!\n"); 399 | return -7; 400 | } 401 | ndl = (int)ceil(((double)(wdl / wbps) / wh.samprate) * ival1) * wbps; 402 | nd = kmalloc(ndl); 403 | rnd8 = (signed char*)nd; 404 | rnd16 = (signed short*)nd; 405 | rnd32 = (signed int*)nd; 406 | switch(ival2) { //interp. method 407 | case 0: //none 408 | for (i = 0, l = ndl / wbps; i < l; i++) 409 | for (j = 0; j < tc; j++) 410 | switch(tb){ 411 | case 1: rnd8[i*tc + j] = rwd8[(((long long)i * ts) / ival1) * tc + j]; break; 412 | case 2: rnd16[i*tc + j] = rwd16[(((long long)i * ts) / ival1) * tc + j]; break; 413 | case 4: rnd32[i*tc + j] = rwd32[(((long long)i * ts) / ival1) * tc + j]; break; 414 | } 415 | break; 416 | case 1: //linear 417 | for (t = 0, i = 0, l = ndl/wbps; i < l; i++, t+=val1){ 418 | tf = t - floor(t); 419 | for (j = 0; j < tc; j++) 420 | switch(tb){ 421 | case 1: rnd8[i*tc + j] = (signed char)((float)rwd8[(int)floor(t) * tc + j] * (1 - tf) + (float)rwd8[(int)ceil(t) * tc + j] * tf); break; 422 | case 2: rnd16[i*tc + j] = (signed short)((float)rwd16[(int)floor(t) * tc + j] * (1 - tf) + (float)rwd16[(int)ceil(t) * tc + j] * tf); break; 423 | case 4: rnd32[i*tc + j] = (signed int)((float)rwd32[(int)floor(t) * tc + j] * (1 - tf) + (float)rwd32[(int)ceil(t) * tc + j] * tf); break; 424 | } 425 | } 426 | break; 427 | } 428 | case 20: //setsample 429 | wh.samprate = ival1; 430 | break; 431 | case 30: //amplify 432 | nd = wd; ndl = wdl; 433 | rnd8 = (signed char*)nd; 434 | rnd16 = (signed short*)nd; 435 | rnd32 = (signed int*)nd; 436 | for (i = ssp / tb, l = (ssp + slen) / tb; i < l; i++) 437 | switch(tb){ 438 | case 1: rnd8[i] = (signed char)CLAMP((float)rwd8[i] * tf + .5f, -0x80, 0x7f); break; 439 | case 2: rnd16[i] = (signed short)CLAMP((float)rwd16[i] * tf + .5f, -0x8000, 0x7fff); break; 440 | case 4: rnd32[i] = (signed int)CLAMP((float)rwd32[i] * tf + .5f, -0x80000000, 0x7fffffff); break; 441 | } 442 | transition(nd + ssp, od + ssp, od, od+wdl, strans, tb); 443 | transition(nd + ssp + slen, od + ssp + slen, od, od+wdl, -strans, tb); 444 | break; 445 | case 40: //rol/ror 446 | case 41: 447 | sdp = ((int)(val1 * wh.samprate) * wbps) % slen; 448 | if (sdp <= 0) return 1; 449 | ndl = wdl; 450 | nd = kmalloc(ndl); 451 | if (ssp > 0 || ssp + slen < wdl) 452 | memcpy(nd, wd, wdl); 453 | switch(op){ 454 | case 40: 455 | memcpy(nd + ssp + slen - sdp, wd + ssp, sdp); 456 | memcpy(nd + ssp, wd + ssp + sdp, slen - sdp); 457 | break; 458 | case 41: 459 | memcpy(nd + ssp, wd + ssp + slen - sdp, sdp); 460 | memcpy(nd + ssp + sdp, wd + ssp, slen - sdp); 461 | break; 462 | } 463 | transition(nd + ssp, od + ssp, od, od+wdl, strans, tb); 464 | transition(nd + ssp + slen, od + ssp + slen, od, od+wdl, -strans, tb); 465 | break; 466 | case 50: //copy 467 | nd = kmalloc(wdl); 468 | memcpy(nd, wd, wdl); 469 | wdle = wdl; 470 | wde = wd; 471 | case 51: //copyext 472 | if (!nd) nd = wd; 473 | ndl = wdl; 474 | if (sdp < 0) { 475 | ssp -= sdp; slen += sdp; sdp = 0; 476 | } 477 | if (slen <= 0 || sdp > wdl) { 478 | printf("[WARN] Copy destination is outside file's bounds!\n"); 479 | return 0; 480 | } 481 | if (ssp + strans < 0) memset(nd + sdp, 0, MIN(-ssp, wdl - sdp)); 482 | i = sdp + MAX(0, wdle - ssp); 483 | l = MIN(slen - MAX(0, wdle - ssp), wdl - i); 484 | if (ssp + slen - strans > wdle && l > 0) memset(nd + i, 0, l); 485 | if (ssp < 0) { 486 | sdp -= ssp; slen += ssp; ssp = 0; 487 | } 488 | l = MIN(slen, MIN(wdle - ssp, wdl - sdp)); 489 | if (slen < 0 || ssp > wdle || sdp > wdl) 490 | printf("[WARN] Copy source is outside file's bounds!\n"); 491 | else 492 | memcpy(nd + sdp, wde + ssp, l); 493 | transition(nd + sdp, od + sdp, od, od+wdl, strans, tb); 494 | transition(nd + sdp + l, od + sdp + l, od, od+wdl, -strans, tb); 495 | break; 496 | case 60: //convert bitdepth 497 | nd = wd; 498 | ndl = wdl/tb*(ival1/8); 499 | if (ndl > wdl) 500 | nd = kmalloc(ndl); 501 | wh.bitdepth = ival1; 502 | ival1/=8; 503 | if (tb == 1) 504 | for (i=0; i < wdl; i++) 505 | wd[i] = wd[i]+0x80; 506 | for (i=0, j=0; i < slen; i++) { 507 | if (i%tb==0) 508 | for (l=0; l < ival1-tb; l++) 509 | nd[j++] = 0x80; 510 | if (i%tb >= tb-ival1) 511 | nd[j++] = wd[i]; 512 | } 513 | if (ival1 == 1) 514 | for (i=0; i < ndl; i++) 515 | nd[i] = nd[i]+0x80; 516 | break; 517 | } 518 | 519 | writeWav(fp, wh, nd, ndl); 520 | fclose(fp); 521 | if (file2) fclose(fpe); 522 | 523 | return 0; 524 | } 525 | 526 | 527 | 528 | -------------------------------------------------------------------------------- /wavedit.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sobitcorp/FlacMyGame/e0a33f03236b0b5fa3d4f385697213d02cccbf32/wavedit.exe --------------------------------------------------------------------------------