Work on CMake conversion: sound transformation, conversion, and table generation

Some parts need to be cleaned up/removed/streamlined after the CMake
build can build the game on its own and compatibility with what the
old makefile does is no longer needed.
This commit is contained in:
Matt Penny 2024-09-12 02:13:25 -04:00
parent 8845a96667
commit dea0c3591d
5 changed files with 278 additions and 75 deletions

View file

@ -9,11 +9,13 @@ set(IMAGEMAGICK_CONVERT "convert")
set(MPG123 "mpg123")
set(NODEJS "node")
set(PYTHON3 "python")
set(SFZ2N64 "sfz2n64")
set(SOX "sox")
set(VPK "vpk")
set(VTF2PNG "vtf2png")
set(CONVERT_ASSET "${PROJECT_SOURCE_DIR}/tools/convert_asset.py")
set(GEN_SOUND_IDS "${PROJECT_SOURCE_DIR}/tools/generate_sound_ids.js")
set(JSOX "${PROJECT_SOURCE_DIR}/tools/jsox.js")
set(SKELETOOL64 "${PROJECT_SOURCE_DIR}/skelatool64/skeletool64")

View file

@ -1,2 +1,19 @@
set(VALVE_INTRO_VIDEO "${VPK_DIR}/Portal/hl2/media/valve.bik")
if(NOT EXISTS ${VALVE_INTRO_VIDEO})
# The Mac release of Portal uses a .mov instead of a .bik
string(REPLACE ".mov" ".bik" VALVE_INTRO_VIDEO_MAC "${VALVE_INTRO_VIDEO}")
# The Valve video doesn't exist in a VPK so we can check its type at
# configuration time and avoid complicating the conversion commands.
#
# Users may forget to copy their game files before running CMake.
# Only use the .mov if it exists at configuration time, so the build
# system supports the common case by default.
if (EXISTS ${VALVE_INTRO_VIDEO_MAC})
set(VALVE_INTRO_VIDEO ${VALVE_INTRO_VIDEO_MAC})
endif()
endif()
add_subdirectory(materials)
add_subdirectory(sound)

View file

