diff options
author | Rangi <remy.oukaour+rangi42@gmail.com> | 2020-11-06 15:53:21 -0500 |
---|---|---|
committer | Rangi <remy.oukaour+rangi42@gmail.com> | 2020-11-06 15:53:21 -0500 |
commit | cad2f6832c46952ec2bf05785861adb9fd14dfcb (patch) | |
tree | d3b8345e4d978b2dddf73b966c06dea4105f8f19 | |
parent | d65ac7be34e0f1f10b21ca22408a37e43619cfa2 (diff) |
Replace pcm.py with pcm.c, removing the dependency on Python
-rw-r--r-- | INSTALL.md | 8 | ||||
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | tools/Makefile | 2 | ||||
-rw-r--r-- | tools/pcm.c | 157 |
4 files changed, 162 insertions, 10 deletions
@@ -39,7 +39,6 @@ Run setup and leave the default settings. At the "**Select Packages**" step, cho - `make` - `git` - `gcc-core` -- `python` Double click on the text that says "**Skip**" next to each package to select the most recent version to install. @@ -82,7 +81,7 @@ Open **Terminal** and enter the following commands, depending on which distro yo To install the software required for **pokeyellow**: ```bash -sudo apt-get install make gcc git python +sudo apt-get install make gcc git ``` Then follow the [**rgbds** instructions](https://rgbds.gbdev.io/install/source) to build **rgbds 0.4.1** from source. @@ -92,7 +91,7 @@ Then follow the [**rgbds** instructions](https://rgbds.gbdev.io/install/source) To install the software required for **pokeyellow**: ```bash -sudo zypper install make gcc git python +sudo zypper install make gcc git ``` Then follow the [**rgbds** instructions](https://rgbds.gbdev.io/install/source) to build **rgbds 0.4.1** from source. @@ -102,7 +101,7 @@ Then follow the [**rgbds** instructions](https://rgbds.gbdev.io/install/source) To install the software required for **pokeyellow**: ```bash -sudo pacman -S make gcc git python +sudo pacman -S make gcc git ``` Then follow the [**rgbds** instructions](https://rgbds.gbdev.io/install/arch) for Arch Linux to install **rgbds 0.4.1**. @@ -133,7 +132,6 @@ If your distro is not listed here, try to find the required software in its repo - `gcc` (or `clang`) - `git` - `rgbds` -- `python` If `rgbds` is not available, you'll need to follow the [**rgbds** instructions](https://rgbds.gbdev.io/install/source) to build **rgbds 0.4.1** from source. @@ -27,9 +27,6 @@ RGBFIX ?= $(RGBDS)rgbfix RGBGFX ?= $(RGBDS)rgbgfx RGBLINK ?= $(RGBDS)rgblink -PYTHON := python -pcm := $(PYTHON) tools/pokemontools/pcm.py pcm - ### Build targets @@ -140,4 +137,4 @@ gfx/surfing_pikachu/surfing_pikachu_3.2bpp: tools/gfx += --trim-whitespace %.wav: ; %.pcm: %.wav - @$(pcm) $< + tools/pcm $< $@ diff --git a/tools/Makefile b/tools/Makefile index 13bab1fb..ca99b118 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -3,7 +3,7 @@ CC := gcc CFLAGS := -O3 -std=c99 -Wall -Wextra -tools := scan_includes gfx pkmncompress +tools := scan_includes gfx pkmncompress pcm all: $(tools) @: diff --git a/tools/pcm.c b/tools/pcm.c new file mode 100644 index 00000000..114fdd38 --- /dev/null +++ b/tools/pcm.c @@ -0,0 +1,157 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#define CHUNKID(b1, b2, b3, b4) \ + (uint32_t)((uint32_t)(b1) | ((uint32_t)(b2) << 8) | \ + ((uint32_t)(b3) << 16) | ((uint32_t)(b4) << 24)) + +size_t file_size(FILE *f) { + if (fseek(f, 0, SEEK_END) == -1) return 0; + long f_size = ftell(f); + if (f_size == -1) return 0; + if (fseek(f, 0, SEEK_SET) == -1) return 0; + return (size_t)f_size; +} + +int32_t get_uint16le(uint8_t *data, size_t size, size_t i) { + return i + 2 >= size ? -1 : + (int32_t)data[i] | ((int32_t)data[i+1] << 8); +} + +int64_t get_uint32le(uint8_t *data, size_t size, size_t i) { + return i + 4 >= size ? -1 : + (int64_t)data[i] | ((int64_t)data[i+1] << 8) | + ((int64_t)data[i+2] << 16) | ((int64_t)data[i+3] << 24); +} + +uint8_t *wav2pcm(uint8_t *wavdata, size_t wavsize, size_t *pcmsize) { + int64_t fourcc = get_uint32le(wavdata, wavsize, 0); + if (fourcc != CHUNKID('R', 'I', 'F', 'F')) { + fputs("WAV file does not start with 'RIFF'\n", stderr); + return NULL; + } + + int64_t waveid = get_uint32le(wavdata, wavsize, 8); + if (waveid != CHUNKID('W', 'A', 'V', 'E')) { + fputs("RIFF chunk does not start with 'WAVE'\n", stderr); + return NULL; + } + + size_t sample_offset = 0; + int64_t num_samples = 0; + + size_t riffsize = (size_t)get_uint32le(wavdata, wavsize, 4) + 8; + for (size_t i = 12; i < riffsize;) { + int64_t chunkid = get_uint32le(wavdata, wavsize, i); + int64_t chunksize = get_uint32le(wavdata, wavsize, i+4); + i += 8; + if (chunksize == -1) { + fputs("failed to read sub-chunk size\n", stderr); + return NULL; + } + + if (chunkid == CHUNKID('f', 'm', 't', ' ')) { + int32_t audio_format = get_uint16le(wavdata, wavsize, i); + if (audio_format != 1) { + fputs("WAV data is not PCM format\n", stderr); + return NULL; + } + + int32_t num_channels = get_uint16le(wavdata, wavsize, i+2); + if (num_channels != 1) { + fputs("WAV data is not mono\n", stderr); + return NULL; + } + + int32_t bits_per_sample = get_uint16le(wavdata, wavsize, i+14); + if (bits_per_sample != 8) { + fputs("WAV data is not 8-bit samples\n", stderr); + return NULL; + } + } + + else if (chunkid == CHUNKID('d', 'a', 't', 'a')) { + sample_offset = i; + num_samples = chunksize; + break; + } + + i += (size_t)chunksize; + } + + if (!num_samples) { + fputs("WAV data has no PCM samples\n", stderr); + return NULL; + } + + // pack 8 WAV samples per PCM byte, clamping each to 0 or 1 + *pcmsize = (size_t)((num_samples + 7) / 8); + uint8_t *pcmdata = malloc(*pcmsize); + for (int64_t i = 0; i < num_samples; i += 8) { + uint8_t v = 0; + for (int64_t j = 0; j < 8 && i + j < num_samples; j++) { + v |= (wavdata[sample_offset + i + j] > 0x80) << (7 - j); + } + pcmdata[i / 8] = v; + } + + return pcmdata; +} + +int main(int argc, char *argv[]) +{ + if (argc != 3) { + fprintf(stderr, "Usage: %s infile.wav outfile.pcm\n", argv[0]); + return EXIT_FAILURE; + } + + char *wavname = argv[1]; + char *pcmname = argv[2]; + + FILE *wavfile = fopen(wavname, "rb"); + if (!wavfile) { + fprintf(stderr, "failed to open for reading: '%s'\n", wavname); + return EXIT_FAILURE; + } + + size_t wavsize = file_size(wavfile); + if (!wavsize) { + fclose(wavfile); + fprintf(stderr, "failed to get file size: '%s'\n", wavname); + return EXIT_FAILURE; + } + + uint8_t *wavdata = malloc(wavsize); + size_t readsize = fread(wavdata, 1, wavsize, wavfile); + fclose(wavfile); + if (readsize != wavsize) { + fprintf(stderr, "failed to read: '%s'\n", wavname); + return EXIT_FAILURE; + } + + size_t pcmsize; + uint8_t *pcmdata = wav2pcm(wavdata, wavsize, &pcmsize); + free(wavdata); + if (!pcmdata) { + fprintf(stderr, "failed to convert: '%s'\n", wavname); + return EXIT_FAILURE; + } + + FILE *pcmfile = fopen(pcmname, "wb"); + if (!pcmfile) { + fprintf(stderr, "failed to open for writing: '%s'\n", pcmname); + return EXIT_FAILURE; + } + + size_t writesize = fwrite(pcmdata, 1, pcmsize, pcmfile); + free(pcmdata); + fclose(pcmfile); + if (writesize != pcmsize) { + fprintf(stderr, "failed to write: '%s'\n", pcmname); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} |