idtech2-tools/wav2loop.c

156 lines
3.8 KiB
C

/*
* Copyright (c) 2014-2021 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* open a .wav file, add a loop point for idTech
this exists solely because nobody makes this easy
and convenient or hell even automated.
don't ask me what's wrong with the software dev
community but not even Audacity of all things can
do something as miniscule as adding cue points
to a .WAV file in the first quarter of the 21st century
people actually submitted patches but those went ignored.
why bother contributing when you have to do everything
yourself anyway ~eukara
*/
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
/* so it's easier to fwrite */
typedef struct
{
char cuehead[4];
int chunk_size;
int numcues;
int cueid;
int cuepos;
char datahead[4];
int chunk_start;
int block_start;
int sample_offset;
} loop_t;
/* -o enables users to specify at which point in the sample to start */
static int sample_offset;
void process_wav2loop(char *filename)
{
FILE *fWAV;
FILE *fLOOP;
size_t szWAV;
char *buffer;
loop_t loopy;
fWAV = fopen(filename, "rb");
if (!fWAV) {
fprintf(stderr, "couldn't find %s\n", filename);
return;
}
/* get wav file size */
fseek(fWAV, 0L, SEEK_END);
szWAV = (size_t)ftell(fWAV);
fseek(fWAV, 0L, SEEK_SET);
/* load wav into memory */
buffer = (char *)malloc(szWAV);
if (buffer == NULL) {
fprintf(stderr, "error: Memory allocation failed. Exiting.\n");
exit(0);
}
fread(buffer, 1, szWAV, fWAV);
fclose(fWAV);
/* this is LAZY, however we're not going to bother writing a full WAV loader LMAO */
for (int i = 0; i < (szWAV - 4); i++ ) {
if (buffer[i] == 'c')
if (buffer[i+1] == 'u')
if (buffer[i+2] == 'e')
if (buffer[i+3] == ' ') {
fprintf(stderr, "wav file %s has cue info already\n", filename);
goto end;
}
}
/* this is quite stupid, we're just appending it at the end,
we don't even care if there already are other cue marks */
fLOOP = fopen(filename, "w+b");
fwrite(buffer, 1, szWAV, fLOOP);
loopy.cuehead[0] = 'c';
loopy.cuehead[1] = 'u';
loopy.cuehead[2] = 'e';
loopy.cuehead[3] = ' ';
loopy.chunk_size = 28;
loopy.numcues = 1;
loopy.cueid = 0;
loopy.cuepos = 0;
loopy.datahead[0] = 'd';
loopy.datahead[1] = 'a';
loopy.datahead[2] = 't';
loopy.datahead[3] = 'a';
loopy.chunk_start = 0;
loopy.block_start = 0;
loopy.sample_offset = sample_offset;
/* append our data to the end of the file */
fwrite(&loopy, 1, sizeof(loop_t), fLOOP);
fclose(fLOOP);
/* inb4 goto considered harmful */
end:
free(buffer);
}
int main(int argc, char *argv[])
{
int c, ch;
if (argc <= 1) {
fprintf(stderr, "usage: wav2loop [-o offset] file.wav ...\n");
return 1;
}
/* by default, we loop at the very start */
sample_offset = 0;
/* process arguments: TODO: add more? probably not */
while ((ch = getopt(argc, argv, "o")) != -1) {
switch (ch) {
case 'o':
sample_offset = atoi(argv[optind]);
optind++;
printf("sample offset: %i\n", sample_offset);
break;
default:
return 1;
}
}
argc -= optind;
argv += optind;
for (c = 0; c < argc; c++)
process_wav2loop(argv[c]);
return 0;
}