mirror of
https://github.com/pret/pokefirered.git
synced 2026-05-09 12:35:23 -05:00
update tools
This commit is contained in:
parent
c30df7a808
commit
3b866928b7
2
tools/aif2pcm_old/.gitignore
vendored
2
tools/aif2pcm_old/.gitignore
vendored
|
|
@ -1,2 +0,0 @@
|
|||
aif2pcm
|
||||
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
Copyright (c) 2016 huderlem
|
||||
Copyright (c) 2005, 2006 by Marco Trillo <marcotrillo@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
CC = gcc
|
||||
|
||||
CFLAGS = -Wall -Wextra -Wno-switch -Werror -std=c11 -O2
|
||||
|
||||
LIBS = -lm
|
||||
|
||||
SRCS = main.c extended.c
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: aif2pcm
|
||||
@:
|
||||
|
||||
aif2pcm: $(SRCS)
|
||||
$(CC) $(CFLAGS) $(SRCS) -o $@ $(LDFLAGS) $(LIBS)
|
||||
|
||||
clean:
|
||||
$(RM) aif2pcm aif2pcm.exe
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
/* $Id: extended.c,v 1.8 2006/12/23 11:17:49 toad32767 Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 2005, 2006 by Marco Trillo <marcotrillo@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any
|
||||
* person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the
|
||||
* Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice
|
||||
* shall be included in all copies or substantial portions of
|
||||
* the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
* KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
||||
* OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* Infinite & NAN values
|
||||
* for non-IEEE systems
|
||||
*/
|
||||
#ifndef HUGE_VAL
|
||||
#ifdef HUGE
|
||||
#define INFINITE_VALUE HUGE
|
||||
#define NAN_VALUE HUGE
|
||||
#endif
|
||||
#else
|
||||
#define INFINITE_VALUE HUGE_VAL
|
||||
#define NAN_VALUE HUGE_VAL
|
||||
#endif
|
||||
|
||||
/*
|
||||
* IEEE 754 Extended Precision
|
||||
*
|
||||
* Implementation here is the 80-bit extended precision
|
||||
* format of Motorola 68881, Motorola 68882 and Motorola
|
||||
* 68040 FPUs, as well as Intel 80x87 FPUs.
|
||||
*
|
||||
* See:
|
||||
* http://www.freescale.com/files/32bit/doc/fact_sheet/BR509.pdf
|
||||
*/
|
||||
/*
|
||||
* Exponent range: [-16383,16383]
|
||||
* Precision for mantissa: 64 bits with no hidden bit
|
||||
* Bias: 16383
|
||||
*/
|
||||
|
||||
/*
|
||||
* Write IEEE Extended Precision Numbers
|
||||
*/
|
||||
void
|
||||
ieee754_write_extended(double in, uint8_t* out)
|
||||
{
|
||||
int sgn, exp, shift;
|
||||
double fraction, t;
|
||||
unsigned int lexp, hexp;
|
||||
unsigned long low, high;
|
||||
|
||||
if (in == 0.0) {
|
||||
memset(out, 0, 10);
|
||||
return;
|
||||
}
|
||||
if (in < 0.0) {
|
||||
in = fabs(in);
|
||||
sgn = 1;
|
||||
} else
|
||||
sgn = 0;
|
||||
|
||||
fraction = frexp(in, &exp);
|
||||
|
||||
if (exp == 0 || exp > 16384) {
|
||||
if (exp > 16384) /* infinite value */
|
||||
low = high = 0;
|
||||
else {
|
||||
low = 0x80000000;
|
||||
high = 0;
|
||||
}
|
||||
exp = 32767;
|
||||
goto done;
|
||||
}
|
||||
fraction = ldexp(fraction, 32);
|
||||
t = floor(fraction);
|
||||
low = (unsigned long) t;
|
||||
fraction -= t;
|
||||
t = floor(ldexp(fraction, 32));
|
||||
high = (unsigned long) t;
|
||||
|
||||
/* Convert exponents < -16382 to -16382 (then they will be
|
||||
* stored as -16383) */
|
||||
if (exp < -16382) {
|
||||
shift = 0 - exp - 16382;
|
||||
high >>= shift;
|
||||
high |= (low << (32 - shift));
|
||||
low >>= shift;
|
||||
exp = -16382;
|
||||
}
|
||||
exp += 16383 - 1; /* bias */
|
||||
|
||||
done:
|
||||
lexp = ((unsigned int) exp) >> 8;
|
||||
hexp = ((unsigned int) exp) & 0xFF;
|
||||
|
||||
/* big endian */
|
||||
out[0] = ((uint8_t) sgn) << 7;
|
||||
out[0] |= (uint8_t) lexp;
|
||||
out[1] = (uint8_t) hexp;
|
||||
out[2] = (uint8_t) (low >> 24);
|
||||
out[3] = (uint8_t) ((low >> 16) & 0xFF);
|
||||
out[4] = (uint8_t) ((low >> 8) & 0xFF);
|
||||
out[5] = (uint8_t) (low & 0xFF);
|
||||
out[6] = (uint8_t) (high >> 24);
|
||||
out[7] = (uint8_t) ((high >> 16) & 0xFF);
|
||||
out[8] = (uint8_t) ((high >> 8) & 0xFF);
|
||||
out[9] = (uint8_t) (high & 0xFF);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read IEEE Extended Precision Numbers
|
||||
*/
|
||||
double
|
||||
ieee754_read_extended(uint8_t* in)
|
||||
{
|
||||
int sgn, exp;
|
||||
unsigned long low, high;
|
||||
double out;
|
||||
|
||||
/* Extract the components from the big endian buffer */
|
||||
sgn = (int) (in[0] >> 7);
|
||||
exp = ((int) (in[0] & 0x7F) << 8) | ((int) in[1]);
|
||||
low = (((unsigned long) in[2]) << 24)
|
||||
| (((unsigned long) in[3]) << 16)
|
||||
| (((unsigned long) in[4]) << 8) | (unsigned long) in[5];
|
||||
high = (((unsigned long) in[6]) << 24)
|
||||
| (((unsigned long) in[7]) << 16)
|
||||
| (((unsigned long) in[8]) << 8) | (unsigned long) in[9];
|
||||
|
||||
if (exp == 0 && low == 0 && high == 0)
|
||||
return (sgn ? -0.0 : 0.0);
|
||||
|
||||
switch (exp) {
|
||||
case 32767:
|
||||
if (low == 0 && high == 0)
|
||||
return (sgn ? -INFINITE_VALUE : INFINITE_VALUE);
|
||||
else
|
||||
return (sgn ? -NAN_VALUE : NAN_VALUE);
|
||||
default:
|
||||
exp -= 16383; /* unbias exponent */
|
||||
|
||||
}
|
||||
|
||||
out = ldexp((double) low, -31 + exp);
|
||||
out += ldexp((double) high, -63 + exp);
|
||||
|
||||
return (sgn ? -out : out);
|
||||
}
|
||||
|
|
@ -1,888 +0,0 @@
|
|||
// Copyright(c) 2016 huderlem
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* extended.c */
|
||||
void ieee754_write_extended (double, uint8_t*);
|
||||
double ieee754_read_extended (uint8_t*);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#define FATAL_ERROR(format, ...) \
|
||||
do \
|
||||
{ \
|
||||
fprintf(stderr, format, __VA_ARGS__); \
|
||||
exit(1); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
#define FATAL_ERROR(format, ...) \
|
||||
do \
|
||||
{ \
|
||||
fprintf(stderr, format, ##__VA_ARGS__); \
|
||||
exit(1); \
|
||||
} while (0)
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
typedef struct {
|
||||
unsigned long num_samples;
|
||||
uint8_t *samples;
|
||||
uint8_t midi_note;
|
||||
bool has_loop;
|
||||
unsigned long loop_offset;
|
||||
double sample_rate;
|
||||
unsigned long real_num_samples;
|
||||
} AifData;
|
||||
|
||||
struct Bytes {
|
||||
unsigned long length;
|
||||
uint8_t *data;
|
||||
};
|
||||
|
||||
struct Marker {
|
||||
unsigned short id;
|
||||
unsigned long position;
|
||||
// don't care about the name
|
||||
};
|
||||
|
||||
struct Bytes *read_bytearray(const char *filename)
|
||||
{
|
||||
struct Bytes *bytes = malloc(sizeof(struct Bytes));
|
||||
FILE *f = fopen(filename, "rb");
|
||||
if (!f)
|
||||
{
|
||||
FATAL_ERROR("Failed to open '%s' for reading!\n", filename);
|
||||
}
|
||||
fseek(f, 0, SEEK_END);
|
||||
bytes->length = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
bytes->data = malloc(bytes->length);
|
||||
unsigned long read = fread(bytes->data, bytes->length, 1, f);
|
||||
fclose(f);
|
||||
if (read <= 0)
|
||||
{
|
||||
FATAL_ERROR("Failed to read data from '%s'!\n", filename);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void write_bytearray(const char *filename, struct Bytes *bytes)
|
||||
{
|
||||
FILE *f = fopen(filename, "wb");
|
||||
if (!f)
|
||||
{
|
||||
FATAL_ERROR("Failed to open '%s' for writing!\n", filename);
|
||||
}
|
||||
fwrite(bytes->data, bytes->length, 1, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void free_bytearray(struct Bytes *bytes)
|
||||
{
|
||||
free(bytes->data);
|
||||
free(bytes);
|
||||
}
|
||||
|
||||
char *get_file_extension(char *filename)
|
||||
{
|
||||
char *index = strrchr(filename, '.');
|
||||
if (!index || index == filename)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return index + 1;
|
||||
}
|
||||
|
||||
char *new_file_extension(char *filename, char *ext)
|
||||
{
|
||||
char *index = strrchr(filename, '.');
|
||||
if (!index || index == filename)
|
||||
{
|
||||
index = filename + strlen(filename);
|
||||
}
|
||||
int length = index - filename;
|
||||
char *new_filename = malloc(length + 1 + strlen(ext) + 1);
|
||||
if (new_filename)
|
||||
{
|
||||
strcpy(new_filename, filename);
|
||||
new_filename[length] = '.';
|
||||
strcpy(new_filename + length + 1, ext);
|
||||
}
|
||||
return new_filename;
|
||||
}
|
||||
|
||||
void read_aif(struct Bytes *aif, AifData *aif_data)
|
||||
{
|
||||
aif_data->has_loop = false;
|
||||
aif_data->num_samples = 0;
|
||||
|
||||
unsigned long pos = 0;
|
||||
char chunk_name[5]; chunk_name[4] = '\0';
|
||||
char chunk_type[5]; chunk_type[4] = '\0';
|
||||
|
||||
// Check for FORM Chunk
|
||||
memcpy(chunk_name, &aif->data[pos], 4);
|
||||
pos += 4;
|
||||
if (strcmp(chunk_name, "FORM") != 0)
|
||||
{
|
||||
FATAL_ERROR("Input .aif file has invalid header Chunk '%s'!\n", chunk_name);
|
||||
}
|
||||
|
||||
// Read size of whole file.
|
||||
unsigned long whole_chunk_size = aif->data[pos++] << 24;
|
||||
whole_chunk_size |= (aif->data[pos++] << 16);
|
||||
whole_chunk_size |= (aif->data[pos++] << 8);
|
||||
whole_chunk_size |= (uint8_t)aif->data[pos++];
|
||||
|
||||
unsigned long expected_whole_chunk_size = aif->length - 8;
|
||||
if (whole_chunk_size != expected_whole_chunk_size)
|
||||
{
|
||||
FATAL_ERROR("FORM Chunk ckSize '%lu' doesn't match actual size '%lu'!\n", whole_chunk_size, expected_whole_chunk_size);
|
||||
}
|
||||
|
||||
// Check for AIFF Form Type
|
||||
memcpy(chunk_type, &aif->data[pos], 4);
|
||||
pos += 4;
|
||||
if (strcmp(chunk_type, "AIFF") != 0)
|
||||
{
|
||||
FATAL_ERROR("FORM Type is '%s', but it must be AIFF!", chunk_type);
|
||||
}
|
||||
|
||||
struct Marker *markers = NULL;
|
||||
unsigned short num_markers = 0, loop_start = 0, loop_end = 0;
|
||||
unsigned long num_sample_frames = 0;
|
||||
|
||||
// Read all the Chunks to populate the AifData struct.
|
||||
while ((pos + 8) < aif->length)
|
||||
{
|
||||
// Read Chunk id
|
||||
memcpy(chunk_name, &aif->data[pos], 4);
|
||||
pos += 4;
|
||||
|
||||
unsigned long chunk_size = (aif->data[pos++] << 24);
|
||||
chunk_size |= (aif->data[pos++] << 16);
|
||||
chunk_size |= (aif->data[pos++] << 8);
|
||||
chunk_size |= aif->data[pos++];
|
||||
|
||||
if ((pos + chunk_size) > aif->length)
|
||||
{
|
||||
FATAL_ERROR("%s chunk at 0x%lx reached end of file before finishing\n", chunk_name, pos);
|
||||
}
|
||||
|
||||
if (strcmp(chunk_name, "COMM") == 0)
|
||||
{
|
||||
short num_channels = (aif->data[pos++] << 8);
|
||||
num_channels |= (uint8_t)aif->data[pos++];
|
||||
if (num_channels != 1)
|
||||
{
|
||||
FATAL_ERROR("numChannels (%d) in the COMM Chunk must be 1!\n", num_channels);
|
||||
}
|
||||
|
||||
num_sample_frames = (aif->data[pos++] << 24);
|
||||
num_sample_frames |= (aif->data[pos++] << 16);
|
||||
num_sample_frames |= (aif->data[pos++] << 8);
|
||||
num_sample_frames |= (uint8_t)aif->data[pos++];
|
||||
|
||||
short sample_size = (aif->data[pos++] << 8);
|
||||
sample_size |= (uint8_t)aif->data[pos++];
|
||||
if (sample_size != 8)
|
||||
{
|
||||
FATAL_ERROR("sampleSize (%d) in the COMM Chunk must be 8!\n", sample_size);
|
||||
}
|
||||
|
||||
double sample_rate = ieee754_read_extended((uint8_t*)(aif->data + pos));
|
||||
pos += 10;
|
||||
|
||||
aif_data->sample_rate = sample_rate;
|
||||
|
||||
if (aif_data->num_samples == 0)
|
||||
{
|
||||
aif_data->num_samples = num_sample_frames;
|
||||
}
|
||||
}
|
||||
else if (strcmp(chunk_name, "MARK") == 0)
|
||||
{
|
||||
num_markers = (aif->data[pos++] << 8);
|
||||
num_markers |= (uint8_t)aif->data[pos++];
|
||||
|
||||
if (markers)
|
||||
{
|
||||
FATAL_ERROR("More than one MARK Chunk in file!\n");
|
||||
}
|
||||
|
||||
markers = calloc(num_markers, sizeof(struct Marker));
|
||||
|
||||
// Read each marker.
|
||||
for (int i = 0; i < num_markers; i++)
|
||||
{
|
||||
unsigned short marker_id = (aif->data[pos++] << 8);
|
||||
marker_id |= (uint8_t)aif->data[pos++];
|
||||
|
||||
unsigned long marker_position = (aif->data[pos++] << 24);
|
||||
marker_position |= (aif->data[pos++] << 16);
|
||||
marker_position |= (aif->data[pos++] << 8);
|
||||
marker_position |= (uint8_t)aif->data[pos++];
|
||||
|
||||
// Marker name is a Pascal-style string.
|
||||
uint8_t marker_name_size = aif->data[pos++];
|
||||
// We don't actually need the marker name for anything anymore.
|
||||
/*char *marker_name = (char *)malloc((marker_name_size + 1) * sizeof(char));
|
||||
memcpy(marker_name, &aif->data[pos], marker_name_size);
|
||||
marker_name[marker_name_size] = '\0';*/
|
||||
pos += marker_name_size + !(marker_name_size & 1);
|
||||
|
||||
markers[i].id = marker_id;
|
||||
markers[i].position = marker_position;
|
||||
}
|
||||
}
|
||||
else if (strcmp(chunk_name, "INST") == 0)
|
||||
{
|
||||
uint8_t midi_note = (uint8_t)aif->data[pos++];
|
||||
|
||||
aif_data->midi_note = midi_note;
|
||||
|
||||
// Skip over data we don't need.
|
||||
pos += 7;
|
||||
|
||||
unsigned short loop_type = (aif->data[pos++] << 8);
|
||||
loop_type |= (uint8_t)aif->data[pos++];
|
||||
|
||||
if (loop_type)
|
||||
{
|
||||
loop_start = (aif->data[pos++] << 8);
|
||||
loop_start |= (uint8_t)aif->data[pos++];
|
||||
|
||||
loop_end = (aif->data[pos++] << 8);
|
||||
loop_end |= (uint8_t)aif->data[pos++];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Skip NoLooping sustain loop.
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
// Skip release loop, we don't need it.
|
||||
pos += 6;
|
||||
}
|
||||
else if (strcmp(chunk_name, "SSND") == 0)
|
||||
{
|
||||
// Skip offset and blockSize
|
||||
pos += 8;
|
||||
|
||||
unsigned long num_samples = chunk_size - 8;
|
||||
uint8_t *sample_data = (uint8_t *)malloc(num_samples * sizeof(uint8_t));
|
||||
memcpy(sample_data, &aif->data[pos], num_samples);
|
||||
|
||||
aif_data->samples = sample_data;
|
||||
aif_data->real_num_samples = num_samples;
|
||||
pos += chunk_size - 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Skip over unsupported chunks.
|
||||
pos += chunk_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (markers)
|
||||
{
|
||||
// Resolve loop points.
|
||||
struct Marker *cur_marker = markers;
|
||||
|
||||
// Grab loop start point.
|
||||
for (int i = 0; i < num_markers; i++, cur_marker++)
|
||||
{
|
||||
if (cur_marker->id == loop_start)
|
||||
{
|
||||
aif_data->loop_offset = cur_marker->position;
|
||||
aif_data->has_loop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cur_marker = markers;
|
||||
|
||||
// Grab loop end point.
|
||||
for (int i = 0; i < num_markers; i++, cur_marker++)
|
||||
{
|
||||
if (cur_marker->id == loop_end)
|
||||
{
|
||||
if (cur_marker->position < aif_data->loop_offset) {
|
||||
aif_data->loop_offset = cur_marker->position;
|
||||
aif_data->has_loop = true;
|
||||
}
|
||||
aif_data->num_samples = cur_marker->position;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(markers);
|
||||
}
|
||||
}
|
||||
|
||||
// This is a table of deltas between sample values in compressed PCM data.
|
||||
const int gDeltaEncodingTable[] = {
|
||||
0, 1, 4, 9, 16, 25, 36, 49,
|
||||
-64, -49, -36, -25, -16, -9, -4, -1,
|
||||
};
|
||||
|
||||
struct Bytes *delta_decompress(struct Bytes *delta, unsigned int expected_length)
|
||||
{
|
||||
struct Bytes *pcm = malloc(sizeof(struct Bytes));
|
||||
pcm->length = expected_length;
|
||||
pcm->data = malloc(pcm->length + 0x40);
|
||||
|
||||
uint8_t hi, lo;
|
||||
unsigned int i = 0;
|
||||
unsigned int j = 0;
|
||||
int k;
|
||||
int8_t base;
|
||||
while (i < delta->length)
|
||||
{
|
||||
base = (int8_t)delta->data[i++];
|
||||
pcm->data[j++] = (uint8_t)base;
|
||||
if (i >= delta->length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (j >= pcm->length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
lo = delta->data[i] & 0xf;
|
||||
base += gDeltaEncodingTable[lo];
|
||||
pcm->data[j++] = base;
|
||||
i++;
|
||||
if (i >= delta->length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (j >= pcm->length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
for (k = 0; k < 31; k++)
|
||||
{
|
||||
hi = (delta->data[i] >> 4) & 0xf;
|
||||
base += gDeltaEncodingTable[hi];
|
||||
pcm->data[j++] = base;
|
||||
if (j >= pcm->length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
lo = delta->data[i] & 0xf;
|
||||
base += gDeltaEncodingTable[lo];
|
||||
pcm->data[j++] = base;
|
||||
i++;
|
||||
if (i >= delta->length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (j >= pcm->length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j >= pcm->length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pcm->length = j;
|
||||
return pcm;
|
||||
}
|
||||
|
||||
int get_delta_index(uint8_t sample, uint8_t prev_sample)
|
||||
{
|
||||
int best_error = INT_MAX;
|
||||
int best_index = -1;
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
uint8_t new_sample = prev_sample + gDeltaEncodingTable[i];
|
||||
int error = sample > new_sample ? sample - new_sample : new_sample - sample;
|
||||
|
||||
if (error < best_error)
|
||||
{
|
||||
best_error = error;
|
||||
best_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
return best_index;
|
||||
}
|
||||
|
||||
struct Bytes *delta_compress(struct Bytes *pcm)
|
||||
{
|
||||
struct Bytes *delta = malloc(sizeof(struct Bytes));
|
||||
// estimate the length so we can malloc
|
||||
int num_blocks = pcm->length / 64;
|
||||
delta->length = num_blocks * 33;
|
||||
|
||||
int extra = pcm->length % 64;
|
||||
if (extra)
|
||||
{
|
||||
delta->length += 1;
|
||||
extra -= 1;
|
||||
}
|
||||
if (extra)
|
||||
{
|
||||
delta->length += 1;
|
||||
extra -= 1;
|
||||
}
|
||||
if (extra)
|
||||
{
|
||||
delta->length += (extra + 1) / 2;
|
||||
}
|
||||
|
||||
delta->data = malloc(delta->length + 33);
|
||||
|
||||
unsigned int i = 0;
|
||||
unsigned int j = 0;
|
||||
int k;
|
||||
uint8_t base;
|
||||
int delta_index;
|
||||
|
||||
while (i < pcm->length)
|
||||
{
|
||||
base = pcm->data[i++];
|
||||
delta->data[j++] = base;
|
||||
|
||||
if (i >= pcm->length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
delta_index = get_delta_index(pcm->data[i++], base);
|
||||
base += gDeltaEncodingTable[delta_index];
|
||||
delta->data[j++] = delta_index;
|
||||
|
||||
for (k = 0; k < 31; k++)
|
||||
{
|
||||
if (i >= pcm->length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
delta_index = get_delta_index(pcm->data[i++], base);
|
||||
base += gDeltaEncodingTable[delta_index];
|
||||
delta->data[j] = (delta_index << 4);
|
||||
|
||||
if (i >= pcm->length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
delta_index = get_delta_index(pcm->data[i++], base);
|
||||
base += gDeltaEncodingTable[delta_index];
|
||||
delta->data[j++] |= delta_index;
|
||||
}
|
||||
}
|
||||
|
||||
delta->length = j;
|
||||
|
||||
return delta;
|
||||
}
|
||||
|
||||
#define STORE_U32_LE(dest, value) \
|
||||
do { \
|
||||
*(dest) = (value) & 0xff; \
|
||||
*((dest) + 1) = ((value) >> 8) & 0xff; \
|
||||
*((dest) + 2) = ((value) >> 16) & 0xff; \
|
||||
*((dest) + 3) = ((value) >> 24) & 0xff; \
|
||||
} while (0)
|
||||
|
||||
#define LOAD_U32_LE(var, src) \
|
||||
do { \
|
||||
(var) = *(src); \
|
||||
(var) |= (*((src) + 1) << 8); \
|
||||
(var) |= (*((src) + 2) << 16); \
|
||||
(var) |= (*((src) + 3) << 24); \
|
||||
} while (0)
|
||||
|
||||
// Reads an .aif file and produces a .pcm file containing an array of 8-bit samples.
|
||||
void aif2pcm(const char *aif_filename, const char *pcm_filename, bool compress)
|
||||
{
|
||||
struct Bytes *aif = read_bytearray(aif_filename);
|
||||
AifData aif_data = {0,0,0,0,0,0,0};
|
||||
read_aif(aif, &aif_data);
|
||||
|
||||
int header_size = 0x10;
|
||||
struct Bytes *pcm;
|
||||
struct Bytes output = {0,0};
|
||||
|
||||
if (compress)
|
||||
{
|
||||
struct Bytes *input = malloc(sizeof(struct Bytes));
|
||||
input->data = aif_data.samples;
|
||||
input->length = aif_data.real_num_samples;
|
||||
pcm = delta_compress(input);
|
||||
free(input);
|
||||
}
|
||||
else
|
||||
{
|
||||
pcm = malloc(sizeof(struct Bytes));
|
||||
pcm->data = aif_data.samples;
|
||||
pcm->length = aif_data.real_num_samples;
|
||||
}
|
||||
output.length = header_size + pcm->length;
|
||||
output.data = malloc(output.length);
|
||||
|
||||
uint32_t pitch_adjust = (uint32_t)(aif_data.sample_rate * 1024);
|
||||
uint32_t loop_offset = (uint32_t)(aif_data.loop_offset);
|
||||
uint32_t adjusted_num_samples = (uint32_t)(aif_data.num_samples - 1);
|
||||
uint32_t flags = 0;
|
||||
if (aif_data.has_loop) flags |= 0x40000000;
|
||||
if (compress) flags |= 1;
|
||||
STORE_U32_LE(output.data + 0, flags);
|
||||
STORE_U32_LE(output.data + 4, pitch_adjust);
|
||||
STORE_U32_LE(output.data + 8, loop_offset);
|
||||
STORE_U32_LE(output.data + 12, adjusted_num_samples);
|
||||
memcpy(&output.data[header_size], pcm->data, pcm->length);
|
||||
write_bytearray(pcm_filename, &output);
|
||||
|
||||
free(aif->data);
|
||||
free(aif);
|
||||
free(pcm);
|
||||
free(output.data);
|
||||
free(aif_data.samples);
|
||||
}
|
||||
|
||||
// Reads a .pcm file containing an array of 8-bit samples and produces an .aif file.
|
||||
// See http://www-mmsp.ece.mcgill.ca/documents/audioformats/aiff/Docs/AIFF-1.3.pdf for .aif file specification.
|
||||
void pcm2aif(const char *pcm_filename, const char *aif_filename, uint32_t base_note)
|
||||
{
|
||||
struct Bytes *pcm = read_bytearray(pcm_filename);
|
||||
|
||||
AifData *aif_data = malloc(sizeof(AifData));
|
||||
|
||||
uint32_t flags;
|
||||
LOAD_U32_LE(flags, pcm->data + 0);
|
||||
aif_data->has_loop = flags & 0x40000000;
|
||||
bool compressed = flags & 1;
|
||||
|
||||
uint32_t pitch_adjust;
|
||||
LOAD_U32_LE(pitch_adjust, pcm->data + 4);
|
||||
aif_data->sample_rate = pitch_adjust / 1024.0;
|
||||
|
||||
LOAD_U32_LE(aif_data->loop_offset, pcm->data + 8);
|
||||
LOAD_U32_LE(aif_data->num_samples, pcm->data + 12);
|
||||
aif_data->num_samples += 1;
|
||||
|
||||
if (compressed)
|
||||
{
|
||||
struct Bytes *delta = pcm;
|
||||
uint8_t *pcm_data = pcm->data;
|
||||
delta->length -= 0x10;
|
||||
delta->data += 0x10;
|
||||
pcm = delta_decompress(delta, aif_data->num_samples);
|
||||
free(pcm_data);
|
||||
free(delta);
|
||||
}
|
||||
else
|
||||
{
|
||||
pcm->length -= 0x10;
|
||||
pcm->data += 0x10;
|
||||
}
|
||||
|
||||
aif_data->samples = malloc(pcm->length);
|
||||
memcpy(aif_data->samples, pcm->data, pcm->length);
|
||||
|
||||
struct Bytes *aif = malloc(sizeof(struct Bytes));
|
||||
aif->length = 54 + 60 + pcm->length;
|
||||
aif->data = malloc(aif->length);
|
||||
|
||||
long pos = 0;
|
||||
|
||||
// First, write the FORM header chunk.
|
||||
// FORM Chunk ckID
|
||||
aif->data[pos++] = 'F';
|
||||
aif->data[pos++] = 'O';
|
||||
aif->data[pos++] = 'R';
|
||||
aif->data[pos++] = 'M';
|
||||
|
||||
// FORM Chunk ckSize
|
||||
unsigned long form_size = pos;
|
||||
unsigned long data_size = aif->length - 8;
|
||||
aif->data[pos++] = ((data_size >> 24) & 0xFF);
|
||||
aif->data[pos++] = ((data_size >> 16) & 0xFF);
|
||||
aif->data[pos++] = ((data_size >> 8) & 0xFF);
|
||||
aif->data[pos++] = (data_size & 0xFF);
|
||||
|
||||
// FORM Chunk formType
|
||||
aif->data[pos++] = 'A';
|
||||
aif->data[pos++] = 'I';
|
||||
aif->data[pos++] = 'F';
|
||||
aif->data[pos++] = 'F';
|
||||
|
||||
// Next, write the Common Chunk
|
||||
// Common Chunk ckID
|
||||
aif->data[pos++] = 'C';
|
||||
aif->data[pos++] = 'O';
|
||||
aif->data[pos++] = 'M';
|
||||
aif->data[pos++] = 'M';
|
||||
|
||||
// Common Chunk ckSize
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 18;
|
||||
|
||||
// Common Chunk numChannels
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 1; // 1 channel
|
||||
|
||||
// Common Chunk numSampleFrames
|
||||
aif->data[pos++] = ((aif_data->num_samples >> 24) & 0xFF);
|
||||
aif->data[pos++] = ((aif_data->num_samples >> 16) & 0xFF);
|
||||
aif->data[pos++] = ((aif_data->num_samples >> 8) & 0xFF);
|
||||
aif->data[pos++] = (aif_data->num_samples & 0xFF);
|
||||
|
||||
// Common Chunk sampleSize
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 8; // 8 bits per sample
|
||||
|
||||
// Common Chunk sampleRate
|
||||
//double sample_rate = pitch_adjust / 1024.0;
|
||||
uint8_t sample_rate_buffer[10];
|
||||
ieee754_write_extended(aif_data->sample_rate, sample_rate_buffer);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
aif->data[pos++] = sample_rate_buffer[i];
|
||||
}
|
||||
|
||||
if (aif_data->has_loop)
|
||||
{
|
||||
|
||||
// Marker Chunk ckID
|
||||
aif->data[pos++] = 'M';
|
||||
aif->data[pos++] = 'A';
|
||||
aif->data[pos++] = 'R';
|
||||
aif->data[pos++] = 'K';
|
||||
|
||||
// Marker Chunk ckSize
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 12 + (aif_data->has_loop ? 12 : 0);
|
||||
|
||||
// Marker Chunk numMarkers
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = (aif_data->has_loop ? 2 : 1);
|
||||
|
||||
// Marker loop start
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 1; // id = 1
|
||||
|
||||
long loop_start = aif_data->loop_offset;
|
||||
aif->data[pos++] = ((loop_start >> 24) & 0xFF);
|
||||
aif->data[pos++] = ((loop_start >> 16) & 0xFF);
|
||||
aif->data[pos++] = ((loop_start >> 8) & 0xFF);
|
||||
aif->data[pos++] = (loop_start & 0xFF); // position
|
||||
|
||||
aif->data[pos++] = 5; // pascal-style string length
|
||||
aif->data[pos++] = 'S';
|
||||
aif->data[pos++] = 'T';
|
||||
aif->data[pos++] = 'A';
|
||||
aif->data[pos++] = 'R';
|
||||
aif->data[pos++] = 'T'; // markerName
|
||||
|
||||
// Marker loop end
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = (aif_data->has_loop ? 2 : 1); // id = 2
|
||||
|
||||
long loop_end = aif_data->num_samples;
|
||||
aif->data[pos++] = ((loop_end >> 24) & 0xFF);
|
||||
aif->data[pos++] = ((loop_end >> 16) & 0xFF);
|
||||
aif->data[pos++] = ((loop_end >> 8) & 0xFF);
|
||||
aif->data[pos++] = (loop_end & 0xFF); // position
|
||||
|
||||
aif->data[pos++] = 3; // pascal-style string length
|
||||
aif->data[pos++] = 'E';
|
||||
aif->data[pos++] = 'N';
|
||||
aif->data[pos++] = 'D';
|
||||
}
|
||||
|
||||
// Instrument Chunk ckID
|
||||
aif->data[pos++] = 'I';
|
||||
aif->data[pos++] = 'N';
|
||||
aif->data[pos++] = 'S';
|
||||
aif->data[pos++] = 'T';
|
||||
|
||||
// Instrument Chunk ckSize
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 20;
|
||||
|
||||
aif->data[pos++] = base_note; // baseNote
|
||||
aif->data[pos++] = 0; // detune
|
||||
aif->data[pos++] = 0; // lowNote
|
||||
aif->data[pos++] = 127; // highNote
|
||||
aif->data[pos++] = 1; // lowVelocity
|
||||
aif->data[pos++] = 127; // highVelocity
|
||||
aif->data[pos++] = 0; // gain (hi)
|
||||
aif->data[pos++] = 0; // gain (lo)
|
||||
|
||||
// Instrument Chunk sustainLoop
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 1; // playMode = ForwardLooping
|
||||
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 1; // beginLoop marker id
|
||||
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 2; // endLoop marker id
|
||||
|
||||
// Instrument Chunk releaseLoop
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 1; // playMode = ForwardLooping
|
||||
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 1; // beginLoop marker id
|
||||
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 2; // endLoop marker id
|
||||
|
||||
// Finally, write the Sound Data Chunk
|
||||
// Sound Data Chunk ckID
|
||||
aif->data[pos++] = 'S';
|
||||
aif->data[pos++] = 'S';
|
||||
aif->data[pos++] = 'N';
|
||||
aif->data[pos++] = 'D';
|
||||
|
||||
// Sound Data Chunk ckSize
|
||||
unsigned long sound_data_size = pcm->length + 8;
|
||||
aif->data[pos++] = ((sound_data_size >> 24) & 0xFF);
|
||||
aif->data[pos++] = ((sound_data_size >> 16) & 0xFF);
|
||||
aif->data[pos++] = ((sound_data_size >> 8) & 0xFF);
|
||||
aif->data[pos++] = (sound_data_size & 0xFF);
|
||||
|
||||
// Sound Data Chunk offset
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 0;
|
||||
|
||||
// Sound Data Chunk blockSize
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 0;
|
||||
aif->data[pos++] = 0;
|
||||
|
||||
// Sound Data Chunk soundData
|
||||
for (unsigned int i = 0; i < aif_data->loop_offset; i++)
|
||||
{
|
||||
aif->data[pos++] = aif_data->samples[i];
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
for (unsigned int i = aif_data->loop_offset; i < pcm->length; i++)
|
||||
{
|
||||
int pcm_index = aif_data->loop_offset + (j++ % (pcm->length - aif_data->loop_offset));
|
||||
aif->data[pos++] = aif_data->samples[pcm_index];
|
||||
}
|
||||
|
||||
aif->length = pos;
|
||||
|
||||
// Go back and rewrite ckSize
|
||||
data_size = aif->length - 8;
|
||||
aif->data[form_size + 0] = ((data_size >> 24) & 0xFF);
|
||||
aif->data[form_size + 1] = ((data_size >> 16) & 0xFF);
|
||||
aif->data[form_size + 2] = ((data_size >> 8) & 0xFF);
|
||||
aif->data[form_size + 3] = (data_size & 0xFF);
|
||||
|
||||
write_bytearray(aif_filename, aif);
|
||||
|
||||
free(aif->data);
|
||||
free(aif);
|
||||
}
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: aif2pcm bin_file [aif_file]\n");
|
||||
fprintf(stderr, " aif2pcm aif_file [bin_file] [--compress]\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *input_file = argv[1];
|
||||
char *extension = get_file_extension(input_file);
|
||||
char *output_file;
|
||||
bool compressed = false;
|
||||
|
||||
if (argc > 3)
|
||||
{
|
||||
for (int i = 3; i < argc; i++)
|
||||
{
|
||||
if (strcmp(argv[i], "--compress") == 0)
|
||||
{
|
||||
compressed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(extension, "aif") == 0 || strcmp(extension, "aiff") == 0)
|
||||
{
|
||||
if (argc >= 3)
|
||||
{
|
||||
output_file = argv[2];
|
||||
aif2pcm(input_file, output_file, compressed);
|
||||
}
|
||||
else
|
||||
{
|
||||
output_file = new_file_extension(input_file, "bin");
|
||||
aif2pcm(input_file, output_file, compressed);
|
||||
free(output_file);
|
||||
}
|
||||
}
|
||||
else if (strcmp(extension, "bin") == 0)
|
||||
{
|
||||
if (argc >= 3)
|
||||
{
|
||||
output_file = argv[2];
|
||||
pcm2aif(input_file, output_file, 60);
|
||||
}
|
||||
else
|
||||
{
|
||||
output_file = new_file_extension(input_file, "aif");
|
||||
pcm2aif(input_file, output_file, 60);
|
||||
free(output_file);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FATAL_ERROR("Input file must be .aif or .bin: '%s'\n", input_file);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
CXX ?= g++
|
||||
|
||||
CXXFLAGS := -Werror -std=c++17 -pthread -O2 -Wunused
|
||||
CXXFLAGS := -Werror -std=c++17 -O2
|
||||
|
||||
INCLUDES := -I .
|
||||
|
||||
SRCS := compresSmol.cpp compressAlgo.cpp tANS.cpp fileDispatcher.cpp
|
||||
TILEMAP_SRCS := mainTiles.cpp compressAlgo.cpp compressSmolTiles.cpp tANS.cpp fileDispatcher.cpp
|
||||
SRCS := compresSmol.cpp compressAlgo.cpp tANS.cpp
|
||||
TILEMAP_SRCS := mainTiles.cpp compressSmolTiles.cpp tANS.cpp compressAlgo.cpp
|
||||
|
||||
HEADERS := compressAlgo.h tANS.h fileDispatcher.h
|
||||
TILEMAP_HEADERS := compressAlgo.h compressSmolTiles.h tANS.h fileDispatcher.h
|
||||
HEADERS := compressAlgo.h tANS.h
|
||||
TILEMAP_HEADERS := compressSmolTiles.h tANS.h compressAlgo.h
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
EXE := .exe
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ bool isNumber(std::string input)
|
|||
}
|
||||
|
||||
enum Option {
|
||||
ANALYZE,
|
||||
WRITE,
|
||||
FRAME_WRITE,
|
||||
DECODE,
|
||||
|
|
@ -31,15 +30,12 @@ int main(int argc, char *argv[])
|
|||
bool printUsage = false;
|
||||
std::string input;
|
||||
std::string output;
|
||||
int numThreads = 1;
|
||||
InputSettings settings(true, true, true);
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
std::string argument = argv[1];
|
||||
if (argument.compare("-a") == 0)
|
||||
option = ANALYZE;
|
||||
else if (argument.compare("-w") == 0)
|
||||
if (argument.compare("-w") == 0)
|
||||
option = WRITE;
|
||||
else if (argument.compare("-fw") == 0)
|
||||
option = FRAME_WRITE;
|
||||
|
|
@ -48,46 +44,12 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
switch (option)
|
||||
{
|
||||
case ANALYZE:
|
||||
if (argc > 2)
|
||||
input = argv[2];
|
||||
else
|
||||
printUsage = true;
|
||||
if (argc > 4)
|
||||
{
|
||||
std::string arg2 = argv[3];
|
||||
std::string arg2arg = argv[4];
|
||||
if (arg2.compare("-t") == 0 && isNumber(arg2arg))
|
||||
numThreads = std::stoi(arg2arg.c_str());
|
||||
}
|
||||
if (argc > 7)
|
||||
{
|
||||
std::string setting1 = argv[5];
|
||||
std::string setting2 = argv[6];
|
||||
std::string setting3 = argv[7];
|
||||
if (setting1.compare("true") == 0)
|
||||
settings.canEncodeLO = true;
|
||||
else if (setting1.compare("false") == 0)
|
||||
settings.canEncodeLO = false;
|
||||
else
|
||||
fprintf(stderr, "Unrecognized setting1 \"%s\", defaulting to \"true\"\n", setting1.c_str());
|
||||
if (setting2.compare("true") == 0)
|
||||
settings.canEncodeSyms = true;
|
||||
else if (setting2.compare("false") == 0)
|
||||
settings.canEncodeSyms = false;
|
||||
else
|
||||
fprintf(stderr, "Unrecognized setting2 \"%s\", defaulting to \"true\"\n", setting2.c_str());
|
||||
if (setting3.compare("true") == 0)
|
||||
settings.canDeltaSyms = true;
|
||||
else if (setting3.compare("false") == 0)
|
||||
settings.canDeltaSyms = false;
|
||||
else
|
||||
fprintf(stderr, "Unrecognized setting3 \"%s\", defaulting to \"true\"\n", setting3.c_str());
|
||||
}
|
||||
break;
|
||||
case FRAME_WRITE:
|
||||
// Not implemented yet
|
||||
fprintf(stderr, "Frame writing isn't implemented yet\n");
|
||||
settings.useFrames = true;
|
||||
option = WRITE;
|
||||
return 1;
|
||||
case WRITE:
|
||||
if (argc > 3)
|
||||
{
|
||||
|
|
@ -141,10 +103,6 @@ int main(int argc, char *argv[])
|
|||
if (printUsage)
|
||||
{
|
||||
printf("Usage:\n\
|
||||
%s -a \"path/to/some/directory\"\n\
|
||||
Analyses all images currently in .4bpp.lz format and compares with this compression.\n\
|
||||
-t <number> can be appended to this mode to specify how many threads to use.\n\
|
||||
\n\
|
||||
%s -w \"path/to/some/file.4bpp\" \"path/to/some/file.4bpp.smol\"\
|
||||
Compresses the first argument and writes the result to the second argument.\n\
|
||||
These modes can also be appended with 4 true/false statements that control the following settings of the compression:\n\
|
||||
|
|
@ -153,64 +111,11 @@ int main(int argc, char *argv[])
|
|||
- If the compression instructions can be delta encoded.\n\
|
||||
- If the raw symbols in the compression ca be delta encoded.\n\
|
||||
%s -d \"path/to/some/file.4bpp.smol\" \"path/to/some/file.4bpp\"\n\
|
||||
Decompresses the first argument and writes it to the second argument.", argv[0], argv[0], argv[0]);
|
||||
Decompresses the first argument and writes it to the second argument.", argv[0], argv[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (option == ANALYZE)
|
||||
{
|
||||
std::filesystem::path dirPath = input;
|
||||
FileDispatcher dispatcher(dirPath);
|
||||
if (!dispatcher.initFileList())
|
||||
{
|
||||
fprintf(stderr, "Failed to init file list\n");
|
||||
return 1;
|
||||
}
|
||||
std::mutex dispatchMutex;
|
||||
std::vector<CompressedImage> allImages;
|
||||
std::mutex imageMutex;
|
||||
|
||||
settings.shouldCompare = true;
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
for (int i = 0; i < numThreads; i++)
|
||||
{
|
||||
threads.emplace_back(analyzeImages, &allImages, &imageMutex,
|
||||
&dispatcher, &dispatchMutex,
|
||||
settings);
|
||||
}
|
||||
|
||||
for (int i = 0; i < numThreads; i++)
|
||||
threads[i].join();
|
||||
|
||||
size_t lzSizes = 0;
|
||||
size_t newSizes = 0;
|
||||
size_t rawSizes = 0;
|
||||
size_t totalImages = 0;
|
||||
size_t invalidImages = 0;
|
||||
for (CompressedImage currImage : allImages)
|
||||
{
|
||||
totalImages++;
|
||||
if (currImage.isValid)
|
||||
{
|
||||
lzSizes += currImage.lzSize;
|
||||
newSizes += currImage.compressedSize;
|
||||
rawSizes += currImage.rawNumBytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Failed to solve %s\n", currImage.fileName.c_str());
|
||||
invalidImages++;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "RawSize: %zu\n", rawSizes);
|
||||
fprintf(stderr, "LZsize: %zu\n", lzSizes);
|
||||
fprintf(stderr, "SmolSize: %zu\n", newSizes);
|
||||
fprintf(stderr, "Total Images: %zu\n", totalImages);
|
||||
fprintf(stderr, "Invalid Images: %zu\n", invalidImages);
|
||||
}
|
||||
if (option == WRITE)
|
||||
{
|
||||
if (std::filesystem::exists(input))
|
||||
|
|
@ -240,8 +145,13 @@ int main(int argc, char *argv[])
|
|||
{
|
||||
if (std::filesystem::exists(input))
|
||||
{
|
||||
std::vector<unsigned int> inData = readFileAsUInt(input);
|
||||
std::vector<unsigned short> image4bpp = readRawDataVecs(&inData);
|
||||
std::vector<unsigned int> inData;
|
||||
if (!readFileAsUInt(input, &inData))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
std::vector<unsigned short> image4bpp;
|
||||
readRawDataVecs(&inData, &image4bpp);
|
||||
std::vector<unsigned char> charVec(image4bpp.size()*2);
|
||||
for (size_t i = 0; i < image4bpp.size(); i++)
|
||||
{
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -54,20 +54,7 @@ struct ShortCopy {
|
|||
size_t length;
|
||||
size_t offset;
|
||||
unsigned short firstSymbol;
|
||||
std::vector<unsigned short> usSequence;
|
||||
ShortCopy();
|
||||
ShortCopy(size_t index, size_t length, size_t offset, std::vector<unsigned short> usSequence);
|
||||
};
|
||||
|
||||
struct CompressionInstruction {
|
||||
size_t length;
|
||||
size_t offset;
|
||||
size_t index;
|
||||
unsigned char firstSymbol;
|
||||
std::vector<unsigned char> symbols;
|
||||
std::vector<unsigned char> bytes;
|
||||
void buildBytes();
|
||||
bool verifyInstruction();
|
||||
ShortCopy(size_t index, size_t length, size_t offset, unsigned short firstSymbol);
|
||||
};
|
||||
|
||||
struct ShortCompressionInstruction {
|
||||
|
|
@ -75,20 +62,9 @@ struct ShortCompressionInstruction {
|
|||
size_t offset;
|
||||
size_t index;
|
||||
unsigned short firstSymbol;
|
||||
std::vector<unsigned short> symbols;
|
||||
std::vector<unsigned char> loBytes;
|
||||
std::vector<unsigned short> symShorts;
|
||||
void buildBytes();
|
||||
bool verifyInstruction();
|
||||
};
|
||||
|
||||
struct SortedShortElement {
|
||||
size_t index;
|
||||
ShortCopy copy;
|
||||
bool isRun = false;
|
||||
bool isCopy = false;
|
||||
SortedShortElement();
|
||||
SortedShortElement(size_t index, ShortCopy copy);
|
||||
void buildBytes(std::vector<unsigned short> *pInput);
|
||||
};
|
||||
|
||||
struct CompressedImage {
|
||||
|
|
@ -116,7 +92,6 @@ struct InputSettings {
|
|||
bool canEncodeLO = true;
|
||||
bool canEncodeSyms = true;
|
||||
bool canDeltaSyms = true;
|
||||
bool shouldCompare = false;
|
||||
bool useFrames = false;
|
||||
InputSettings();
|
||||
InputSettings(bool canEncodeLO, bool canEncodeSyms, bool canDeltaSyms);
|
||||
|
|
@ -127,45 +102,38 @@ struct DataVecs {
|
|||
std::vector<unsigned short> symVec;
|
||||
};
|
||||
|
||||
void analyzeImages(std::vector<CompressedImage> *allImages, std::mutex *imageMutex, FileDispatcher *dispatcher, std::mutex *dispatchMutex, InputSettings settings);
|
||||
|
||||
CompressedImage processImage(std::string fileName, InputSettings settings);
|
||||
CompressedImage processImageFrames(std::string fileName, InputSettings settings);
|
||||
CompressedImage processImageData(std::vector<unsigned char> input, InputSettings settings, std::string fileName);
|
||||
bool processImageData(std::vector<unsigned char> *pInput, CompressedImage *pImage, InputSettings settings, std::string fileName);
|
||||
|
||||
std::vector<unsigned int> readFileAsUInt(std::string filePath);
|
||||
bool readFileAsUInt(std::string filePath, std::vector<unsigned int> *pFileData);
|
||||
|
||||
size_t getCompressedSize(CompressedImage *pImage);
|
||||
|
||||
std::vector<ShortCopy> getShortCopies(std::vector<unsigned short> input, size_t minLength);
|
||||
bool getShortCopies(std::vector<unsigned short> *pInput, size_t minLength, std::vector<ShortCopy> *pShortCopies);
|
||||
bool verifyShortCopies(std::vector<ShortCopy> *pCopies, std::vector<unsigned short> *pImage);
|
||||
|
||||
std::vector<int> getNormalizedCounts(std::vector<size_t> input);
|
||||
std::vector<unsigned int> getFreqWriteInts(std::vector<int> input);
|
||||
std::vector<unsigned int> getNewHeaders(CompressionMode mode, size_t imageSize, size_t symLength, int initialState, size_t bitstreamSize, size_t loLength);
|
||||
int findInitialState(EncodeCol encodeCol, unsigned char firstSymbol);
|
||||
CompressedImage fillCompressVecNew(std::vector<unsigned char> loVec, std::vector<unsigned short> symVec, CompressionMode mode, size_t imageBytes, std::string name);
|
||||
std::vector<ShortCompressionInstruction> getShortInstructions(std::vector<ShortCopy> copies, size_t lengthMod);
|
||||
std::vector<unsigned char> getLosFromInstructions(std::vector<ShortCompressionInstruction> instructions);
|
||||
std::vector<unsigned short> getSymsFromInstructions(std::vector<ShortCompressionInstruction> instructions);
|
||||
int findInitialState(EncodeCol *encodeCol, unsigned char firstSymbol);
|
||||
|
||||
bool fillCompressVec(std::vector<unsigned char> *pLoVec, std::vector<unsigned short> *pSymVec, CompressionMode mode, size_t imageBytes, std::string name, CompressedImage *pOutput);
|
||||
|
||||
bool getShortInstructions(std::vector<ShortCopy> *pCopies, std::vector<ShortCompressionInstruction> *pInstructions, std::vector<unsigned short> *pInput);
|
||||
void getLosFromInstructions(std::vector<ShortCompressionInstruction> *pInstructions, std::vector<unsigned char> *pOutput);
|
||||
void getSymsFromInstructions(std::vector<ShortCompressionInstruction> *pInstructions, std::vector<unsigned short> *pOutput);
|
||||
std::vector<int> unpackFrequencies(unsigned int pInts[3]);
|
||||
CompressedImage getDataFromUIntVec(std::vector<unsigned int> *pInput);
|
||||
CompressedImage readNewHeader(std::vector<unsigned int> *pInput);
|
||||
std::vector<unsigned int> getUIntVecFromData(CompressedImage *pImage);
|
||||
void readNewHeader(std::vector<unsigned int> *pInput, CompressedImage *pOutput);
|
||||
void getUIntVecFromData(CompressedImage *pImage, std::vector<unsigned int> *pOutput);
|
||||
|
||||
std::vector<unsigned short> decodeBytesShort(std::vector<unsigned char> *pLoVec, std::vector<unsigned short> *pSymVec);
|
||||
std::vector<unsigned short> decodeImageShort(CompressedImage *pInput);
|
||||
DataVecs decodeDataVectorsNew(CompressedImage *pInput);
|
||||
|
||||
size_t decodeNibbles(std::vector<DecodeCol> decodeTable, std::vector<unsigned int> *bits, int *currState, std::vector<unsigned char> *nibbleVec, size_t currBitIndex, size_t numNibbles);
|
||||
|
||||
bool compareVectorsShort(std::vector<unsigned short> *pVec1, std::vector<unsigned short> *pVec2);
|
||||
|
||||
bool verifyCompressionShort(CompressedImage *pInput, std::vector<unsigned short> *pImage);
|
||||
bool verifyBytesShort(std::vector<unsigned char> *pLoVec, std::vector<unsigned short> *pSymVec, std::vector<unsigned short> *pImage);
|
||||
bool verifyUIntVecShort(std::vector<unsigned int> *pInput, std::vector<unsigned short> *pImage);
|
||||
|
||||
std::vector<unsigned short> readRawDataVecs(std::vector<unsigned int> *pInput);
|
||||
bool verifyBytesShort(std::vector<unsigned char> *pLoVec, std::vector<unsigned short> *pSymVec, std::vector<unsigned short> *pImage);
|
||||
void readRawDataVecs(std::vector<unsigned int> *pInput, std::vector<unsigned short> *pOutput);
|
||||
|
||||
bool isModeLoEncoded(CompressionMode mode);
|
||||
bool isModeSymEncoded(CompressionMode mode);
|
||||
|
|
@ -175,4 +143,5 @@ void deltaEncode(std::vector<unsigned char> *buffer, int length);
|
|||
void deltaDecode(std::vector<unsigned char> *buffer, int length);
|
||||
|
||||
std::vector<int> getTestFreqs(std::vector<int> freqs, std::string name);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -91,15 +91,19 @@ std::vector<unsigned short> decompressVector(std::vector<unsigned short> *pVec)
|
|||
CompressVectors compressVector(std::vector<unsigned short> *pVec)
|
||||
{
|
||||
CompressVectors vecs;
|
||||
std::vector<ShortCopy> shortCopies = getShortCopies(*pVec, 2);
|
||||
std::vector<ShortCopy> shortCopies;
|
||||
getShortCopies(pVec, 2, &shortCopies);
|
||||
if (!verifyShortCopies(&shortCopies, pVec))
|
||||
{
|
||||
fprintf(stderr, "Error getting tile-number compression\n");
|
||||
return vecs;
|
||||
}
|
||||
std::vector<ShortCompressionInstruction> shortInstructions = getShortInstructions(shortCopies, 0);
|
||||
std::vector<unsigned char> loVec = getLosFromInstructions(shortInstructions);
|
||||
std::vector<unsigned short> symVec = getSymsFromInstructions(shortInstructions);
|
||||
std::vector<ShortCompressionInstruction> shortInstructions;
|
||||
getShortInstructions(&shortCopies, &shortInstructions, pVec);
|
||||
std::vector<unsigned char> loVec;
|
||||
getLosFromInstructions(&shortInstructions, &loVec);
|
||||
std::vector<unsigned short> symVec;
|
||||
getSymsFromInstructions(&shortInstructions, &symVec);
|
||||
|
||||
if (!verifyBytesShort(&loVec, &symVec, pVec))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ int main(int argc, char *argv[])
|
|||
fileOut.close();
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
else if (argc == 2)
|
||||
{
|
||||
std::filesystem::path filePath = argv[1];
|
||||
|
|
@ -66,6 +67,7 @@ int main(int argc, char *argv[])
|
|||
printf("New size: %zu\n", totalSize);
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "tANS.h"
|
||||
#include <stdio.h>
|
||||
|
||||
std::vector<DecodeCol> createDecodingTable(std::vector<unsigned char> symbols, std::vector<int> frequencies)
|
||||
{
|
||||
|
|
@ -8,6 +9,7 @@ std::vector<DecodeCol> createDecodingTable(std::vector<unsigned char> symbols, s
|
|||
{
|
||||
for (size_t j = 0; j < frequencies[i]; j++)
|
||||
{
|
||||
//printf("%zu %zu\n", table.size(), currCol);
|
||||
table[currCol].state = TANS_TABLE_SIZE + currCol;
|
||||
table[currCol].symbol = symbols[i];
|
||||
table[currCol].y = frequencies[i] + j;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#define GET_GBA_PAL_BLUE(x) (((x) >> 10) & 0x1F)
|
||||
|
||||
#define SET_GBA_PAL(r, g, b) (((b) << 10) | ((g) << 5) | (r))
|
||||
#define SET_GBA_PAL_RGBA(r, g, b, a) (((a) << 15) | ((b) << 10) | ((g) << 5) | (r))
|
||||
|
||||
#define UPCONVERT_BIT_DEPTH(x) (((x) * 255) / 31)
|
||||
|
||||
|
|
@ -578,8 +579,9 @@ void WriteGbaPalette(char *path, struct Palette *palette)
|
|||
unsigned char red = DOWNCONVERT_BIT_DEPTH(palette->colors[i].red);
|
||||
unsigned char green = DOWNCONVERT_BIT_DEPTH(palette->colors[i].green);
|
||||
unsigned char blue = DOWNCONVERT_BIT_DEPTH(palette->colors[i].blue);
|
||||
bool alpha = palette->colors[i].alpha;
|
||||
|
||||
uint16_t paletteEntry = SET_GBA_PAL(red, green, blue);
|
||||
uint16_t paletteEntry = SET_GBA_PAL_RGBA(red, green, blue, alpha);
|
||||
|
||||
fputc(paletteEntry & 0xFF, fp);
|
||||
fputc(paletteEntry >> 8, fp);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ struct Color {
|
|||
unsigned char red;
|
||||
unsigned char green;
|
||||
unsigned char blue;
|
||||
bool alpha;
|
||||
};
|
||||
|
||||
struct Palette {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
// Blue - "0 0 255\r\n"
|
||||
// Brown - "150 75 0\r\n"
|
||||
|
||||
#define MAX_LINE_LENGTH 11
|
||||
#define MAX_LINE_LENGTH 64
|
||||
|
||||
void ReadJascPaletteLine(FILE *fp, char *line)
|
||||
{
|
||||
|
|
@ -156,6 +156,42 @@ void ReadJascPalette(char *path, struct Palette *palette)
|
|||
FATAL_ERROR("Garbage after color data.\n");
|
||||
|
||||
fclose(fp);
|
||||
|
||||
// Try to parse alpha/high bit info for colors from auxiliary .pla file
|
||||
char *dot = strrchr(path, '.');
|
||||
if (strcmp(dot, ".pal") != 0)
|
||||
return;
|
||||
strcpy(dot, ".pla"); // replace .pal with .pla
|
||||
fp = fopen(path, "rb");
|
||||
|
||||
if (fp == NULL)
|
||||
return;
|
||||
|
||||
int i = 0;
|
||||
// Keep reading lines until number of colors is reached or we run out
|
||||
while (i < palette->numColors && fgets(line, MAX_LINE_LENGTH, fp) != NULL)
|
||||
{
|
||||
if (line[0] == '#') // comment line; ignore
|
||||
continue;
|
||||
|
||||
char *s = line;
|
||||
char *end;
|
||||
int colorIndex;
|
||||
|
||||
if (!ParseNumber(s, &end, 10, &colorIndex))
|
||||
FATAL_ERROR("Failed to parse aux color index.\n");
|
||||
|
||||
s = end;
|
||||
|
||||
if (colorIndex >= palette->numColors)
|
||||
FATAL_ERROR("Aux color index %d out of bounds.\n", colorIndex);
|
||||
|
||||
palette->colors[colorIndex].alpha = 1; // set alpha color
|
||||
// fprintf(stderr, "Color index: %d\n", colorIndex);
|
||||
i++;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void WriteJascPalette(char *path, struct Palette *palette)
|
||||
|
|
|
|||
|
|
@ -291,7 +291,7 @@ void HandlePngToGbaCommand(char *inputPath, char *outputPath, int argc, char **a
|
|||
|
||||
void HandlePngToJascPaletteCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
|
||||
{
|
||||
struct Palette palette = {};
|
||||
struct Palette palette = {0};
|
||||
|
||||
ReadPngPalette(inputPath, &palette);
|
||||
WriteJascPalette(outputPath, &palette);
|
||||
|
|
@ -299,7 +299,7 @@ void HandlePngToJascPaletteCommand(char *inputPath, char *outputPath, int argc U
|
|||
|
||||
void HandlePngToGbaPaletteCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
|
||||
{
|
||||
struct Palette palette = {};
|
||||
struct Palette palette = {0};
|
||||
|
||||
ReadPngPalette(inputPath, &palette);
|
||||
WriteGbaPalette(outputPath, &palette);
|
||||
|
|
@ -307,7 +307,7 @@ void HandlePngToGbaPaletteCommand(char *inputPath, char *outputPath, int argc UN
|
|||
|
||||
void HandleGbaToJascPaletteCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
|
||||
{
|
||||
struct Palette palette = {};
|
||||
struct Palette palette = {0};
|
||||
|
||||
ReadGbaPalette(inputPath, &palette);
|
||||
WriteJascPalette(outputPath, &palette);
|
||||
|
|
@ -333,6 +333,9 @@ void HandleJascToGbaPaletteCommand(char *inputPath, char *outputPath, int argc,
|
|||
|
||||
if (numColors < 1)
|
||||
FATAL_ERROR("Number of colors must be positive.\n");
|
||||
|
||||
if (numColors > 255)
|
||||
FATAL_ERROR("Number of colors must be less than 256.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -340,7 +343,7 @@ void HandleJascToGbaPaletteCommand(char *inputPath, char *outputPath, int argc,
|
|||
}
|
||||
}
|
||||
|
||||
struct Palette palette = {};
|
||||
struct Palette palette = {0};
|
||||
|
||||
ReadJascPalette(inputPath, &palette);
|
||||
|
||||
|
|
@ -425,7 +428,7 @@ void HandlePngToFullwidthJapaneseFontCommand(char *inputPath, char *outputPath,
|
|||
void HandleLZCompressCommand(char *inputPath, char *outputPath, int argc, char **argv)
|
||||
{
|
||||
int overflowSize = 0;
|
||||
int minDistance = 2; // default, for compatibility with DecompressDataWithHeaderVram()
|
||||
int minDistance = 2; // default, for compatibility with LZ77UnCompVram()
|
||||
|
||||
for (int i = 3; i < argc; i++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
CXX ?= g++
|
||||
|
||||
CXXFLAGS := -Wall -std=c++11 -O2
|
||||
CXXFLAGS := -Wall -std=c++17 -O2
|
||||
|
||||
SRCS := json11.cpp mapjson.cpp
|
||||
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@
|
|||
* L: Sets the filename to the remainder of the line.
|
||||
* R: Sets the result to the remainder of the line, and flushes any
|
||||
* output buffered since the previous R.
|
||||
* P/K/F/A: Sets the result to the remaining of the line, flushes any
|
||||
* output since the previous P/K/F/A and increment the number of
|
||||
* passes/known fails/assumption fails/fails.
|
||||
* P/E/K/F/A: Sets the result to the remaining of the line, flushes any
|
||||
* output since the previous P/E/K/F/A and increment the number of
|
||||
* passes/expected fails/known fails/assumption fails/fails.
|
||||
*/
|
||||
#include <fcntl.h>
|
||||
#include <math.h>
|
||||
|
|
@ -59,6 +59,8 @@ struct Runner
|
|||
int passes;
|
||||
int knownFails;
|
||||
int knownFailsPassing;
|
||||
int expectedFails;
|
||||
int expectedFailsPassing;
|
||||
int todos;
|
||||
int assumptionFails;
|
||||
int fails;
|
||||
|
|
@ -67,6 +69,8 @@ struct Runner
|
|||
char failed_TestFilenameLine[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char knownFailingPassed_TestNames[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char knownFailingPassed_FilenameLine[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char expectedFailingPassed_TestNames[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char expectedFailingPassed_FilenameLine[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char assumeFailed_TestNames[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char assumeFailed_FilenameLine[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
};
|
||||
|
|
@ -241,6 +245,9 @@ static void handle_read(int i, struct Runner *runner)
|
|||
case 'P':
|
||||
runner->passes++;
|
||||
goto add_to_results;
|
||||
case 'E':
|
||||
runner->expectedFails++;
|
||||
goto add_to_results;
|
||||
case 'K':
|
||||
runner->knownFails++;
|
||||
goto add_to_results;
|
||||
|
|
@ -252,6 +259,14 @@ static void handle_read(int i, struct Runner *runner)
|
|||
}
|
||||
runner->knownFailsPassing++;
|
||||
goto add_to_results;
|
||||
case 'V':
|
||||
if (runner->expectedFailsPassing < MAX_SUMMARY_TESTS_TO_LIST)
|
||||
{
|
||||
strcpy(runner->expectedFailingPassed_TestNames[runner->expectedFailsPassing], runner->test_name);
|
||||
strcpy(runner->expectedFailingPassed_FilenameLine[runner->expectedFailsPassing], runner->filename_line);
|
||||
}
|
||||
runner->expectedFailsPassing++;
|
||||
goto add_to_results;
|
||||
case 'T':
|
||||
runner->todos++;
|
||||
goto add_to_results;
|
||||
|
|
@ -737,6 +752,8 @@ int main(int argc, char *argv[])
|
|||
// Reap test runners and collate exit codes.
|
||||
int exit_code = 0;
|
||||
int passes = 0;
|
||||
int expectedFails = 0;
|
||||
int expectedFailsPassing = 0;
|
||||
int knownFails = 0;
|
||||
int knownFailsPassing = 0;
|
||||
int todos = 0;
|
||||
|
|
@ -750,6 +767,9 @@ int main(int argc, char *argv[])
|
|||
char knownFailingPassed_TestNames[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char knownFailingPassed_FilenameLine[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
|
||||
char expectedFailingPassed_TestNames[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char expectedFailingPassed_FilenameLine[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
|
||||
char assumeFailed_TestNames[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
char assumeFailed_FilenameLine[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||
|
||||
|
|
@ -766,6 +786,7 @@ int main(int argc, char *argv[])
|
|||
if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) > exit_code)
|
||||
exit_code = WEXITSTATUS(wstatus);
|
||||
passes += runners[i].passes;
|
||||
expectedFails += runners[i].expectedFails;
|
||||
knownFails += runners[i].knownFails;
|
||||
for (int j = 0; j < runners[i].knownFailsPassing; j++)
|
||||
{
|
||||
|
|
@ -776,6 +797,15 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
knownFailsPassing++;
|
||||
}
|
||||
for (int j = 0; j < runners[i].expectedFailsPassing; j++)
|
||||
{
|
||||
if (j < MAX_SUMMARY_TESTS_TO_LIST)
|
||||
{
|
||||
strcpy(expectedFailingPassed_TestNames[expectedFailsPassing], runners[i].expectedFailingPassed_TestNames[j]);
|
||||
strcpy(expectedFailingPassed_FilenameLine[expectedFailsPassing], runners[i].expectedFailingPassed_FilenameLine[j]);
|
||||
}
|
||||
expectedFailsPassing++;
|
||||
}
|
||||
todos += runners[i].todos;
|
||||
for (int j = 0; j < runners[i].assumptionFails; j++)
|
||||
{
|
||||
|
|
@ -855,6 +885,8 @@ int main(int argc, char *argv[])
|
|||
fprintf(stdout, "\n");
|
||||
if (fails > 0)
|
||||
fprintf(stdout, "- Tests \e[31mFAILED\e[0m : %d Add TESTS='X' to run tests with the defined prefix.\n", fails);
|
||||
if (expectedFailsPassing > 0)
|
||||
fprintf(stdout, "- \e[31mEXPECTED_FAIL_PASSING\e[0m: %d\n", expectedFailsPassing);
|
||||
if (knownFails > 0)
|
||||
fprintf(stdout, "- Tests \e[33mKNOWN_FAILING\e[0m: %d\n", knownFails);
|
||||
if (assumptionFails > 0)
|
||||
|
|
@ -863,7 +895,10 @@ int main(int argc, char *argv[])
|
|||
fprintf(stdout, "- Tests \e[33mTO_DO\e[0m: %d\n", todos);
|
||||
if (knownFailsPassing > 0)
|
||||
fprintf(stdout, "- \e[32mKNOWN_FAILING_PASSING\e[0m: %d \e[33mPlease remove KNOWN_FAILING if these tests intentionally PASS\e[0m\n", knownFailsPassing);
|
||||
fprintf(stdout, "- Tests \e[32mPASSED\e[0m: %d\n", passes);
|
||||
if (expectedFails > 0)
|
||||
fprintf(stdout, "- Tests \e[32mEXPECT_FAILING\e[0m: %d\n", expectedFails);
|
||||
if (passes > 0)
|
||||
fprintf(stdout, "- Tests \e[32mPASSED\e[0m: %d\n", passes);
|
||||
fprintf(stdout, "- Tests \e[34mTOTAL\e[0m: %d\n", results);
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
|
|
|
|||
|
|
@ -5,3 +5,4 @@ The source code for these specific builds is available from:
|
|||
|
||||
- Windows: <https://github.com/mgba-emu/mgba/tree/7ee2be6c96222dca12a9a579b747fe5ff1829def>
|
||||
- Linux: <https://github.com/mgba-emu/mgba/tree/dbffb46c4e7d2e7a2cbed7c3488cece4c2176d4c>
|
||||
- Mac: <https://github.com/mgba-emu/mgba/tree/daf01b03d5316dac966acd4b05318a225cab12f5>
|
||||
|
|
|
|||
BIN
tools/mgba/mgba-rom-test-mac
Executable file
BIN
tools/mgba/mgba-rom-test-mac
Executable file
Binary file not shown.
Loading…
Reference in New Issue
Block a user