@ -160,23 +160,6 @@ endforeach()
## Valve logo ##
################
set(VALVE_INTRO_VIDEO "${VPK_DIR}/Portal/hl2/media/valve.bik")
if(NOT EXISTS ${VALVE_INTRO_VIDEO})
# The Mac release of Portal uses a .mov instead of a .bik
string(REPLACE ".mov" ".bik" VALVE_INTRO_VIDEO_MAC "${VALVE_INTRO_VIDEO}")
# The Valve video doesn't exist in a VPK so we can check its type at
# configuration time and avoid complicating the conversion command.
#
# Users may forget to copy their game files before running CMake.
# Only use the .mov if it exists at configuration time, so the build
# system supports the common case by default.
if (EXISTS ${VALVE_INTRO_VIDEO_MAC})
set(VALVE_INTRO_VIDEO ${VALVE_INTRO_VIDEO_MAC})
endif()
endif()
function(_add_extract_frame_command INPUT_FILE OUTPUT_FILE SECONDS)
cmake_path(
GET OUTPUT_FILE PARENT_PATH
@ -191,7 +174,7 @@ function(_add_extract_frame_command INPUT_FILE OUTPUT_FILE SECONDS)
COMMAND
${CMAKE_COMMAND} -E make_directory ${OUTPUT_DIR}
COMMAND
${FFMPEG} -ss 00:00:${SECONDS} -i ${VALVE_INTRO_VIDEO} -frames:v 1 -update true -q:v 2 -loglevel quiet -y ${OUTPUT_FILE}
${FFMPEG} -ss 00:00:${SECONDS} -i ${INPUT_FILE} -frames:v 1 -update true -q:v 2 -loglevel quiet -y ${OUTPUT_FILE}
COMMAND
${IMAGEMAGICK_CONVERT} ${OUTPUT_FILE} -crop 491x369+265+202 -resize 160x120 ${OUTPUT_FILE}
COMMENT
@ -202,13 +185,13 @@ endfunction()
_add_extract_frame_command(
${VALVE_INTRO_VIDEO}
${CMAKE_BINARY_DIR}/assets/images/valve.png
${PAK_MODIFIED_DIR}/images/valve.png
4
)
_add_extract_frame_command(
${VALVE_INTRO_VIDEO}
${CMAKE_BINARY_DIR}/assets/images/valve-no-logo.png
${PAK_MODIFIED_DIR}/images/valve-no-logo.png
1
)
@ -221,18 +204,6 @@ _add_extract_frame_command(
# glob pitfalls do not apply here.
file(GLOB_RECURSE TEXTURE_SCRIPTS "*.ims")
function(_get_texture_script_file_list TEXTURE_SCRIPT PROPERTY_NAME PARENT_DIR OUTPUT)
get_source_file_property(FILE_LIST ${TEXTURE_SCRIPT} ${PROPERTY_NAME})
if (FILE_LIST)
list(TRANSFORM FILE_LIST PREPEND "${PARENT_DIR}/" OUTPUT_VARIABLE FILE_LIST)
list(TRANSFORM FILE_LIST APPEND ".png" OUTPUT_VARIABLE FILE_LIST)
list(APPEND ${OUTPUT} ${FILE_LIST})
endif()
return(PROPAGATE ${OUTPUT})
endfunction()
function(_add_texture_transform_command TEXTURE_SCRIPT OUTPUT_LIST)
cmake_path(
RELATIVE_PATH TEXTURE_SCRIPT
@ -261,7 +232,7 @@ function(_add_texture_transform_command TEXTURE_SCRIPT OUTPUT_LIST)
COMMAND
${PYTHON3} ${CONVERT_ASSET} ${IMAGEMAGICK_CONVERT} ${INPUT_FILE} ${TEXTURE_SCRIPT} ${OUTPUT_FILE}
WORKING_DIRECTORY
# TODO: Change this to PAK_MODIFIED_DIR and update .ims files with relative path
# TODO: Change this to PAK_MODIFIED_MATERIALS_DIR and update .ims files with relative path
${PROJECT_SOURCE_DIR}
COMMENT
"Transforming $<PATH:RELATIVE_PATH,${INPUT_FILE},${PROJECT_SOURCE_DIR}>"
@ -272,6 +243,18 @@ function(_add_texture_transform_command TEXTURE_SCRIPT OUTPUT_LIST)
return(PROPAGATE ${OUTPUT_LIST})
endfunction()
function(_get_texture_script_file_list TEXTURE_SCRIPT PROPERTY_NAME PARENT_DIR OUTPUT)
get_source_file_property(FILE_LIST ${TEXTURE_SCRIPT} ${PROPERTY_NAME})
if (FILE_LIST)
list(TRANSFORM FILE_LIST PREPEND "${PARENT_DIR}/" OUTPUT_VARIABLE FILE_LIST)
list(TRANSFORM FILE_LIST APPEND ".png" OUTPUT_VARIABLE FILE_LIST)
list(APPEND ${OUTPUT} ${FILE_LIST})
endif()
return(PROPAGATE ${OUTPUT})
endfunction()
# Add commands for transforming converted PNG textures (crop, scale, etc.).
# There are some special cases due to some conversion scripts reading textures
# other than those they are named after (combining multiple textures), or
@ -419,8 +402,6 @@ function(_add_material_generate_command INPUT_FILE OUTPUT_LIST)
${OUTPUT_FILE_H} ${OUTPUT_FILE_C}
COMMAND
${SKELETOOL64} --name ${MATERIAL_NAME} -m ${INPUT_FILE} --material-output -o ${OUTPUT_FILE_H}
WORKING_DIRECTORY
${PROJECT_SOURCE_DIR}
COMMENT
"Generating materials for $<PATH:RELATIVE_PATH,${INPUT_FILE},${PROJECT_SOURCE_DIR}>"
VERBATIM
@ -440,7 +421,7 @@ set_property(SOURCE hud.skm.yaml
set_property(SOURCE images.skm.yaml
PROPERTY ADDITIONAL_DEPS
${CMAKE_BINARY_DIR}/assets/images/valve.png
${PAK_MODIFIED_DIR}/images/valve.png
)
set_property(SOURCE ui.skm.yaml
@ -463,6 +444,7 @@ foreach(MATERIAL ${MATERIALS})
_add_material_generate_command(${MATERIAL} GENERATED_MATERIALS)
endforeach()
# TODO: proper dependencies from consumers
add_custom_target(
all_materials
DEPENDS ${GENERATED_MATERIALS}

View file

@ -1,6 +1,44 @@
# TODO: multiple languages
set(PAK_SOUND_DIR "${PAK_DIR}/sound")
set(PAK_MODIFIED_SOUND_DIR "${PAK_MODIFIED_DIR}/sound")
cmake_path(
RELATIVE_PATH CMAKE_CURRENT_SOURCE_DIR
BASE_DIRECTORY "${PROJECT_SOURCE_DIR}"
OUTPUT_VARIABLE RELATIVE_CURRENT_DIR
)
#################
## Valve sound ##
#################
function(_add_extract_video_audio_command INPUT_FILE OUTPUT_FILE)
cmake_path(
GET OUTPUT_FILE PARENT_PATH
OUTPUT_DIR
)
add_custom_command(
DEPENDS
${INPUT_FILE}
OUTPUT
${OUTPUT_FILE}
COMMAND
${CMAKE_COMMAND} -E make_directory ${OUTPUT_DIR}
COMMAND
${FFMPEG} -i ${INPUT_FILE} -vn -loglevel quiet -y ${OUTPUT_FILE}
COMMENT
"Converting $<PATH:RELATIVE_PATH,${INPUT_FILE},${PROJECT_SOURCE_DIR}>"
VERBATIM
)
endfunction()
_add_extract_video_audio_command(
${VALVE_INTRO_VIDEO}
${PAK_SOUND_DIR}/ambient/music/valve.wav
)
##########################
## Sound transformation ##
##########################
@ -11,6 +49,7 @@ set(SOUND_SCRIPTS
ambient/machines/portalgun_rotate1.sox
ambient/machines/ticktock1.sox
ambient/machines/wall_move5.sox
ambient/music/valve.sox
buttons/button10.sox
buttons/button3.sox
common/wpn_denyselect.sox
@ -137,10 +176,66 @@ set(MUSIC_SCRIPTS
music/portal_taste_of_blood.msox
)
# TODO: special cases:
# - valve (extract from video)
# - tank_turret_loop1 (generate wav with 16 bits per sample - original has 8)
# - ambience_base (generate wav at 22050 kHz - original is 11025)
set(INSTRUMENT_BANKS
ambient/atmosphere/ambience_base.ins
ambient/machines/beam_platform_loop1.ins
ambient/music/looping_radio_mix.ins
doors/door_metal_medium_open1.ins
vehicles/fast_windloop1.ins
vehicles/tank_turret_loop1.ins
weapons/physcannon/energy_sing_loop4.ins
)
# TODO: remove
function(_add_sound_transform_command_direct SOUND_NAME ARGS OUTPUT_LIST)
set(INPUT_FILE "${PAK_SOUND_DIR}/${SOUND_NAME}.wav")
string(REPLACE " " ";" ARGS ${ARGS})
set(OUTPUT_FILE "${CMAKE_BINARY_DIR}/${RELATIVE_CURRENT_DIR}/${SOUND_NAME}.wav")
cmake_path(
GET OUTPUT_FILE PARENT_PATH
OUTPUT_DIR
)
add_custom_command(
DEPENDS
extract_vpks ${INPUT_FILE}
OUTPUT
${OUTPUT_FILE}
COMMAND
${CMAKE_COMMAND} -E make_directory ${OUTPUT_DIR}
COMMAND
${SOX} ${INPUT_FILE} ${ARGS} ${OUTPUT_FILE}
COMMENT
"Transforming $<PATH:RELATIVE_PATH,${INPUT_FILE},${PROJECT_SOURCE_DIR}>"
VERBATIM
)
list(APPEND ${OUTPUT_LIST} ${OUTPUT_FILE})
return(PROPAGATE ${OUTPUT_LIST})
endfunction()
function(_add_sound_transform_command SOUND_SCRIPT OUTPUT_LIST)
cmake_path(
REMOVE_EXTENSION SOUND_SCRIPT
OUTPUT_VARIABLE SOUND_NAME
)
# TODO: change output to PAK_MODIFIED_SOUND_DIR once makefile is no longer in use
set(SOUND_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/${SOUND_SCRIPT}")
set(INPUT_FILE "${PAK_SOUND_DIR}/${SOUND_NAME}.wav")
set(OUTPUT_FILE "${CMAKE_BINARY_DIR}/${RELATIVE_CURRENT_DIR}/${SOUND_NAME}.wav")
if(SOUND_SCRIPT MATCHES ".*\.jsox")
_add_sound_transform_command_jsox(${SOUND_SCRIPT} ${INPUT_FILE} ${OUTPUT_FILE})
else()
_add_sound_transform_command_sox(${SOUND_SCRIPT} ${INPUT_FILE} ${OUTPUT_FILE})
endif()
list(APPEND ${OUTPUT_LIST} ${OUTPUT_FILE})
return(PROPAGATE ${OUTPUT_LIST})
endfunction()
function(_add_sound_transform_command_sox SOUND_SCRIPT INPUT_FILE OUTPUT_FILE)
add_custom_command(
@ -170,47 +265,17 @@ function(_add_sound_transform_command_jsox SOUND_SCRIPT INPUT_FILE OUTPUT_FILE)
)
endfunction()
function(_add_sound_transform_command SOUND_SCRIPT OUTPUT_LIST)
cmake_path(
REMOVE_EXTENSION SOUND_SCRIPT
OUTPUT_VARIABLE SOUND_NAME
)
cmake_path(
RELATIVE_PATH CMAKE_CURRENT_SOURCE_DIR
BASE_DIRECTORY "${PROJECT_SOURCE_DIR}"
OUTPUT_VARIABLE RELATIVE_DIR
)
# TODO: change output to PAK_MODIFIED_SOUND_DIR once makefile is no longer in use
set(SOUND_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/${SOUND_SCRIPT}")
set(INPUT_FILE "${PAK_SOUND_DIR}/${SOUND_NAME}.wav")
set(OUTPUT_FILE "${CMAKE_BINARY_DIR}/${RELATIVE_DIR}/${SOUND_NAME}.wav")
if(SOUND_SCRIPT MATCHES ".*\.jsox")
_add_sound_transform_command_jsox(${SOUND_SCRIPT} ${INPUT_FILE} ${OUTPUT_FILE})
else()
_add_sound_transform_command_sox(${SOUND_SCRIPT} ${INPUT_FILE} ${OUTPUT_FILE})
endif()
list(APPEND ${OUTPUT_LIST} ${OUTPUT_FILE})
return(PROPAGATE ${OUTPUT_LIST})
endfunction()
function(_add_music_transform_command MUSIC_SCRIPT OUTPUT_LIST)
cmake_path(
REMOVE_EXTENSION MUSIC_SCRIPT
OUTPUT_VARIABLE MUSIC_NAME
)
cmake_path(
RELATIVE_PATH CMAKE_CURRENT_SOURCE_DIR
BASE_DIRECTORY "${PROJECT_SOURCE_DIR}"
OUTPUT_VARIABLE RELATIVE_DIR
)
# TODO: change output to PAK_MODIFIED_SOUND_DIR once makefile is no longer in use
set(MUSIC_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/${MUSIC_SCRIPT}")
set(INPUT_FILE "${PAK_SOUND_DIR}/${MUSIC_NAME}.mp3")
set(CONVERTED_FILE "${PAK_SOUND_DIR}/${MUSIC_NAME}.wav")
set(OUTPUT_FILE "${CMAKE_BINARY_DIR}/${RELATIVE_DIR}/${MUSIC_NAME}.wav")
set(OUTPUT_FILE "${CMAKE_BINARY_DIR}/${RELATIVE_CURRENT_DIR}/${MUSIC_NAME}.wav")
# First convert to WAV
add_custom_command(
@ -232,11 +297,23 @@ function(_add_music_transform_command MUSIC_SCRIPT OUTPUT_LIST)
return(PROPAGATE ${OUTPUT_LIST})
endfunction()
# Add commands for transforming audio files
# Add commands for transforming sound files
# Music is stored as MP3 and is converted to WAV first
set(SOUNDS_TRANSFORMED "")
# TODO: remove this special casing once makefile is no longer in use (just use .sox)
_add_sound_transform_command_direct(
vehicles/tank_turret_loop1
"-b 16"
SOUNDS_TRANSFORMED
)
_add_sound_transform_command_direct(
ambient/atmosphere/ambience_base
"-c 1 -r 22050"
SOUNDS_TRANSFORMED
)
foreach(SOUND_SCRIPT ${SOUND_SCRIPTS})
_add_sound_transform_command(${SOUND_SCRIPT} SOUNDS_TRANSFORMED)
endforeach()
@ -245,9 +322,130 @@ foreach(MUSIC_SCRIPT ${MUSIC_SCRIPTS})
_add_music_transform_command(${MUSIC_SCRIPT} SOUNDS_TRANSFORMED)
endforeach()
add_custom_target(
all_sounds
DEPENDS ${SOUNDS_TRANSFORMED}
######################
## Sound conversion ##
######################
function(_add_sound_convert_command INPUT_FILE OUTPUT_LIST)
# TODO: change output to PAK_MODIFIED_SOUND_DIR once makefile is no longer in use
cmake_path(
REPLACE_EXTENSION INPUT_FILE
".aifc"
OUTPUT_VARIABLE OUTPUT_FILE
)
# TODO: convert to AIFC
add_custom_command(
DEPENDS
${INPUT_FILE}
OUTPUT
${OUTPUT_FILE}
COMMAND
${SFZ2N64} -o ${OUTPUT_FILE} ${INPUT_FILE}
COMMENT
"Converting $<PATH:RELATIVE_PATH,${INPUT_FILE},${PROJECT_SOURCE_DIR}>"
VERBATIM
)
list(APPEND ${OUTPUT_LIST} ${OUTPUT_FILE})
return(PROPAGATE ${OUTPUT_LIST})
endfunction()
# Add commands for converting transformed sound files to N64 AIFC (compressed AIFF)
set(SOUNDS_CONVERTED "")
foreach(TRANSFORMED_SOUND ${SOUNDS_TRANSFORMED})
_add_sound_convert_command(${TRANSFORMED_SOUND} SOUNDS_CONVERTED)
endforeach()
add_custom_target(
all_sounds
DEPENDS ${SOUNDS_CONVERTED}
)
############################
## Sound table generation ##
############################
set(SOUND_TABLE_DEPENDENCIES ${SOUNDS_CONVERTED})
set(SOUND_TABLE_INPUTS "")
foreach(INS_BANK ${INSTRUMENT_BANKS})
cmake_path(
REMOVE_EXTENSION INS_BANK
OUTPUT_VARIABLE SOUND_NAME
)
# Each bank references a WAV. Keep track of the dependency.
#
# Some banks depend on converted sounds instead of unmodified.
# That dependency is taken care of via SOUNDS_CONVERTED.
list(APPEND SOUND_TABLE_DEPENDENCIES "${PAK_SOUND_DIR}/${SOUND_NAME}.wav")
list(APPEND SOUND_TABLE_INPUTS "${CMAKE_CURRENT_SOURCE_DIR}/${INS_BANK}")
endforeach()
foreach(CONVERTED_SOUND ${SOUNDS_CONVERTED})
cmake_path(
RELATIVE_PATH CONVERTED_SOUND
BASE_DIRECTORY "${CMAKE_BINARY_DIR}/${RELATIVE_CURRENT_DIR}"
OUTPUT_VARIABLE INS_BANK
)
cmake_path(
REPLACE_EXTENSION INS_BANK
".ins"
OUTPUT_VARIABLE INS_BANK
)
# Only include the sound if an instrument bank doesn't already do so
if(NOT INS_BANK IN_LIST INSTRUMENT_BANKS)
list(APPEND SOUND_TABLE_INPUTS ${CONVERTED_SOUND})
endif()
endforeach()
# Add commands for generating sound tables
set(SOUND_TABLE_SOUNDS "${CMAKE_BINARY_DIR}/${RELATIVE_CURRENT_DIR}/sounds.sounds")
set(SOUND_TABLE_TBL "${CMAKE_BINARY_DIR}/${RELATIVE_CURRENT_DIR}/sounds.sounds.tbl")
add_custom_command(
DEPENDS
all_sounds ${SOUND_TABLE_DEPENDENCIES}
OUTPUT
${SOUND_TABLE_SOUNDS} ${SOUND_TABLE_TBL}
COMMAND
${SFZ2N64} -o ${SOUND_TABLE_SOUNDS} ${SOUND_TABLE_INPUTS}
COMMENT
"Generating sound data tables"
VERBATIM
)
set(BUILD_AUDIO_DIR "${CMAKE_BINARY_DIR}/src/audio")
set(CLIPS_H "${BUILD_AUDIO_DIR}/clips.h")
set(LANGUAGES_H "${BUILD_AUDIO_DIR}/languages.h")
set(LANGUAGES_C "${BUILD_AUDIO_DIR}/languages.c")
add_custom_command(
DEPENDS
all_sounds ${SOUND_TABLE_DEPENDENCIES}
OUTPUT
${CLIPS_H} ${LANGUAGES_H} ${LANGUAGES_C}
COMMAND
${NODEJS} ${GEN_SOUND_IDS} -o ${BUILD_AUDIO_DIR} -p SOUNDS_ ${SOUND_TABLE_INPUTS}
COMMENT
"Generating sound lookup tables"
VERBATIM
)
# TODO: proper dependencies from consumers
add_custom_target(
sound_data_tables
DEPENDS
${SOUND_TABLE_SOUNDS}
${SOUND_TABLE_TBL}
)
add_custom_target(
sound_lookup_tables
DEPENDS
${CLIPS_H}
${LANGUAGES_H}
${LANGUAGES_C}
)

View file

@ -32,6 +32,10 @@ for (let i = 2; i < process.argv.length; ++i) {
}
}
if (!fs.existsSync(output)) {
fs.mkdirSync(output, { recursive: true });
}
outputLanguagesSourceFile = output + '/languages.c';
outputLanguagesHeader += output + '/languages.h';
output += '/clips.h';