Skip to content

Instantly share code, notes, and snippets.

@autch
Created September 28, 2021 03:52
Show Gist options
  • Save autch/90d1578e2c017e39c41ca20f917a258c to your computer and use it in GitHub Desktop.
Save autch/90d1578e2c017e39c41ca20f917a258c to your computer and use it in GitHub Desktop.
CSTMのループ情報を LOOPSTART/LOOPLENGTH に変換して出力
#include <stdio.h>
#include <stdint.h>
// reference: https://www.3dbrew.org/wiki/BCSTM
#define CSTM_SIGNATURE 'MTSC'
#define CSTM_LITTLE_ENDIAN 0xfeff
#define CSTM_REF_TYPE_INFO 0x4000
#define CSTM_REF_TYPE_SEEK 0x4001
#define CSTM_REF_TYPE_DATA 0x4002
struct CSTM_reference
{
uint16_t type_id;
uint16_t padding;
uint32_t offset;
};
struct CSTM_sized_reference
{
struct CSTM_reference reference;
uint32_t size;
};
struct CSTM_header
{
uint32_t cstm;
uint16_t endianness;
uint16_t header_size;
uint32_t version;
uint32_t file_size;
uint16_t num_of_blocks;
uint16_t reserved1;
struct CSTM_sized_reference info_block;
struct CSTM_sized_reference seek_block;
struct CSTM_sized_reference data_block;
};
#define CSTM_BLOCK_INFO 'OFNI'
#define CSTM_BLOCK_SEEK 'KEES'
#define CSTM_BLOCK_DATA 'ATAD'
struct CSTM_block_header
{
uint32_t magic;
uint32_t size;
};
struct CSTM_stream_info
{
uint8_t encoding;
uint8_t looped;
uint8_t channel_count;
uint8_t padding;
uint32_t sample_rate;
uint32_t loop_start_frame;
uint32_t loop_end_frame;
uint32_t sample_block_count;
uint32_t sample_block_size;
uint32_t sample_block_sample_count;
uint32_t last_sample_block_size;
uint32_t last_sample_block_padded_size;
uint32_t seek_data_size;
uint32_t seek_interval_sample_count;
struct CSTM_reference sample_data_reference;
};
struct CSTM_info_block
{
struct CSTM_block_header header;
struct CSTM_reference stream_info_reference;
struct CSTM_reference track_info_reference;
struct CSTM_reference channel_info_reference;
struct CSTM_stream_info stream_info;
// ...
};
int get_loop_info(char* filename)
{
FILE* fp = fopen(filename, "rb");
if(!fp) {
fprintf(stderr, "Cannot open %s\n", filename);
return -1;
}
struct CSTM_header file_header;
fread(&file_header, sizeof file_header, 1, fp);
if(file_header.cstm != CSTM_SIGNATURE) {
fprintf(stderr, "%s: is not a CSTM\n", filename);
fclose(fp);
return -1;
}
if(file_header.endianness != CSTM_LITTLE_ENDIAN) {
fprintf(stderr, "%s: unsupported endianness\n", filename);
fclose(fp);
return -1;
}
if(file_header.info_block.reference.type_id != CSTM_REF_TYPE_INFO) {
fprintf(stderr, "%s: unexpected info block layout\n", filename);
fclose(fp);
return -1;
}
fseek(fp, file_header.info_block.reference.offset, SEEK_SET);
struct CSTM_info_block info_block;
fread(&info_block, sizeof info_block, 1, fp);
if(info_block.header.magic != CSTM_BLOCK_INFO) {
fprintf(stderr, "%s: referenced info block is not actuaully an info block\n", filename);
fclose(fp);
return -1;
}
printf("[%s]\n", filename);
printf("LOOPSTART=%d\n", info_block.stream_info.loop_start_frame);
printf("LOOPLENGTH=%d\n", info_block.stream_info.loop_end_frame
- info_block.stream_info.loop_start_frame);
printf("\n");
fclose(fp);
return 0;
}
int main(int ac, char** av)
{
if(ac == 1) {
fprintf(stderr, "Usage: %s *.bcstm...\n", *av);
return 1;
}
av++;
while(*av)
{
get_loop_info(*av);
av++;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment