summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRangi <remy.oukaour+rangi42@gmail.com>2020-11-06 15:53:21 -0500
committerRangi <remy.oukaour+rangi42@gmail.com>2020-11-06 15:53:21 -0500
commitcad2f6832c46952ec2bf05785861adb9fd14dfcb (patch)
treed3b8345e4d978b2dddf73b966c06dea4105f8f19
parentd65ac7be34e0f1f10b21ca22408a37e43619cfa2 (diff)
Replace pcm.py with pcm.c, removing the dependency on Python
-rw-r--r--INSTALL.md8
-rw-r--r--Makefile5
-rw-r--r--tools/Makefile2
-rw-r--r--tools/pcm.c157
4 files changed, 162 insertions, 10 deletions
diff --git a/INSTALL.md b/INSTALL.md
index 0d49fedc..73e1be31 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -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.
diff --git a/Makefile b/Makefile
index 434a3192..52b6e875 100644
--- a/Makefile
+++ b/Makefile
@@ -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;
+}