156 lines
3.8 KiB
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;
|
|
}
|