mirror of
https://github.com/Yonokid/PyTaiko.git
synced 2026-02-04 03:30:13 +01:00
6
.github/workflows/python-app.yml
vendored
6
.github/workflows/python-app.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew update
|
||||
brew install portaudio libsndfile libsamplerate pkg-config
|
||||
brew install portaudio libsndfile speexdsp pkg-config
|
||||
|
||||
- name: Set up MSYS2 (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
base-devel
|
||||
mingw-w64-x86_64-gcc
|
||||
mingw-w64-x86_64-libsndfile
|
||||
mingw-w64-x86_64-libsamplerate
|
||||
mingw-w64-x86_64-speexdsp
|
||||
mingw-w64-x86_64-flac
|
||||
mingw-w64-x86_64-libvorbis
|
||||
mingw-w64-x86_64-libogg
|
||||
@@ -175,7 +175,7 @@ jobs:
|
||||
libportaudio2 \
|
||||
portaudio19-dev \
|
||||
libsndfile1-dev \
|
||||
libsamplerate0-dev \
|
||||
libspeexdsp-dev \
|
||||
libflac-dev \
|
||||
libvorbis-dev \
|
||||
libogg-dev \
|
||||
|
||||
@@ -53,7 +53,7 @@ source $HOME/.local/bin/env
|
||||
git clone https://github.com/Yonokid/PyTaiko
|
||||
cd PyTaiko
|
||||
brew install libsndfile
|
||||
brew install libsamplerate
|
||||
brew install speexdsp
|
||||
cd libs/audio
|
||||
make
|
||||
mv libaudio.dylib ../../
|
||||
@@ -118,7 +118,7 @@ Then run with Python as described in the Building from Source section.
|
||||
|
||||
### C Libraries
|
||||
```bash
|
||||
sudo apt install libsamplerate libsndfile
|
||||
sudo apt install speexdsp libsndfile
|
||||
```
|
||||
|
||||
Some distributions may also require [patchelf](https://github.com/NixOS/patchelf) and this symbolic link:
|
||||
|
||||
@@ -71,10 +71,11 @@ ifneq (,$(findstring MINGW,$(UNAME_S)))
|
||||
CORE_LIBS += -lsndfile
|
||||
endif
|
||||
|
||||
ifneq (,$(wildcard /mingw64/lib/libsamplerate.a))
|
||||
CORE_LIBS += /mingw64/lib/libsamplerate.a
|
||||
ifneq (,$(wildcard /mingw64/lib/libspeexdsp.a))
|
||||
CORE_LIBS += /mingw64/lib/libspeexdsp.a
|
||||
CFLAGS += -DHAVE_SPEEXDSP
|
||||
else
|
||||
CORE_LIBS += -lsamplerate
|
||||
CORE_LIBS += -lspeexdsp
|
||||
endif
|
||||
|
||||
# Windows system libraries (these provide the missing symbols)
|
||||
@@ -103,7 +104,8 @@ else ifeq ($(UNAME_S),Darwin)
|
||||
CORE_LIBS += -lportaudio
|
||||
endif
|
||||
|
||||
CORE_LIBS += -lsndfile -lsamplerate
|
||||
CORE_LIBS += -lsndfile
|
||||
CORE_LIBS += -lspeexdsp
|
||||
|
||||
# macOS frameworks
|
||||
LIBS = $(CORE_LIBS) -framework CoreAudio -framework AudioToolbox -framework AudioUnit
|
||||
@@ -127,12 +129,9 @@ else ifeq ($(UNAME_S),Linux)
|
||||
|
||||
CORE_LIBS += -lsndfile
|
||||
|
||||
# Check for libsamplerate
|
||||
ifeq ($(call check_lib,samplerate),yes)
|
||||
CORE_LIBS += -lsamplerate
|
||||
CFLAGS += -DHAVE_SAMPLERATE
|
||||
else
|
||||
$(warning libsamplerate not found - building without sample rate conversion)
|
||||
ifeq ($(call check_lib,speexdsp),yes)
|
||||
CORE_LIBS += -lspeexdsp
|
||||
CFLAGS += -DHAVE_SPEEXDSP
|
||||
endif
|
||||
|
||||
# Audio backend libraries (optional)
|
||||
@@ -188,7 +187,7 @@ else ifeq ($(UNAME_S),Linux)
|
||||
else
|
||||
# Generic Unix fallback - minimal dependencies
|
||||
LIBNAME = libaudio.so
|
||||
LIBS = -lportaudio -lsndfile -lpthread -lm
|
||||
LIBS = -lportaudio -lsndfile -lspeexdsp -lpthread -lm
|
||||
OBJ_EXT = .o
|
||||
endif
|
||||
|
||||
@@ -250,7 +249,7 @@ ifneq (,$(findstring MINGW,$(UNAME_S)))
|
||||
@echo "Checking for Windows-specific libportaudio:"
|
||||
@ls -la ./libportaudio-win.a 2>/dev/null && echo "✓ Found local libportaudio-win.a" || echo "✗ No local libportaudio-win.a"
|
||||
@echo "Available system static libraries:"
|
||||
@ls /mingw64/lib/lib{portaudio,sndfile,samplerate,FLAC,vorbis*,ogg}.a 2>/dev/null || echo "None found"
|
||||
@ls /mingw64/lib/lib{portaudio,sndfile,speexdsp,FLAC,vorbis*,ogg}.a 2>/dev/null || echo "None found"
|
||||
@echo "Static pthread library:"
|
||||
@ls /mingw64/lib/libwinpthread.a 2>/dev/null && echo "✓ Found libwinpthread.a" || echo "✗ Missing libwinpthread.a"
|
||||
@echo "Libraries to link: $(LIBS)"
|
||||
@@ -262,7 +261,7 @@ ifdef PKG_CONFIG
|
||||
@echo "pkg-config available: yes"
|
||||
@echo -n "PortAudio: "; pkg-config --exists portaudio-2.0 && echo "✓" || echo "✗"
|
||||
@echo -n "libsndfile: "; pkg-config --exists sndfile && echo "✓" || echo "✗"
|
||||
@echo -n "libsamplerate: "; pkg-config --exists samplerate && echo "✓" || echo "✗"
|
||||
@echo -n "speexdsp: "; pkg-config --exists speexdsp && echo "✓" || echo "✗"
|
||||
@echo -n "ALSA: "; pkg-config --exists alsa && echo "✓" || echo "✗"
|
||||
@echo -n "PulseAudio: "; pkg-config --exists libpulse && echo "✓" || echo "✗"
|
||||
@echo -n "JACK: "; pkg-config --exists jack && echo "✓" || echo "✗"
|
||||
@@ -288,7 +287,7 @@ list-libs:
|
||||
@echo "All libraries: $(LIBS)"
|
||||
|
||||
# Build with only essential libraries (fallback)
|
||||
minimal: override LIBS = -lportaudio -lsndfile -lpthread -lm
|
||||
minimal: override LIBS = -lportaudio -lsndfile -lspeexdsp -lpthread -lm
|
||||
minimal: $(LIBNAME)
|
||||
@echo "Built minimal version with basic dependencies only"
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sndfile.h>
|
||||
#include <samplerate.h>
|
||||
//#include <samplerate.h>
|
||||
#include <speex/speex_resampler.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
@@ -78,7 +79,7 @@ typedef struct music {
|
||||
// Music context data, required for music streaming
|
||||
typedef struct music_ctx {
|
||||
SNDFILE *snd_file;
|
||||
SRC_STATE *resampler;
|
||||
SpeexResamplerState *resampler;
|
||||
double src_ratio;
|
||||
} music_ctx;
|
||||
|
||||
@@ -693,28 +694,50 @@ sound load_sound_from_wave(wave wave) {
|
||||
if (wave.sampleRate != AUDIO.System.sampleRate) {
|
||||
TRACELOG(LOG_INFO, "Resampling wave from %d Hz to %f Hz", wave.sampleRate, AUDIO.System.sampleRate);
|
||||
|
||||
SRC_DATA src_data;
|
||||
src_data.data_in = wave.data;
|
||||
src_data.input_frames = wave.frameCount;
|
||||
src_data.src_ratio = AUDIO.System.sampleRate / wave.sampleRate;
|
||||
src_data.output_frames = (sf_count_t)(wave.frameCount * src_data.src_ratio);
|
||||
int error = 0;
|
||||
SpeexResamplerState *resampler = speex_resampler_init(
|
||||
wave.channels,
|
||||
wave.sampleRate,
|
||||
(int)AUDIO.System.sampleRate,
|
||||
SPEEX_RESAMPLER_QUALITY_MIN,
|
||||
&error
|
||||
);
|
||||
|
||||
resampled_wave.data = calloc(src_data.output_frames * wave.channels, sizeof(float));
|
||||
if (resampled_wave.data == NULL) {
|
||||
TRACELOG(LOG_WARNING, "Failed to allocate memory for resampling");
|
||||
if (error || resampler == NULL) {
|
||||
TRACELOG(LOG_WARNING, "Failed to initialize resampler: %d", error);
|
||||
return sound;
|
||||
}
|
||||
src_data.data_out = resampled_wave.data;
|
||||
|
||||
int error = src_simple(&src_data, SRC_SINC_BEST_QUALITY, wave.channels);
|
||||
if (error) {
|
||||
TRACELOG(LOG_WARNING, "Resampling failed: %s", src_strerror(error));
|
||||
spx_uint32_t out_frames = (spx_uint32_t)(wave.frameCount * AUDIO.System.sampleRate / wave.sampleRate) + 10;
|
||||
|
||||
resampled_wave.data = calloc(out_frames * wave.channels, sizeof(float));
|
||||
if (resampled_wave.data == NULL) {
|
||||
TRACELOG(LOG_WARNING, "Failed to allocate memory for resampling");
|
||||
speex_resampler_destroy(resampler);
|
||||
return sound;
|
||||
}
|
||||
|
||||
spx_uint32_t in_len = wave.frameCount;
|
||||
spx_uint32_t out_len = out_frames;
|
||||
|
||||
error = speex_resampler_process_interleaved_float(
|
||||
resampler,
|
||||
wave.data,
|
||||
&in_len,
|
||||
resampled_wave.data,
|
||||
&out_len
|
||||
);
|
||||
|
||||
speex_resampler_destroy(resampler);
|
||||
|
||||
if (error != RESAMPLER_ERR_SUCCESS) {
|
||||
TRACELOG(LOG_WARNING, "Resampling failed with error: %d", error);
|
||||
FREE(resampled_wave.data);
|
||||
return sound;
|
||||
}
|
||||
|
||||
resampled_wave.frameCount = src_data.output_frames_gen;
|
||||
resampled_wave.sampleRate = AUDIO.System.sampleRate;
|
||||
resampled_wave.frameCount = out_len;
|
||||
resampled_wave.sampleRate = (int)AUDIO.System.sampleRate;
|
||||
resampled_wave.channels = wave.channels;
|
||||
resampled_wave.sampleSize = wave.sampleSize;
|
||||
is_resampled = true;
|
||||
@@ -913,9 +936,9 @@ music load_music_stream(const char* filename) {
|
||||
if (sf_info.samplerate != AUDIO.System.sampleRate) {
|
||||
TRACELOG(LOG_INFO, "Resampling music from %d Hz to %f Hz", sf_info.samplerate, AUDIO.System.sampleRate);
|
||||
int error;
|
||||
ctx->resampler = src_new(SRC_SINC_FASTEST, sf_info.channels, &error);
|
||||
ctx->resampler = speex_resampler_init(sf_info.channels, sf_info.samplerate, AUDIO.System.sampleRate, SPEEX_RESAMPLER_QUALITY_MIN, &error);
|
||||
if (ctx->resampler == NULL) {
|
||||
TRACELOG(LOG_WARNING, "Failed to create resampler: %s", src_strerror(error));
|
||||
TRACELOG(LOG_WARNING, "Failed to create resampler");
|
||||
free(ctx);
|
||||
sf_close(snd_file);
|
||||
return music;
|
||||
@@ -962,7 +985,7 @@ void unload_music_stream(music music) {
|
||||
if (music.ctxData) {
|
||||
music_ctx *ctx = (music_ctx *)music.ctxData;
|
||||
if (ctx->snd_file) sf_close(ctx->snd_file);
|
||||
if (ctx->resampler) src_delete(ctx->resampler);
|
||||
if (ctx->resampler) speex_resampler_destroy(ctx->resampler);
|
||||
free(ctx);
|
||||
}
|
||||
unload_audio_stream(music.stream);
|
||||
@@ -1036,19 +1059,22 @@ void update_music_stream(music music) {
|
||||
sf_count_t frames_written = 0;
|
||||
|
||||
if (ctx->resampler) {
|
||||
SRC_DATA src_data;
|
||||
src_data.data_in = input_ptr;
|
||||
src_data.input_frames = frames_read;
|
||||
src_data.data_out = buffer_data + subBufferOffset;
|
||||
src_data.output_frames = subBufferSizeFrames;
|
||||
src_data.src_ratio = ctx->src_ratio;
|
||||
src_data.end_of_input = (frames_read < frames_to_read);
|
||||
spx_uint32_t in_len = frames_read;
|
||||
spx_uint32_t out_len = subBufferSizeFrames;
|
||||
|
||||
int error = src_process(ctx->resampler, &src_data);
|
||||
if (error) {
|
||||
TRACELOG(LOG_WARNING, "Resampling failed: %s", src_strerror(error));
|
||||
int error = speex_resampler_process_interleaved_float(
|
||||
ctx->resampler,
|
||||
input_ptr,
|
||||
&in_len,
|
||||
buffer_data + subBufferOffset,
|
||||
&out_len
|
||||
);
|
||||
|
||||
if (error != RESAMPLER_ERR_SUCCESS) {
|
||||
TRACELOG(LOG_WARNING, "Resampling failed with error: %d", error);
|
||||
}
|
||||
frames_written = src_data.output_frames_gen;
|
||||
|
||||
frames_written = out_len;
|
||||
} else {
|
||||
if (music.stream.channels == 1 && AUDIO_DEVICE_CHANNELS == 2) {
|
||||
for (int j = 0; j < frames_read; j++) {
|
||||
|
||||
Reference in New Issue
Block a user