From d2432c92f54af4dfa6c8a54d504d6645076c6b80 Mon Sep 17 00:00:00 2001 From: djdiskmachine Date: Fri, 17 Oct 2025 23:23:17 +0200 Subject: [PATCH 01/38] Inital port of libav Could enable printfx on more platforms Builds, runs and produces output equivalent to ffmpeg Pad not implemented Need to test in cross-compile job Needs cleanup --- projects/Makefile | 4 +- projects/Makefile.X64 | 5 +- projects/rules_libav | 7 + sources/Application/FX/FxPrinter.cpp | 27 +- sources/Application/FX/FxPrinter.h | 13 +- sources/Application/FX/LibavProcessor.c | 704 ++++++++++++++++++++++++ sources/Application/FX/LibavProcessor.h | 14 + 7 files changed, 749 insertions(+), 25 deletions(-) create mode 100644 projects/rules_libav create mode 100644 sources/Application/FX/LibavProcessor.c create mode 100644 sources/Application/FX/LibavProcessor.h diff --git a/projects/Makefile b/projects/Makefile index f735c9d7..5267e08f 100644 --- a/projects/Makefile +++ b/projects/Makefile @@ -259,7 +259,9 @@ COMMONFILES := \ char.o n_assert.o fixed.o wildcard.o \ SyncMaster.o TablePlayback.o Player.o \ Table.o TableView.o\ - InstrumentBank.o WavFileWriter.o WavFile.o MidiInstrument.o Filters.o SampleVariable.o SampleInstrument.o SamplePool.o CommandList.o FxPrinter.o\ + InstrumentBank.o WavFileWriter.o WavFile.o MidiInstrument.o Filters.o \ + SampleVariable.o SampleInstrument.o SamplePool.o CommandList.o \ + LibavProcessor.o FxPrinter.o\ PersistencyService.o Persistent.o \ Observable.o SingletonRegistry.o \ Audio.o AudioMixer.o AudioOutDriver.o AudioDriver.o \ diff --git a/projects/Makefile.X64 b/projects/Makefile.X64 index 6460f413..d9fa59a8 100644 --- a/projects/Makefile.X64 +++ b/projects/Makefile.X64 @@ -1,4 +1,5 @@ -include $(PWD)/rules_base +-include $(PWD)/rules_libav # config DEFINES := \ @@ -24,10 +25,10 @@ SDL_LIBS := $(shell pkg-config sdl2 --libs) OPT_FLAGS := -O3 #For debugging OPT_FLAGS := -g -INCLUDES := $(ALSA_CFLAGS) $(JACK_CFLAGS) $(SDL_CFLAGS) -I$(PWD)/../sources +INCLUDES := $(ALSA_CFLAGS) $(JACK_CFLAGS) $(SDL_CFLAGS) $(FFMPEG_CFLAGS) -I$(PWD)/../sources CFLAGS := $(OPT_FLAGS) $(DEFINES) $(INCLUDES) -Wall CXXFLAGS := $(CFLAGS) -std=gnu++11 -LIBS := $(ALSA_LIBS) $(JACK_LIBS) $(SDL_LIBS) +LIBS := $(ALSA_LIBS) $(JACK_LIBS) $(SDL_LIBS) $(FFMPEG_LIBS) OUTPUT := ../lgpt EXTENSION := x64 diff --git a/projects/rules_libav b/projects/rules_libav new file mode 100644 index 00000000..c8e13cf4 --- /dev/null +++ b/projects/rules_libav @@ -0,0 +1,7 @@ +FFMPEG_INCL= libavformat \ + libavfilter \ + libavcodec \ + libavutil \ + +FFMPEG_CFLAGS := $(shell pkg-config --cflags $(FFMPEG_INCL)) +FFMPEG_LIBS := $(shell pkg-config --libs $(FFMPEG_INCL)) \ No newline at end of file diff --git a/sources/Application/FX/FxPrinter.cpp b/sources/Application/FX/FxPrinter.cpp index 3c4a442a..8e22aaa0 100644 --- a/sources/Application/FX/FxPrinter.cpp +++ b/sources/Application/FX/FxPrinter.cpp @@ -8,11 +8,6 @@ FxPrinter::FxPrinter(ViewData* viewData) InstrumentBank* bank = viewData_->project_->GetInstrumentBank(); instrument_ = static_cast(bank->GetInstrument(curInstr)); notificationResult_ = ""; - // Assume ffmpeg exists but swap for local ffmpig if it doesn't - ffmpeg_ = "ffmpeg"; - Path pigPath("bin:ffmpig"); - Path ffmpigPath(pigPath.GetPath().c_str()); - if(ffmpigPath.Exists()) ffmpeg_ = pigPath.GetPath(); } void FxPrinter::setParams() { @@ -22,9 +17,10 @@ void FxPrinter::setParams() { void FxPrinter::setPaths() { fi_ = std::string(instrument_->GetName()); + fiPath_ = samples_dir.GetPath() + '/' + fi_; - foWav_ = fi_.substr(0, fi_.find_last_of('.')) + "_.wav"; - fo_ = "\"" + samples_dir.GetPath() + '/' + foWav_ + "\""; + fo_ = fi_.substr(0, fi_.find_last_of('.')) + "_.wav"; + foPath_ = samples_dir.GetPath() + '/' + fo_; ir_ = impulse_dir.GetPath() + "/IR-s/"; ir_ += std::string(instrument_->FindVariable(SIP_PRINTFX)->GetString()); @@ -36,9 +32,9 @@ std::string FxPrinter::parseCommand() { float smplLength = static_cast(instrument_->GetSampleSize()) / 44100; std::ostringstream cm1, cm2, cm3, cm4, cm5; - cm1 << ffmpeg_ << " -y -i " - << "\"" << samples_dir.GetPath() << "/" << fi_ << "\"" - << " -i " << ir_ << " -filter_complex "; + // cm1 << ffmpeg_ << " -y -i " + // << "\"" << fi_ << "\"" + // << " -i " << ir_ << " -filter_complex "; // bug in ffmpeg version 4.4.2 // requires pad_dur to be over 0 or output will be infinitely long if (irPad_ > 0) { @@ -64,13 +60,12 @@ bool FxPrinter::Run() { setParams(); setPaths(); // Are we overwriting an already imported sample? - bool imported = SamplePool::GetInstance()->IsImported(foWav_); - std::string cmd = parseCommand(); - Trace::Log("Processed", cmd.c_str()); - if (system(cmd.c_str()) == 0) { - int newIndex = SamplePool::GetInstance()->Reassign(foWav_, imported); + bool imported = SamplePool::GetInstance()->IsImported(fo_); + parseCommand(); + if (encode(fiPath_.c_str(), ir_.c_str(), foPath_.c_str(), irWet_, irPad_) == 0) { + int newIndex = SamplePool::GetInstance()->Reassign(fo_, imported); instrument_->AssignSample(newIndex); - notificationResult_ = "OK!"; + notificationResult_ = "libav OK!"; return true; } else { Trace::Log("PRINTFX", "Failed"); diff --git a/sources/Application/FX/FxPrinter.h b/sources/Application/FX/FxPrinter.h index 61ad65ad..0e5e3018 100644 --- a/sources/Application/FX/FxPrinter.h +++ b/sources/Application/FX/FxPrinter.h @@ -1,13 +1,14 @@ #ifndef FxPrinter_H #define FxPrinter_H -#include -#include -#include "Application/Views/ViewData.h" #include "Application/Instruments/InstrumentBank.h" #include "Application/Instruments/SampleInstrument.h" -#include "System/FileSystem/FileSystem.h" #include "Application/Instruments/SamplePool.h" +#include "Application/Views/ViewData.h" +#include "LibavProcessor.h" +#include "System/FileSystem/FileSystem.h" +#include +#include class FxPrinter { public: @@ -26,10 +27,10 @@ class FxPrinter { int irPad_; int irWet_; std::string fi_; + std::string fiPath_; std::string fo_; + std::string foPath_; std::string ir_; - std::string foWav_; - std::string ffmpeg_; char* notificationResult_; }; diff --git a/sources/Application/FX/LibavProcessor.c b/sources/Application/FX/LibavProcessor.c new file mode 100644 index 00000000..f10374e0 --- /dev/null +++ b/sources/Application/FX/LibavProcessor.c @@ -0,0 +1,704 @@ +/** + * Apply effects to a file using libav + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static AVFormatContext *ifmt_ctx; +static AVFormatContext *ir_fmt_ctx; +static AVFormatContext *ofmt_ctx; +static AVFilterGraph *filter_graph; +static AVFilterContext *buffersrc_ctx; +static AVFilterContext *ir_buffersrc_ctx; +static AVFilterContext *buffersink_ctx; +static AVCodecContext *enc_ctx = NULL; + +static int open_input_file(const char *filename) +{ + const AVCodec *dec; + AVCodecContext *dec_ctx; + AVStream *stream; + int ret; + + if ((ret = avformat_open_input(&ifmt_ctx, filename, NULL, NULL)) < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n"); + return ret; + } + + if ((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n"); + return ret; + } + + /* select the audio stream */ + ret = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot find an audio stream in the input file\n"); + return ret; + } + + stream = ifmt_ctx->streams[ret]; + + /* create decoding context */ + dec_ctx = avcodec_alloc_context3(dec); + if (!dec_ctx) + return AVERROR(ENOMEM); + avcodec_parameters_to_context(dec_ctx, stream->codecpar); + + /* init the audio decoder */ + if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot open audio decoder\n"); + return ret; + } + + stream->codecpar->codec_id = dec_ctx->codec_id; + stream->codecpar->sample_rate = dec_ctx->sample_rate; + stream->codecpar->format = dec_ctx->sample_fmt; + av_channel_layout_copy(&stream->codecpar->ch_layout, &dec_ctx->ch_layout); + + avcodec_free_context(&dec_ctx); + + return 0; +} + +static int open_ir_file(const char *filename) +{ + const AVCodec *dec; + AVCodecContext *dec_ctx; + AVStream *stream; + int ret; + + if ((ret = avformat_open_input(&ir_fmt_ctx, filename, NULL, NULL)) < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot open IR file\n"); + return ret; + } + + if ((ret = avformat_find_stream_info(ir_fmt_ctx, NULL)) < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot find stream information in IR file\n"); + return ret; + } + + /* select the audio stream */ + ret = av_find_best_stream(ir_fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot find an audio stream in the IR file\n"); + return ret; + } + + stream = ir_fmt_ctx->streams[ret]; + + /* create decoding context */ + dec_ctx = avcodec_alloc_context3(dec); + if (!dec_ctx) + return AVERROR(ENOMEM); + avcodec_parameters_to_context(dec_ctx, stream->codecpar); + + /* init the audio decoder */ + if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot open IR audio decoder\n"); + return ret; + } + + stream->codecpar->codec_id = dec_ctx->codec_id; + stream->codecpar->sample_rate = dec_ctx->sample_rate; + stream->codecpar->format = dec_ctx->sample_fmt; + av_channel_layout_copy(&stream->codecpar->ch_layout, &dec_ctx->ch_layout); + + avcodec_free_context(&dec_ctx); + + return 0; +} + +static int open_output_file(const char *filename) +{ + AVStream *out_stream; + AVStream *in_stream; + const AVCodec *encoder; + int ret; + + avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, filename); + if (!ofmt_ctx) { + av_log(NULL, AV_LOG_ERROR, "Could not create output context\n"); + return AVERROR_UNKNOWN; + } + + in_stream = ifmt_ctx->streams[0]; + out_stream = avformat_new_stream(ofmt_ctx, NULL); + if (!out_stream) { + av_log(NULL, AV_LOG_ERROR, "Failed allocating output stream\n"); + return AVERROR_UNKNOWN; + } + + /* find encoder - force PCM 16-bit little-endian as requested */ + encoder = avcodec_find_encoder(AV_CODEC_ID_PCM_S16LE); + if (!encoder) { + av_log(NULL, AV_LOG_FATAL, "Necessary encoder not found\n"); + return AVERROR_INVALIDDATA; + } + + enc_ctx = avcodec_alloc_context3(encoder); + if (!enc_ctx) { + av_log(NULL, AV_LOG_FATAL, "Failed to allocate the encoder context\n"); + return AVERROR(ENOMEM); + } + + /* Set output parameters to target format: 44.1kHz, 16-bit, stereo unless IR is mono */ + enc_ctx->sample_rate = 44100; + + /* Set channel layout based on IR format */ + int ir_channels = ir_fmt_ctx->streams[0]->codecpar->ch_layout.nb_channels; + if (ir_channels == 0) { + ir_channels = ir_fmt_ctx->streams[0]->codecpar->channels; + } + + if (ir_channels == 1) { + av_channel_layout_default(&enc_ctx->ch_layout, 1); /* Mono */ + } else { + av_channel_layout_default(&enc_ctx->ch_layout, 2); /* Stereo */ + } + + /* Use S16 format to match encoder */ + enc_ctx->sample_fmt = AV_SAMPLE_FMT_S16; + + /* Third parameter can be used to pass settings to encoder */ + ret = avcodec_open2(enc_ctx, encoder, NULL); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot open video encoder for stream\n"); + return ret; + } + ret = avcodec_parameters_from_context(out_stream->codecpar, enc_ctx); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Failed to copy encoder parameters to output stream\n"); + return ret; + } + + out_stream->time_base = enc_ctx->time_base; + + av_dump_format(ofmt_ctx, 0, filename, 1); + + /* open the output file, if needed */ + if (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) { + ret = avio_open(&ofmt_ctx->pb, filename, AVIO_FLAG_WRITE); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Could not open output file '%s'", filename); + return ret; + } + } + + /* init muxer, write output file header */ + ret = avformat_write_header(ofmt_ctx, NULL); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Error occurred when opening output file\n"); + return ret; + } + + return 0; +} + +static int init_filters(int ir_wet, int ir_pad) +{ + char args[512]; + char ir_args[512]; + int ret = 0; + const AVFilter *abuffer, *abuffersink; + AVFilterInOut *outputs = avfilter_inout_alloc(); + AVFilterInOut *inputs = avfilter_inout_alloc(); + AVRational time_base = ifmt_ctx->streams[0]->time_base; + AVRational ir_time_base = ir_fmt_ctx->streams[0]->time_base; + + /* Determine the target format - always 44.1kHz, stereo unless IR is mono */ + char target_layout[64]; + int target_sample_rate = 44100; + + /* Determine output channel layout based on IR format */ + int ir_channels = ir_fmt_ctx->streams[0]->codecpar->ch_layout.nb_channels; + if (ir_channels == 0) { + ir_channels = ir_fmt_ctx->streams[0]->codecpar->channels; + } + + if (ir_channels == 1) { + strcpy(target_layout, "mono"); /* If IR is mono, output mono for simplicity */ + } else { + strcpy(target_layout, "stereo"); /* Otherwise, output stereo */ + } + + filter_graph = avfilter_graph_alloc(); + if (!outputs || !inputs || !filter_graph) { + ret = AVERROR(ENOMEM); + goto end; + } + + /* buffer audio source: the decoded frames from the decoder will be inserted here. */ + abuffer = avfilter_get_by_name("abuffer"); + if (!abuffer) { + av_log(NULL, AV_LOG_ERROR, "Could not find the abuffer filter.\n"); + ret = AVERROR_FILTER_NOT_FOUND; + goto end; + } + + buffersrc_ctx = avfilter_graph_alloc_filter(filter_graph, abuffer, "in"); + if (!buffersrc_ctx) { + av_log(NULL, AV_LOG_ERROR, "Could not allocate the abuffer instance.\n"); + ret = AVERROR(ENOMEM); + goto end; + } + + /* Set the filter options through the AVOptions API. */ + char ch_layout_str[64]; + // Use the actual channel layout from the input file + if (ifmt_ctx->streams[0]->codecpar->ch_layout.nb_channels == 0) { + // If channel layout is unknown, default based on channel count + if (ifmt_ctx->streams[0]->codecpar->channels == 1) { + strcpy(ch_layout_str, "mono"); + } else if (ifmt_ctx->streams[0]->codecpar->channels == 2) { + strcpy(ch_layout_str, "stereo"); + } else { + snprintf(ch_layout_str, sizeof(ch_layout_str), "%dc", ifmt_ctx->streams[0]->codecpar->channels); + } + } else { + av_channel_layout_describe(&ifmt_ctx->streams[0]->codecpar->ch_layout, ch_layout_str, sizeof(ch_layout_str)); + } + snprintf(args, sizeof(args), + "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=%s", + time_base.num, time_base.den, ifmt_ctx->streams[0]->codecpar->sample_rate, + av_get_sample_fmt_name(ifmt_ctx->streams[0]->codecpar->format), + ch_layout_str); + ret = avfilter_init_str(buffersrc_ctx, args); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Could not initialize the abuffer filter.\n"); + goto end; + } + + /* buffer audio source for IR: the decoded IR frames will be inserted here. */ + ir_buffersrc_ctx = avfilter_graph_alloc_filter(filter_graph, abuffer, "ir_in"); + if (!ir_buffersrc_ctx) { + av_log(NULL, AV_LOG_ERROR, "Could not allocate the IR abuffer instance.\n"); + ret = AVERROR(ENOMEM); + goto end; + } + + char ir_ch_layout_str[64]; + // Use the actual channel layout from the IR file + if (ir_fmt_ctx->streams[0]->codecpar->ch_layout.nb_channels == 0) { + // If channel layout is unknown, default based on channel count + if (ir_fmt_ctx->streams[0]->codecpar->channels == 1) { + strcpy(ir_ch_layout_str, "mono"); + } else if (ir_fmt_ctx->streams[0]->codecpar->channels == 2) { + strcpy(ir_ch_layout_str, "stereo"); + } else { + snprintf(ir_ch_layout_str, sizeof(ir_ch_layout_str), "%dc", ir_fmt_ctx->streams[0]->codecpar->channels); + } + } else { + av_channel_layout_describe(&ir_fmt_ctx->streams[0]->codecpar->ch_layout, ir_ch_layout_str, sizeof(ir_ch_layout_str)); + } + snprintf(ir_args, sizeof(ir_args), + "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=%s", + ir_time_base.num, ir_time_base.den, ir_fmt_ctx->streams[0]->codecpar->sample_rate, + av_get_sample_fmt_name(ir_fmt_ctx->streams[0]->codecpar->format), + ir_ch_layout_str); + ret = avfilter_init_str(ir_buffersrc_ctx, ir_args); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Could not initialize the IR abuffer filter.\n"); + goto end; + } + + /* buffer audio sink: to terminate the filter chain. */ + abuffersink = avfilter_get_by_name("abuffersink"); + if (!abuffersink) { + av_log(NULL, AV_LOG_ERROR, "Could not find the abuffersink filter.\n"); + ret = AVERROR_FILTER_NOT_FOUND; + goto end; + } + + buffersink_ctx = avfilter_graph_alloc_filter(filter_graph, abuffersink, "out"); + if (!buffersink_ctx) { + av_log(NULL, AV_LOG_ERROR, "Could not allocate the abuffersink instance.\n"); + ret = AVERROR(ENOMEM); + goto end; + } + + /* Configure the buffersink to accept the expected format */ + static const enum AVSampleFormat out_sample_fmts[] = { AV_SAMPLE_FMT_S16, -1 }; + ret = av_opt_set_int_list(buffersink_ctx, "sample_fmts", out_sample_fmts, -1, AV_OPT_SEARCH_CHILDREN); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot set output sample format\n"); + goto end; + } + + ret = av_opt_set(buffersink_ctx, "ch_layouts", target_layout, AV_OPT_SEARCH_CHILDREN); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layout\n"); + goto end; + } + + /* This filter takes no options. */ + ret = avfilter_init_str(buffersink_ctx, NULL); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Could not initialize the abuffersink instance.\n"); + goto end; + } + + /* + * Set the endpoints for the filter graph. The filter_graph will + * be linked to the graph described by filters_descr. + */ + + /* + * The buffer source output must be connected to the input pad of + * the first filter described by filters_descr; since the first + * filter input label is "in", with the pointer, we leave this + * pad open. + */ + outputs->name = av_strdup("in"); + outputs->filter_ctx = buffersrc_ctx; + outputs->pad_idx = 0; + outputs->next = avfilter_inout_alloc(); + + outputs->next->name = av_strdup("ir_in"); + outputs->next->filter_ctx = ir_buffersrc_ctx; + outputs->next->pad_idx = 0; + outputs->next->next = NULL; + + /* + * The buffer sink input must be connected to the output pad of + * the last filter described by filters_descr; since the last + * filter output label is "out", with the pointer, we leave this + * pad open. + */ + inputs->name = av_strdup("out"); + inputs->filter_ctx = buffersink_ctx; + inputs->pad_idx = 0; + inputs->next = NULL; + + /* Apply convolution reverb using afir filter with format normalization */ + char filters_descr[512]; + snprintf(filters_descr, sizeof(filters_descr), + "[ir_in]aresample=%d,aformat=sample_fmts=fltp:channel_layouts=%s[ir_norm];" + "[in]aresample=%d,aformat=sample_fmts=fltp:channel_layouts=%s,asplit[in_1][in_2];" + "[in_1][ir_norm]afir=dry=10:wet=10[reverb];" + "[in_2][reverb]amix=inputs=2:weights=100 %d,volume=1.5,aformat=sample_fmts=s16:channel_layouts=%s[out]", + target_sample_rate, target_layout, target_sample_rate, target_layout, ir_wet, target_layout); + + av_log(NULL, AV_LOG_INFO, "Filter graph: %s\n", filters_descr); + + if ((ret = avfilter_graph_parse_ptr(filter_graph, filters_descr, + &inputs, &outputs, NULL)) < 0) + goto end; + + if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0) + goto end; + +end: + avfilter_inout_free(&inputs); + avfilter_inout_free(&outputs); + + return ret; +} + +static int encode_write_frame(AVFrame *filt_frame, unsigned int stream_index, int *got_frame) { + int ret; + int got_frame_local; + AVPacket *enc_pkt; + + if (!got_frame) + got_frame = &got_frame_local; + + if (!enc_ctx) { + return AVERROR(EINVAL); + } + + enc_pkt = av_packet_alloc(); + if (!enc_pkt) { + return AVERROR(ENOMEM); + } + + /* encode filtered frame */ + ret = avcodec_send_frame(enc_ctx, filt_frame); + if (ret < 0) + goto end; + + while (ret >= 0) { + ret = avcodec_receive_packet(enc_ctx, enc_pkt); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + ret = 0; /* These are not errors */ + break; + } else if (ret < 0) + goto end; + + /* prepare packet for muxing */ + enc_pkt->stream_index = stream_index; + av_packet_rescale_ts(enc_pkt, + enc_ctx->time_base, + ofmt_ctx->streams[stream_index]->time_base); + + /* mux encoded frame */ + ret = av_interleaved_write_frame(ofmt_ctx, enc_pkt); + if (ret < 0) + break; + } + +end: + av_packet_free(&enc_pkt); + return ret; +} + +static int filter_encode_write_frame(AVFrame *frame, AVFrame *ir_frame, unsigned int stream_index) +{ + int ret; + AVFrame *filt_frame; + + /* Only add frames if they are provided */ + if (frame) { + ret = av_buffersrc_add_frame_flags(buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Error while feeding the input filtergraph\n"); + return ret; + } + } + + if (ir_frame) { + ret = av_buffersrc_add_frame_flags(ir_buffersrc_ctx, ir_frame, AV_BUFFERSRC_FLAG_KEEP_REF); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Error while feeding the IR filtergraph\n"); + return ret; + } + } + + /* Always try to pull filtered frames from the filtergraph */ + while (1) { + filt_frame = av_frame_alloc(); + if (!filt_frame) { + ret = AVERROR(ENOMEM); + break; + } + ret = av_buffersink_get_frame(buffersink_ctx, filt_frame); + if (ret < 0) { + /* if no more frames for output - returns AVERROR(EAGAIN) + * if flushed and no more frames for output - returns AVERROR_EOF + * rewrite retcode to 0 to show it as normal procedure completion + */ + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + ret = 0; + av_frame_free(&filt_frame); + break; + } + + printf("Got filtered frame: %d samples, %d channels, %d Hz\n", + filt_frame->nb_samples, filt_frame->ch_layout.nb_channels, filt_frame->sample_rate); + + ret = encode_write_frame(filt_frame, stream_index, NULL); + av_frame_free(&filt_frame); + if (ret < 0) + break; + } + + return ret; +} + +int encode(const char *fi, const char *ir, const char *fo, int irWet, int irPad) +{ + int ret; + AVPacket *packet = NULL, *ir_packet = NULL; + AVFrame *frame = NULL, *ir_frame = NULL; + AVCodecContext *dec_ctx = NULL, *ir_dec_ctx = NULL; + unsigned int stream_index; + int ir_loaded = 0; + + if ((ret = open_input_file(fi)) < 0) + goto end; + if ((ret = open_ir_file(ir)) < 0) + goto end; + if ((ret = open_output_file(fo)) < 0) + goto end; + if ((ret = init_filters(irWet, irPad)) < 0) + goto end; + + packet = av_packet_alloc(); + ir_packet = av_packet_alloc(); + frame = av_frame_alloc(); + ir_frame = av_frame_alloc(); + if (!packet || !ir_packet || !frame || !ir_frame) { + fprintf(stderr, "Could not allocate frame or packet\n"); + return(1); + } + + /* Set up decoder contexts */ + const AVCodec *dec = avcodec_find_decoder(ifmt_ctx->streams[0]->codecpar->codec_id); + const AVCodec *ir_dec = avcodec_find_decoder(ir_fmt_ctx->streams[0]->codecpar->codec_id); + + dec_ctx = avcodec_alloc_context3(dec); + ir_dec_ctx = avcodec_alloc_context3(ir_dec); + + avcodec_parameters_to_context(dec_ctx, ifmt_ctx->streams[0]->codecpar); + avcodec_parameters_to_context(ir_dec_ctx, ir_fmt_ctx->streams[0]->codecpar); + + avcodec_open2(dec_ctx, dec, NULL); + avcodec_open2(ir_dec_ctx, ir_dec, NULL); + + /* Process both streams - load ALL IR data first, then process main audio */ + int ir_eof = 0, main_eof = 0; + + /* First load all IR data */ + while (!ir_eof && av_read_frame(ir_fmt_ctx, ir_packet) >= 0) { + if (ir_packet->stream_index == 0) { + ret = avcodec_send_packet(ir_dec_ctx, ir_packet); + while (ret >= 0) { + ret = avcodec_receive_frame(ir_dec_ctx, ir_frame); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + break; + } else if (ret < 0) { + fprintf(stderr, "Error while decoding IR\n"); + goto end; + } + + ret = av_buffersrc_add_frame_flags(ir_buffersrc_ctx, ir_frame, AV_BUFFERSRC_FLAG_KEEP_REF); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Error while feeding the IR filtergraph\n"); + goto end; + } + ir_loaded = 1; + } + } + av_packet_unref(ir_packet); + } + + /* Signal end of IR stream */ + ret = av_buffersrc_add_frame_flags(ir_buffersrc_ctx, NULL, 0); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Error closing IR filtergraph\n"); + goto end; + } + + if (!ir_loaded) { + fprintf(stderr, "No impulse response data loaded\n"); + goto end; + } + + /* Now process the main audio */ + while (!main_eof && av_read_frame(ifmt_ctx, packet) >= 0) { + if (packet->stream_index == 0) { + ret = avcodec_send_packet(dec_ctx, packet); + while (ret >= 0) { + ret = avcodec_receive_frame(dec_ctx, frame); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + break; + } else if (ret < 0) { + fprintf(stderr, "Error while decoding\n"); + goto end; + } + + ret = av_buffersrc_add_frame_flags(buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Error while feeding the input filtergraph\n"); + goto end; + } + /* Pull filtered frames immediately */ + while (1) { + AVFrame *filt_frame = av_frame_alloc(); + ret = av_buffersink_get_frame(buffersink_ctx, filt_frame); + if (ret == AVERROR(EAGAIN)) { + av_frame_free(&filt_frame); + break; /* Need more input */ + } else if (ret == AVERROR_EOF) { + av_frame_free(&filt_frame); + break; /* No more frames */ + } else if (ret < 0) { + printf("Error getting frame from filter: %s\n", av_err2str(ret)); + av_frame_free(&filt_frame); + goto end; + } + + ret = encode_write_frame(filt_frame, 0, NULL); + av_frame_free(&filt_frame); + if (ret < 0) { + goto end; + } + } + } + } + av_packet_unref(packet); + } + + /* flush the filter graph by sending EOF to input sources */ + ret = av_buffersrc_add_frame_flags(buffersrc_ctx, NULL, 0); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Error while closing the input filtergraph\n"); + goto end; + } + + /* Pull any remaining frames from the filter graph */ + ret = filter_encode_write_frame(NULL, NULL, 0); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Flushing filter failed\n"); + goto end; + } + + /* flush the encoder */ + ret = avcodec_send_frame(enc_ctx, NULL); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Error sending NULL frame to encoder\n"); + goto end; + } + + while (ret >= 0) { + AVPacket *enc_pkt = av_packet_alloc(); + ret = avcodec_receive_packet(enc_ctx, enc_pkt); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + av_packet_free(&enc_pkt); + break; + } else if (ret < 0) { + av_packet_free(&enc_pkt); + av_log(NULL, AV_LOG_ERROR, "Error during encoder flush\n"); + goto end; + } + + enc_pkt->stream_index = 0; + av_packet_rescale_ts(enc_pkt, enc_ctx->time_base, ofmt_ctx->streams[0]->time_base); + ret = av_interleaved_write_frame(ofmt_ctx, enc_pkt); + av_packet_free(&enc_pkt); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Error writing final packet\n"); + goto end; + } + } + + av_write_trailer(ofmt_ctx); +end: + if (dec_ctx) { + avcodec_free_context(&dec_ctx); + } + if (ir_dec_ctx) { + avcodec_free_context(&ir_dec_ctx); + } + av_frame_free(&frame); + av_frame_free(&ir_frame); + av_packet_free(&packet); + av_packet_free(&ir_packet); + avfilter_graph_free(&filter_graph); + avformat_close_input(&ifmt_ctx); + avformat_close_input(&ir_fmt_ctx); + + if (enc_ctx) { + avcodec_free_context(&enc_ctx); + } + + if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) { + avio_closep(&ofmt_ctx->pb); + } + avformat_free_context(ofmt_ctx); + + if (ret < 0 && ret != AVERROR_EOF) { + fprintf(stderr, "Error occurred: %s\n", av_err2str(ret)); + return(1); + } + return 0; +} diff --git a/sources/Application/FX/LibavProcessor.h b/sources/Application/FX/LibavProcessor.h new file mode 100644 index 00000000..10b24fd9 --- /dev/null +++ b/sources/Application/FX/LibavProcessor.h @@ -0,0 +1,14 @@ +#ifndef LIBAV_PROC_H +#define LIBAV_PROC_H + +#ifdef __cplusplus +extern "C" { +#endif + +int encode(const char *fi, const char *ir, const char *fo, int irWet, int irPad); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file From 5e8eda6ad792f975318bd9e084de202a76715b29 Mon Sep 17 00:00:00 2001 From: djdiskmachine Date: Sat, 18 Oct 2025 20:53:14 +0200 Subject: [PATCH 02/38] Add legacy support Adds backwards compatibility Bittboy config builds OK! Garlic config Miyoo does not build, missing libs in toolchain --- projects/Makefile.BITTBOY | 9 ++- projects/Makefile.GARLIC | 8 ++- projects/Makefile.MIYOO | 6 +- projects/rules_libav | 8 ++- sources/Application/FX/LibavProcessor.c | 81 ++++++++++++++++++++++--- 5 files changed, 95 insertions(+), 17 deletions(-) diff --git a/projects/Makefile.BITTBOY b/projects/Makefile.BITTBOY index 2b505bcf..165fc21f 100644 --- a/projects/Makefile.BITTBOY +++ b/projects/Makefile.BITTBOY @@ -1,4 +1,5 @@ -include $(PWD)/rules_base + STRIP = $(CROSS_COMPILE)strip DEFINES := \ @@ -8,6 +9,8 @@ DEFINES := \ -DHAVE_STDINT_H \ -D_NDEBUG \ -D__LINUX_ALSA__ \ + -DFFMPEG_ENABLED \ + -DFFMPEG_LEGACY_API \ -D_NO_JACK_ DEVKIT=/opt/arm-buildroot-linux-musleabi_sdk-buildroot @@ -19,14 +22,16 @@ SDL_CFLAGS := $(shell $(SYSROOT)/usr/bin/sdl-config --cflags) SDL_LIBS := $(shell $(SYSROOT)/usr/bin/sdl-config --libs) SDL_BASE = $(DEVKIT)/arm-buildroot-linux-musleabi/sysroot/usr/bin/ +-include $(PWD)/rules_libav + TOOLPATH=$(DEVKIT)/usr/bin PREFIX := arm-linux- OPT_FLAGS = -O3 -Ofast -INCLUDES = -I$(PWD)/../sources -Iinclude $(SDL_CFLAGS) +INCLUDES = -I$(PWD)/../sources -Iinclude $(SDL_CFLAGS) $(FFMPEG_CFLAGS) CFLAGS := $(DEFINES) $(INCLUDES) $(OPT_FLAGS) $(SDL_CFLAGS) -Wall -DRS97 CXXFLAGS:= $(CFLAGS) -std=gnu++03 -LIBS := $(SDL_LIBS) -lSDL -lSDL_mixer -lasound -lpthread +LIBS := $(SDL_LIBS) -lSDL -lSDL_mixer -lasound -lpthread $(FFMPEG_LIBS) LIBDIRS := $(DEKVIT)/usr/lib OUTPUT = ../lgpt-bittboy EXTENSION:= elf diff --git a/projects/Makefile.GARLIC b/projects/Makefile.GARLIC index 657f6abe..63fa2393 100644 --- a/projects/Makefile.GARLIC +++ b/projects/Makefile.GARLIC @@ -6,6 +6,8 @@ DEFINES := \ -DCPP_MEMORY \ -D_NDEBUG \ -DHAVE_STDINT_H \ + -DFFMPEG_ENABLED \ + -DFFMPEG_LEGACY_API \ -D_NO_JACK_ DEVKIT = /opt/miyoo/ @@ -19,13 +21,15 @@ SYSROOT := $(shell $(CROSS_COMPILE)gcc --print-sysroot) SDL_CFLAGS := $(shell $(SYSROOT)/usr/bin/sdl-config --cflags) SDL_LIBS := $(shell $(SYSROOT)/usr/bin/sdl-config --libs) +-include $(PWD)/rules_libav + # optimization OPT_FLAGS = -O3 -Ofast -fdata-sections -fdata-sections -fno-common -fno-PIC -flto -marm -mtune=cortex-a53 -mfpu=neon-vfpv4 -mfloat-abi=hard PREFIX := arm-linux-gnueabihf- -INCLUDES:= -Iinclude $(SDL_CFLAGS) -I$(PWD)/../sources +INCLUDES:= -Iinclude $(SDL_CFLAGS) $(FFMPEG_CFLAGS) -I$(PWD)/../sources CFLAGS := $(DEFINES) $(INCLUDES) $(OPT_FLAGS) -Wall CXXFLAGS:= $(CFLAGS) -std=gnu++03 -LIBS := $(SDL_LIBS) -lpthread +LIBS := $(SDL_LIBS) $(FFMPEG_LIBS) -lpthread LIBDIRS := $(DEKVIT)/usr/lib LIBDIRS += $(DEKVIT)/usr/include OUTPUT := ../lgpt-garlic diff --git a/projects/Makefile.MIYOO b/projects/Makefile.MIYOO index e38c4117..e36bda73 100644 --- a/projects/Makefile.MIYOO +++ b/projects/Makefile.MIYOO @@ -6,6 +6,7 @@ DEFINES := \ -DCPP_MEMORY \ -DHAVE_STDINT_H \ -D_NDEBUG \ + -DFFMPEG_ENABLED \ -D_NO_JACK_ DEVKIT = /opt/miyoomini-toolchain/ @@ -18,16 +19,17 @@ SYSROOT := $(shell $(CROSS_COMPILE)gcc --print-sysroot) SDL_CFLAGS := $(shell $(SYSROOT)/usr/bin/sdl-config --cflags) SDL_LIBS := $(shell $(SYSROOT)/usr/bin/sdl-config --libs) -INCLUDES = -Iinclude $(SDL_CFLAGS) -I$(PWD)/../sources +INCLUDES = -Iinclude $(SDL_CFLAGS) $(FFMPEG_CFLAGS) -I$(PWD)/../sources OPT_FLAGS = -O3 -Ofast -fdata-sections -fdata-sections -fno-common -fno-PIC -flto -marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7ve+simd +-include $(PWD)/rules_libav TOOLPATH=$(DEVKIT)/usr/bin PREFIX := arm-linux-gnueabihf- CFLAGS := $(DEFINES) $(INCLUDES) $(SDL_CFLAGS) $(OPT_FLAGS) -Wall CXXFLAGS:= $(CFLAGS) -std=gnu++03 -LIBS := -lSDL -lSDL_mixer -lpthread $(SDL_LIBS) +LIBS := -lSDL -lSDL_mixer -lpthread $(SDL_LIBS) $(FFMPEG_LIBS) LIBDIRS := $(DEKVIT)/usr/lib LIBDIRS += $(DEKVIT)/usr/include OUTPUT = ../lgpt-miyoo diff --git a/projects/rules_libav b/projects/rules_libav index c8e13cf4..9c577791 100644 --- a/projects/rules_libav +++ b/projects/rules_libav @@ -3,5 +3,11 @@ FFMPEG_INCL= libavformat \ libavcodec \ libavutil \ +# Use SYSROOT for cross-compilation, fallback to system pkg-config for native builds +ifdef SYSROOT +FFMPEG_CFLAGS := $(shell $(DEVKIT)/bin/pkg-config --cflags $(FFMPEG_INCL)) +FFMPEG_LIBS := $(shell $(DEVKIT)/bin/pkg-config --libs $(FFMPEG_INCL)) +else FFMPEG_CFLAGS := $(shell pkg-config --cflags $(FFMPEG_INCL)) -FFMPEG_LIBS := $(shell pkg-config --libs $(FFMPEG_INCL)) \ No newline at end of file +FFMPEG_LIBS := $(shell pkg-config --libs $(FFMPEG_INCL)) +endif \ No newline at end of file diff --git a/sources/Application/FX/LibavProcessor.c b/sources/Application/FX/LibavProcessor.c index f10374e0..8f0de6d2 100644 --- a/sources/Application/FX/LibavProcessor.c +++ b/sources/Application/FX/LibavProcessor.c @@ -24,7 +24,7 @@ static AVCodecContext *enc_ctx = NULL; static int open_input_file(const char *filename) { - const AVCodec *dec; + AVCodec *dec; AVCodecContext *dec_ctx; AVStream *stream; int ret; @@ -63,7 +63,12 @@ static int open_input_file(const char *filename) stream->codecpar->codec_id = dec_ctx->codec_id; stream->codecpar->sample_rate = dec_ctx->sample_rate; stream->codecpar->format = dec_ctx->sample_fmt; +#ifdef FFMPEG_LEGACY_API + stream->codecpar->channels = dec_ctx->channels; + stream->codecpar->channel_layout = dec_ctx->channel_layout; +#else av_channel_layout_copy(&stream->codecpar->ch_layout, &dec_ctx->ch_layout); +#endif avcodec_free_context(&dec_ctx); @@ -72,7 +77,7 @@ static int open_input_file(const char *filename) static int open_ir_file(const char *filename) { - const AVCodec *dec; + AVCodec *dec; AVCodecContext *dec_ctx; AVStream *stream; int ret; @@ -111,7 +116,12 @@ static int open_ir_file(const char *filename) stream->codecpar->codec_id = dec_ctx->codec_id; stream->codecpar->sample_rate = dec_ctx->sample_rate; stream->codecpar->format = dec_ctx->sample_fmt; +#ifdef FFMPEG_LEGACY_API + stream->codecpar->channels = dec_ctx->channels; + stream->codecpar->channel_layout = dec_ctx->channel_layout; +#else av_channel_layout_copy(&stream->codecpar->ch_layout, &dec_ctx->ch_layout); +#endif avcodec_free_context(&dec_ctx); @@ -155,6 +165,20 @@ static int open_output_file(const char *filename) enc_ctx->sample_rate = 44100; /* Set channel layout based on IR format */ +#ifdef FFMPEG_LEGACY_API + int ir_channels = ir_fmt_ctx->streams[0]->codecpar->channels; + if (ir_channels == 0) { + ir_channels = ir_fmt_ctx->streams[0]->codecpar->channels; + } + + if (ir_channels == 1) { + enc_ctx->channels = 1; + enc_ctx->channel_layout = AV_CH_LAYOUT_MONO; + } else { + enc_ctx->channels = 2; + enc_ctx->channel_layout = AV_CH_LAYOUT_STEREO; + } +#else int ir_channels = ir_fmt_ctx->streams[0]->codecpar->ch_layout.nb_channels; if (ir_channels == 0) { ir_channels = ir_fmt_ctx->streams[0]->codecpar->channels; @@ -165,7 +189,8 @@ static int open_output_file(const char *filename) } else { av_channel_layout_default(&enc_ctx->ch_layout, 2); /* Stereo */ } - +#endif + /* Use S16 format to match encoder */ enc_ctx->sample_fmt = AV_SAMPLE_FMT_S16; @@ -220,11 +245,18 @@ static int init_filters(int ir_wet, int ir_pad) int target_sample_rate = 44100; /* Determine output channel layout based on IR format */ +#ifdef FFMPEG_LEGACY_API + int ir_channels = ir_fmt_ctx->streams[0]->codecpar->channels; + if (ir_channels == 0) { + ir_channels = ir_fmt_ctx->streams[0]->codecpar->channels; + } +#else int ir_channels = ir_fmt_ctx->streams[0]->codecpar->ch_layout.nb_channels; if (ir_channels == 0) { ir_channels = ir_fmt_ctx->streams[0]->codecpar->channels; } - +#endif + if (ir_channels == 1) { strcpy(target_layout, "mono"); /* If IR is mono, output mono for simplicity */ } else { @@ -255,6 +287,15 @@ static int init_filters(int ir_wet, int ir_pad) /* Set the filter options through the AVOptions API. */ char ch_layout_str[64]; // Use the actual channel layout from the input file +#ifdef FFMPEG_LEGACY_API + if (ifmt_ctx->streams[0]->codecpar->channels == 1) { + strcpy(ch_layout_str, "mono"); + } else if (ifmt_ctx->streams[0]->codecpar->channels == 2) { + strcpy(ch_layout_str, "stereo"); + } else { + snprintf(ch_layout_str, sizeof(ch_layout_str), "%dc", ifmt_ctx->streams[0]->codecpar->channels); + } +#else if (ifmt_ctx->streams[0]->codecpar->ch_layout.nb_channels == 0) { // If channel layout is unknown, default based on channel count if (ifmt_ctx->streams[0]->codecpar->channels == 1) { @@ -265,8 +306,10 @@ static int init_filters(int ir_wet, int ir_pad) snprintf(ch_layout_str, sizeof(ch_layout_str), "%dc", ifmt_ctx->streams[0]->codecpar->channels); } } else { - av_channel_layout_describe(&ifmt_ctx->streams[0]->codecpar->ch_layout, ch_layout_str, sizeof(ch_layout_str)); + av_channel_layout_describe(&buffersink_ctx->inputs[0]->ch_layout, + ch_layout_str, sizeof(ch_layout_str)); } +#endif snprintf(args, sizeof(args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=%s", time_base.num, time_base.den, ifmt_ctx->streams[0]->codecpar->sample_rate, @@ -288,6 +331,15 @@ static int init_filters(int ir_wet, int ir_pad) char ir_ch_layout_str[64]; // Use the actual channel layout from the IR file +#ifdef FFMPEG_LEGACY_API + if (ir_fmt_ctx->streams[0]->codecpar->channels == 1) { + strcpy(ir_ch_layout_str, "mono"); + } else if (ir_fmt_ctx->streams[0]->codecpar->channels == 2) { + strcpy(ir_ch_layout_str, "stereo"); + } else { + snprintf(ir_ch_layout_str, sizeof(ir_ch_layout_str), "%dc", ir_fmt_ctx->streams[0]->codecpar->channels); + } +#else if (ir_fmt_ctx->streams[0]->codecpar->ch_layout.nb_channels == 0) { // If channel layout is unknown, default based on channel count if (ir_fmt_ctx->streams[0]->codecpar->channels == 1) { @@ -298,8 +350,10 @@ static int init_filters(int ir_wet, int ir_pad) snprintf(ir_ch_layout_str, sizeof(ir_ch_layout_str), "%dc", ir_fmt_ctx->streams[0]->codecpar->channels); } } else { - av_channel_layout_describe(&ir_fmt_ctx->streams[0]->codecpar->ch_layout, ir_ch_layout_str, sizeof(ir_ch_layout_str)); + av_channel_layout_describe(&buffersink_ctx->inputs[0]->ch_layout, + ir_ch_layout_str, sizeof(ir_ch_layout_str)); } +#endif snprintf(ir_args, sizeof(ir_args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=%s", ir_time_base.num, ir_time_base.den, ir_fmt_ctx->streams[0]->codecpar->sample_rate, @@ -492,8 +546,14 @@ static int filter_encode_write_frame(AVFrame *frame, AVFrame *ir_frame, unsigned break; } - printf("Got filtered frame: %d samples, %d channels, %d Hz\n", - filt_frame->nb_samples, filt_frame->ch_layout.nb_channels, filt_frame->sample_rate); + printf("Got filtered frame: %d samples, %d channels, %d Hz\n", +#ifdef FFMPEG_LEGACY_API + filt_frame->nb_samples, filt_frame->channels, + filt_frame->sample_rate); +#else + filt_frame->nb_samples, filt_frame->ch_layout.nb_channels, + filt_frame->sample_rate); +#endif ret = encode_write_frame(filt_frame, stream_index, NULL); av_frame_free(&filt_frame); @@ -532,8 +592,9 @@ int encode(const char *fi, const char *ir, const char *fo, int irWet, int irPad) } /* Set up decoder contexts */ - const AVCodec *dec = avcodec_find_decoder(ifmt_ctx->streams[0]->codecpar->codec_id); - const AVCodec *ir_dec = avcodec_find_decoder(ir_fmt_ctx->streams[0]->codecpar->codec_id); + AVCodec *dec = + avcodec_find_decoder(ifmt_ctx->streams[0]->codecpar->codec_id); + AVCodec *ir_dec = avcodec_find_decoder(ir_fmt_ctx->streams[0]->codecpar->codec_id); dec_ctx = avcodec_alloc_context3(dec); ir_dec_ctx = avcodec_alloc_context3(ir_dec); From b325f83a35c3080c1c7eb0af0dd4318c61bc8062 Mon Sep 17 00:00:00 2001 From: djdiskmachine Date: Sat, 18 Oct 2025 23:41:29 +0200 Subject: [PATCH 03/38] Fix build errors for most platforms Add support for garlicplus, rg35xxplus Conditionally import libavprocessor if ffmpeg enabled --- .github/workflows/build.yml | 7 ++++--- .github/workflows/check.yml | 10 ++++++---- projects/Makefile | 9 +++++++-- projects/Makefile.GARLICPLUS | 10 +++++++--- projects/Makefile.RG35XXPLUS | 6 ++++-- sources/Application/FX/FxPrinter.cpp | 2 ++ sources/Application/FX/FxPrinter.h | 4 +++- 7 files changed, 33 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c811a04c..9839b784 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: run: | python -m pip install --upgrade pip pip install Pillow - choco install -y directx-sdk zip --no-progress --yes + choco install -y directx-sdk zip ffmpeg-shared --no-progress --yes shell: powershell - name: Download and Extract VCE9 release @@ -151,7 +151,7 @@ jobs: - name: Install required libraries run: | sudo apt update - sudo apt install -y make pkgconf libsdl2-dev libasound2-plugins libjack-dev python3-pillow + sudo apt install -y make pkgconf libsdl2-dev libasound2-plugins libjack-dev python3-pillow libavcodec-dev libavformat-dev libavfilter-dev libavutil-dev libswresample-dev - name: Build X64 working-directory: projects @@ -319,7 +319,7 @@ jobs: wget -qO ./debian-archive-keyring.deb "$BASE$LATEST" dpkg -i ./debian-archive-keyring.deb - apt update && apt install -y python3 python3-pillow + apt update && apt install -y python3 python3-pillow cd projects make PLATFORM=GARLIC ' @@ -439,6 +439,7 @@ jobs: wget https://www.libsdl.org/release/SDL2-2.0.14.dmg hdiutil attach SDL2-2.0.14.dmg sudo cp -R /Volumes/SDL2/SDL2.framework /Library/Frameworks/ + brew install ffmpeg - name: Build Xcode project run: | diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index cac485d8..ec3fffa6 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -60,7 +60,7 @@ jobs: uses: actions/checkout@v4.1.7 - name: Install build deps - run: choco install -y directx-sdk zip --no-progress --yes + run: choco install -y directx-sdk zip ffmpeg-shared --no-progress --yes shell: powershell - name: Download and Extract VCE9 release @@ -116,7 +116,7 @@ jobs: run: | sudo dpkg --add-architecture i386 sudo apt update - sudo apt install -y make pkgconf gcc-multilib g++-multilib libsdl1.2-dev:i386 libasound2-plugins:i386 libjack-dev:i386 python3-pillow + sudo apt install -y make pkgconf gcc-multilib g++-multilib libsdl1.2-dev:i386 libasound2-plugins:i386 libjack-dev:i386 python3-pillow libavcodec-dev:i386 libavformat-dev:i386 libavfilter-dev:i386 libavutil-dev:i386 libswresample-dev:i386 - name: Build DEB working-directory: projects @@ -148,7 +148,7 @@ jobs: run: | sudo dpkg --add-architecture i386 sudo apt update - sudo apt install -y make pkgconf gcc-multilib g++-multilib libsdl2-dev:i386 libasound2-plugins:i386 libjack-dev:i386 python3-pillow + sudo apt install -y make pkgconf gcc-multilib g++-multilib libsdl2-dev:i386 libasound2-plugins:i386 libjack-dev:i386 python3-pillow libavcodec-dev:i386 libavformat-dev:i386 libavfilter-dev:i386 libavutil-dev:i386 libswresample-dev:i386 - name: Build X86 working-directory: projects @@ -395,7 +395,8 @@ jobs: - name: Install required libraries run: | sudo apt update - sudo apt install -y make pkgconf libsdl2-dev libasound2-plugins libjack-dev python3-pillow + sudo apt install -y make pkgconf libsdl2-dev libasound2-plugins libjack-dev python3-pillow libavcodec-dev libavformat-dev libavfilter-dev libavutil-dev libswresample-dev + - name: Build X64 working-directory: projects @@ -429,6 +430,7 @@ jobs: wget https://www.libsdl.org/release/SDL2-2.0.14.dmg hdiutil attach SDL2-2.0.14.dmg sudo cp -R /Volumes/SDL2/SDL2.framework /Library/Frameworks/ + brew install ffmpeg - name: Build Xcode project run: | diff --git a/projects/Makefile b/projects/Makefile index 5267e08f..4bed97eb 100644 --- a/projects/Makefile +++ b/projects/Makefile @@ -260,8 +260,7 @@ COMMONFILES := \ SyncMaster.o TablePlayback.o Player.o \ Table.o TableView.o\ InstrumentBank.o WavFileWriter.o WavFile.o MidiInstrument.o Filters.o \ - SampleVariable.o SampleInstrument.o SamplePool.o CommandList.o \ - LibavProcessor.o FxPrinter.o\ + SampleVariable.o SampleInstrument.o SamplePool.o CommandList.o FxPrinter.o\ PersistencyService.o Persistent.o \ Observable.o SingletonRegistry.o \ Audio.o AudioMixer.o AudioOutDriver.o AudioDriver.o \ @@ -276,6 +275,12 @@ COMMONFILES := \ HexBuffers.o lz.o \ tinyxmlparser.o tinyxml.o tinyxmlerror.o tinystr.o Tiny2NosStub.o +ifneq ($(FFMPEG_ENABLED), 0) +ifneq ($(strip $(FFMPEG_LIBS)),) + COMMONFILES += LibavProcessor.o +endif +endif + #--------------------------------------------------------------------------------- # Linux #--------------------------------------------------------------------------------- diff --git a/projects/Makefile.GARLICPLUS b/projects/Makefile.GARLICPLUS index 72ce69c4..008de35a 100644 --- a/projects/Makefile.GARLICPLUS +++ b/projects/Makefile.GARLICPLUS @@ -9,7 +9,9 @@ DEFINES := \ -DCPP_MEMORY \ -D_NDEBUG \ -DHAVE_STDINT_H \ - -D_NO_JACK_ + -D_NO_JACK_ \ + -DFFMPEG_ENABLED + # compiled using the https://github.com/shauninman/union-rg35xxplus-toolchain @@ -23,13 +25,15 @@ SYSROOT := $(shell $(CROSS_COMPILE)gcc --print-sysroot) SDL_CFLAGS := $(shell $(SYSROOT)/usr/bin/sdl-config --cflags) SDL_LIBS := $(shell $(SYSROOT)/usr/bin/sdl-config --libs) +-include $(PWD)/rules_libav + # optimization OPT_FLAGS = -O3 -Ofast -fdata-sections -fdata-sections -fno-common -fno-PIC -flto -marm -mtune=cortex-a53 -mfpu=neon-vfpv4 -mfloat-abi=hard PREFIX := arm-linux-gnueabihf- -INCLUDES = -Iinclude $(SDL_CFLAGS) -I$(PWD)/../sources +INCLUDES = -Iinclude $(SDL_CFLAGS) $(FFMPEG_CFLAGS) -I$(PWD)/../sources CFLAGS := $(DEFINES) $(INCLUDES) $(OPT_FLAGS) -Wall CXXFLAGS:= $(CFLAGS) -std=gnu++03 -LIBS := -lSDL -lpthread +LIBS := -lSDL -lpthread $(FFMPEG_LIBS) LIBDIRS := $(DEKVIT)/usr/lib LIBDIRS += $(DEKVIT)/usr/include OUTPUT = ../lgpt-garlicplus diff --git a/projects/Makefile.RG35XXPLUS b/projects/Makefile.RG35XXPLUS index dc04b211..09e0a131 100644 --- a/projects/Makefile.RG35XXPLUS +++ b/projects/Makefile.RG35XXPLUS @@ -24,11 +24,13 @@ TOOLPATH=$(DEVKIT)/usr/bin SDL_CFLAGS := -I/$(SYSROOT)/include -D_REENTRANT SDL_LIBS := -lSDL2 +-include $(PWD)/rules_libav + OPT_FLAGS = -O3 -mlittle-endian -mabi=lp64 -march=armv8-a+crypto+crc -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -dumpbase -INCLUDES = -Iinclude $(SDL_CFLAGS) -I$(DEVKIT)/$(TRIPLET)/include -I$(DEVKIT)/$(TRIPLET)/include/c++/11/ -I$(PWD)/../sources +INCLUDES = -Iinclude $(SDL_CFLAGS) $(FFMPEG_CFLAGS) -I$(DEVKIT)/$(TRIPLET)/include -I$(DEVKIT)/$(TRIPLET)/include/c++/11/ -I$(PWD)/../sources CFLAGS := $(DEFINES) $(INCLUDES) $(OPT_FLAGS) -Wall CXXFLAGS:= $(CFLAGS) -std=gnu++03 -LIBS := -Wl,-rpath-link,$(DEVKIT)/$(TRIPLET)/lib -Wl,-rpath-link,$(DEVKIT)/$(TRIPLET)/lib/pulseaudio $(SDL_LIBS) -lpthread +LIBS := -Wl,-rpath-link,$(DEVKIT)/$(TRIPLET)/lib -Wl,-rpath-link,$(DEVKIT)/$(TRIPLET)/lib/pulseaudio $(SDL_LIBS) $(FFMPEG_LIBS) -lpthread OUTPUT = ../lgpt-rg35xxplus EXTENSION:= elf diff --git a/sources/Application/FX/FxPrinter.cpp b/sources/Application/FX/FxPrinter.cpp index 8e22aaa0..665a7f91 100644 --- a/sources/Application/FX/FxPrinter.cpp +++ b/sources/Application/FX/FxPrinter.cpp @@ -62,6 +62,7 @@ bool FxPrinter::Run() { // Are we overwriting an already imported sample? bool imported = SamplePool::GetInstance()->IsImported(fo_); parseCommand(); +#ifdef FFMPEG_ENABLED if (encode(fiPath_.c_str(), ir_.c_str(), foPath_.c_str(), irWet_, irPad_) == 0) { int newIndex = SamplePool::GetInstance()->Reassign(fo_, imported); instrument_->AssignSample(newIndex); @@ -72,4 +73,5 @@ bool FxPrinter::Run() { notificationResult_ = "Failed, check lgpt.log"; return false; } +#endif } diff --git a/sources/Application/FX/FxPrinter.h b/sources/Application/FX/FxPrinter.h index 0e5e3018..912fdae2 100644 --- a/sources/Application/FX/FxPrinter.h +++ b/sources/Application/FX/FxPrinter.h @@ -5,10 +5,12 @@ #include "Application/Instruments/SampleInstrument.h" #include "Application/Instruments/SamplePool.h" #include "Application/Views/ViewData.h" -#include "LibavProcessor.h" #include "System/FileSystem/FileSystem.h" #include #include +#ifdef FFMPEG_ENABLED +#include "LibavProcessor.h" +#endif class FxPrinter { public: From 9a87db733972b111c0bb262f775e77fb0804d028 Mon Sep 17 00:00:00 2001 From: djdiskmachine Date: Sun, 19 Oct 2025 00:56:14 +0200 Subject: [PATCH 04/38] Fix no return value in Run RG35xx is missing libavfilter required for porting Added visual confirmation of includes Fix build error in x86 --- projects/Makefile.RG35XXPLUS | 12 +++++++++++- projects/Makefile.X86 | 14 ++++++++++++-- projects/rules_libav | 5 ++++- sources/Application/FX/FxPrinter.cpp | 4 ++++ 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/projects/Makefile.RG35XXPLUS b/projects/Makefile.RG35XXPLUS index 09e0a131..e9f647f7 100644 --- a/projects/Makefile.RG35XXPLUS +++ b/projects/Makefile.RG35XXPLUS @@ -24,7 +24,17 @@ TOOLPATH=$(DEVKIT)/usr/bin SDL_CFLAGS := -I/$(SYSROOT)/include -D_REENTRANT SDL_LIBS := -lSDL2 --include $(PWD)/rules_libav +FFMPEG_INCL= libavformat \ + libavfilter \ + libavcodec \ + libavutil \ + +LIBAV_PATH := aarch64-linux-gnu/include +FFMPEG_CFLAGS := -I$(DEVKIT)/$(LIBAV_PATH)/libavformat -I$(DEVKIT)/$(LIBAV_PATH)/libavfilter -I$(DEVKIT)/$(LIBAV_PATH)/libavcodec -I$(SYSROOT)/$(LIBAV_PATH)/libavutil +FFMPEG_LIBS := -lavformat -lavfilter -lavcodec -lavutil + +$(info FFMPEG_CFLAGS: $(FFMPEG_CFLAGS)) +$(info FFMPEG_LIBS: $(FFMPEG_LIBS)) OPT_FLAGS = -O3 -mlittle-endian -mabi=lp64 -march=armv8-a+crypto+crc -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -dumpbase INCLUDES = -Iinclude $(SDL_CFLAGS) $(FFMPEG_CFLAGS) -I$(DEVKIT)/$(TRIPLET)/include -I$(DEVKIT)/$(TRIPLET)/include/c++/11/ -I$(PWD)/../sources diff --git a/projects/Makefile.X86 b/projects/Makefile.X86 index 4c8b3b86..8255db5e 100644 --- a/projects/Makefile.X86 +++ b/projects/Makefile.X86 @@ -11,21 +11,31 @@ DEFINES := \ -DRTMIDI \ -DFFMPEG_ENABLED +FFMPEG_INCL= libavformat \ + libavfilter \ + libavcodec \ + libavutil \ + ALSA_CFLAGS := $(shell i686-linux-gnu-pkg-config alsa --cflags) ALSA_LIBS := $(shell i686-linux-gnu-pkg-config alsa --libs) JACK_CFLAGS := $(shell i686-linux-gnu-pkg-config jack --cflags) JACK_LIBS := $(shell i686-linux-gnu-pkg-config jack --libs) SDL_CFLAGS := $(shell i686-linux-gnu-pkg-config sdl2 --cflags) SDL_LIBS := $(shell i686-linux-gnu-pkg-config sdl2 --libs) +FFMPEG_CFLAGS := $(shell i686-linux-gnu-pkg-config $(FFMPEG_INCL) --cflags) +FFMPEG_LIBS := $(shell i686-linux-gnu-pkg-config $(FFMPEG_INCL) --libs) + +$(info FFMPEG_CFLAGS: $(FFMPEG_CFLAGS)) +$(info FFMPEG_LIBS: $(FFMPEG_LIBS)) # optimization OPT_FLAGS := -O3 -m32 #For debugging #OPT_FLAGS := -g -m32 -INCLUDES := $(ALSA_CFLAGS) $(JACK_CFLAGS) $(SDL_CFLAGS) -I$(PWD)/../sources +INCLUDES := $(ALSA_CFLAGS) $(JACK_CFLAGS) $(SDL_CFLAGS) $(FFMPEG_CFLAGS) -I$(PWD)/../sources CFLAGS := $(OPT_FLAGS) $(DEFINES) $(INCLUDES) -Wall CXXFLAGS := $(CFLAGS) -LIBS := $(ALSA_LIBS) $(JACK_LIBS) $(SDL_LIBS) +LIBS := $(ALSA_LIBS) $(JACK_LIBS) $(SDL_LIBS) $(FFMPEG_LIBS) LDFLAGS := -m32 OUTPUT = ../lgpt EXTENSION := x86 diff --git a/projects/rules_libav b/projects/rules_libav index 9c577791..e8876171 100644 --- a/projects/rules_libav +++ b/projects/rules_libav @@ -10,4 +10,7 @@ FFMPEG_LIBS := $(shell $(DEVKIT)/bin/pkg-config --libs $(FFMPEG_INCL)) else FFMPEG_CFLAGS := $(shell pkg-config --cflags $(FFMPEG_INCL)) FFMPEG_LIBS := $(shell pkg-config --libs $(FFMPEG_INCL)) -endif \ No newline at end of file +endif + +$(info FFMPEG_CFLAGS: $(FFMPEG_CFLAGS)) +$(info FFMPEG_LIBS: $(FFMPEG_LIBS)) diff --git a/sources/Application/FX/FxPrinter.cpp b/sources/Application/FX/FxPrinter.cpp index 665a7f91..40b3b368 100644 --- a/sources/Application/FX/FxPrinter.cpp +++ b/sources/Application/FX/FxPrinter.cpp @@ -73,5 +73,9 @@ bool FxPrinter::Run() { notificationResult_ = "Failed, check lgpt.log"; return false; } +#else + Trace::Log("PRINTFX", "Failed"); + notificationResult_ = "Failed, check lgpt.log"; + return false; #endif } From 580f3486ac6d3c993cfae50a8f979d9209181926 Mon Sep 17 00:00:00 2001 From: djdiskmachine Date: Sun, 19 Oct 2025 19:47:20 +0200 Subject: [PATCH 05/38] Swap garlicplus toolchain --- .github/workflows/build.yml | 2 +- .github/workflows/check.yml | 2 +- projects/Makefile.GARLICPLUS | 11 ++++++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9839b784..b329380b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -358,7 +358,7 @@ jobs: - name: Install Garlic Plus toolchain run: | sudo apt update && sudo apt install -y python3-pillow - wget -O /tmp/rg35xxplus-toolchain.tar.xz https://github.com/simotek/union-rg35xxplus-toolchain/releases/download/20240830/rg35xxplus-toolchain.tar.xz + wget -O /tmp/rg35xxplus-toolchain.tar.xz https://github.com/djdiskmachine/union-rg35xxplus-toolchain/releases/download/1.1/rg35xxplus-toolchain.tar.gz mkdir /opt/rg35xxplus-toolchain tar -xvf /tmp/rg35xxplus-toolchain.tar.xz -C /opt/rg35xxplus-toolchain --strip-components=1 diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index ec3fffa6..f416dfe6 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -292,7 +292,7 @@ jobs: - name: Install Garlic Plus toolchain run: | sudo apt update && sudo apt install -y python3-pillow - wget -O /tmp/rg35xxplus-toolchain.tar.xz https://github.com/simotek/union-rg35xxplus-toolchain/releases/download/20240830/rg35xxplus-toolchain.tar.xz + wget -O /tmp/rg35xxplus-toolchain.tar.xz https://github.com/djdiskmachine/union-rg35xxplus-toolchain/releases/download/1.1/rg35xxplus-toolchain.tar.gz mkdir /opt/rg35xxplus-toolchain tar -xvf /tmp/rg35xxplus-toolchain.tar.xz -C /opt/rg35xxplus-toolchain --strip-components=1 diff --git a/projects/Makefile.GARLICPLUS b/projects/Makefile.GARLICPLUS index 008de35a..4b2588a1 100644 --- a/projects/Makefile.GARLICPLUS +++ b/projects/Makefile.GARLICPLUS @@ -25,7 +25,16 @@ SYSROOT := $(shell $(CROSS_COMPILE)gcc --print-sysroot) SDL_CFLAGS := $(shell $(SYSROOT)/usr/bin/sdl-config --cflags) SDL_LIBS := $(shell $(SYSROOT)/usr/bin/sdl-config --libs) --include $(PWD)/rules_libav +FFMPEG_INCL= libavformat \ + libavfilter \ + libavcodec \ + libavutil \ + +FFMPEG_CFLAGS := $(shell $(DEVKIT)/usr/bin/pkg-config --cflags $(FFMPEG_INCL)) +FFMPEG_LIBS := $(shell $(DEVKIT)/usr/bin/pkg-config --libs $(FFMPEG_INCL)) + +$(info FFMPEG_CFLAGS: $(FFMPEG_CFLAGS)) +$(info FFMPEG_LIBS: $(FFMPEG_LIBS)) # optimization OPT_FLAGS = -O3 -Ofast -fdata-sections -fdata-sections -fno-common -fno-PIC -flto -marm -mtune=cortex-a53 -mfpu=neon-vfpv4 -mfloat-abi=hard From e4b878a18ef93248bf92adf74baa6798dc194535 Mon Sep 17 00:00:00 2001 From: djdiskmachine Date: Sun, 19 Oct 2025 20:14:25 +0200 Subject: [PATCH 06/38] Add Win32 Removed Miyoo from targets Fix legacy ffmpeg for garlicplus Updated vcproj Update README table --- README.md | 35 +++++++++++++++++------------------ projects/Makefile.GARLICPLUS | 3 ++- projects/Makefile.MIYOO | 7 ++----- projects/lgpt.vcproj | 16 ++++++++++++---- 4 files changed, 33 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index ce6d7ee7..a8492d1d 100644 --- a/README.md +++ b/README.md @@ -40,25 +40,24 @@ Recommended reading to get you started: ## Features per platform -| Platform | MIDI_Possible | MIDI_enabled | Soundfonts | Note | -|-------------|---------------|--------------|------------|--------------------------------------| -| PSP | NO | NO | YES | [See notes](projects/resources/PSP/INSTALL_HOW_TO.txt) | -| DEB | YES | YES | YES | | -| X64 | YES | YES | NO | | -| X86 | YES | YES | YES | | -| STEAM | YES | YES | NO | | -| MIYOO | NO | NO | YES | Port by [Nine-H](https://ninethehacker.xyz) | -| W32 | YES | YES | YES | Built in VS2008 with love | -| RASPI | YES | YES | YES | Versatile platform | -| CHIP | YES | YES | YES | [See notes](projects/resources/CHIP/INSTALL_HOW_TO.txt) | -| BITTBOY | MAYBE | NO | YES | | -| GARLIC | MAYBE | NO | YES | Port by [Simotek](http://simotek.net)| -| GARLICPLUS | MAYBE | NO | YES | Port by [Simotek](http://simotek.net)| -| RG35XXPLUS | MAYBE | NO | YES | Port by [Simotek](http://simotek.net)| -| MACOS | YES | YES | NO | Port by [clsource](https://genserver.social/clsource) | - +| Platform | MIDI_Possible | MIDI_enabled | Soundfonts | PrintFX | Note | +|-------------|---------------|--------------|------------|---------|--------------------------------------| +| PSP | NO | NO | YES | NO | [See notes](projects/resources/PSP/INSTALL_HOW_TO.txt) | +| DEB | YES | YES | YES | YES | | +| X64 | YES | YES | NO | YES | | +| X86 | YES | YES | YES | YES | | +| STEAM | YES | YES | NO | YES | | +| MIYOO | NO | NO | YES | NO | Port by [Nine-H](https://ninethehacker.xyz) | +| W32 | YES | YES | YES | YES | Built in VS2008 with love | +| RASPI | YES | YES | YES | YES | Versatile platform | +| CHIP | YES | YES | YES | YES | [See notes](projects/resources/CHIP/INSTALL_HOW_TO.txt) | +| BITTBOY | MAYBE | NO | YES | YES | | +| GARLIC | MAYBE | NO | YES | YES | Port by [Simotek](http://simotek.net)| +| GARLICPLUS | MAYBE | NO | YES | YES | Port by [Simotek](http://simotek.net)| +| RG35XXPLUS | MAYBE | NO | YES | NO | Port by [Simotek](http://simotek.net)| +| MACOS | YES | YES | NO | NO | Port by [clsource](https://genserver.social/clsource) | * **Soundfont library is currently not ported for 64bit OS** * **MIDI functionality __greatly__ depends on kernel support, please feature request your favourite OS maintainer =)** * **Install ffmpeg by following install instructions for your platform [here](https://www.ffmpeg.org/download.html)** -* **PrintFX requires full ffmpeg. If marked as TBA, it requires a redesign using [libav](https://trac.ffmpeg.org/wiki/Using%20libav*)** +* **PrintFX requires toolchain support of ffmpeg libs, for all targets marked maybe contact the maintainer of your consoles toolchain** diff --git a/projects/Makefile.GARLICPLUS b/projects/Makefile.GARLICPLUS index 4b2588a1..51b588d3 100644 --- a/projects/Makefile.GARLICPLUS +++ b/projects/Makefile.GARLICPLUS @@ -10,7 +10,8 @@ DEFINES := \ -D_NDEBUG \ -DHAVE_STDINT_H \ -D_NO_JACK_ \ - -DFFMPEG_ENABLED + -DFFMPEG_ENABLED \ + -DFFMPEG_LEGACY_API # compiled using the https://github.com/shauninman/union-rg35xxplus-toolchain diff --git a/projects/Makefile.MIYOO b/projects/Makefile.MIYOO index e36bda73..759de6cf 100644 --- a/projects/Makefile.MIYOO +++ b/projects/Makefile.MIYOO @@ -6,7 +6,6 @@ DEFINES := \ -DCPP_MEMORY \ -DHAVE_STDINT_H \ -D_NDEBUG \ - -DFFMPEG_ENABLED \ -D_NO_JACK_ DEVKIT = /opt/miyoomini-toolchain/ @@ -19,17 +18,15 @@ SYSROOT := $(shell $(CROSS_COMPILE)gcc --print-sysroot) SDL_CFLAGS := $(shell $(SYSROOT)/usr/bin/sdl-config --cflags) SDL_LIBS := $(shell $(SYSROOT)/usr/bin/sdl-config --libs) -INCLUDES = -Iinclude $(SDL_CFLAGS) $(FFMPEG_CFLAGS) -I$(PWD)/../sources +INCLUDES = -Iinclude $(SDL_CFLAGS) -I$(PWD)/../sources OPT_FLAGS = -O3 -Ofast -fdata-sections -fdata-sections -fno-common -fno-PIC -flto -marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7ve+simd --include $(PWD)/rules_libav - TOOLPATH=$(DEVKIT)/usr/bin PREFIX := arm-linux-gnueabihf- CFLAGS := $(DEFINES) $(INCLUDES) $(SDL_CFLAGS) $(OPT_FLAGS) -Wall CXXFLAGS:= $(CFLAGS) -std=gnu++03 -LIBS := -lSDL -lSDL_mixer -lpthread $(SDL_LIBS) $(FFMPEG_LIBS) +LIBS := -lSDL -lSDL_mixer -lpthread $(SDL_LIBS) LIBDIRS := $(DEKVIT)/usr/lib LIBDIRS += $(DEKVIT)/usr/include OUTPUT = ../lgpt-miyoo diff --git a/projects/lgpt.vcproj b/projects/lgpt.vcproj index d50935b8..30d70204 100644 --- a/projects/lgpt.vcproj +++ b/projects/lgpt.vcproj @@ -43,7 +43,7 @@ AdditionalOptions="/MP" Optimization="0" AdditionalIncludeDirectories="../sources/Externals;../sources/" - PreprocessorDefinitions="WIN32;_DEBUG;__WINDOWS_DS__;__WINDOWS_ASIO__;_CRT_SECURE_NO_WARNINGS;__WINDOWS_MM__;CPP_MEMORY;_LGPT_NO_SCREEN_CACHE_" + PreprocessorDefinitions="WIN32;_DEBUG;__WINDOWS_DS__;__WINDOWS_ASIO__;_CRT_SECURE_NO_WARNINGS;__WINDOWS_MM__;CPP_MEMORY;_LGPT_NO_SCREEN_CACHE_;FFMPEG_ENABLED;FFMPEG_LEGACY_API" MinimalRebuild="false" BasicRuntimeChecks="3" RuntimeLibrary="3" @@ -65,7 +65,7 @@ + + + + Date: Sun, 19 Oct 2025 20:28:14 +0200 Subject: [PATCH 07/38] Bump project number --- sources/Application/Model/Project.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/Application/Model/Project.h b/sources/Application/Model/Project.h index 6c347642..33829259 100644 --- a/sources/Application/Model/Project.h +++ b/sources/Application/Model/Project.h @@ -19,8 +19,8 @@ #define VAR_SCALE MAKE_FOURCC('S', 'C', 'A', 'L') #define PROJECT_NUMBER "1" -#define PROJECT_RELEASE "5" -#define BUILD_COUNT "0-bacon2" +#define PROJECT_RELEASE "6" +#define BUILD_COUNT "0-bacon0" #define MAX_TAP 3 From fd49f8cdfc294f155632e3a99e5babea6352f31e Mon Sep 17 00:00:00 2001 From: djdiskmachine Date: Sun, 19 Oct 2025 20:39:09 +0200 Subject: [PATCH 08/38] FFMPEG deps for Win32 --- .github/workflows/check.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index f416dfe6..e882f642 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -63,6 +63,13 @@ jobs: run: choco install -y directx-sdk zip ffmpeg-shared --no-progress --yes shell: powershell + - name: Install FFmpeg development libraries via vcpkg + run: | + git clone https://github.com/Microsoft/vcpkg.git C:\vcpkg + C:\vcpkg\bootstrap-vcpkg.bat + C:\vcpkg\vcpkg.exe install ffmpeg[avcodec,avformat,avfilter,avutil]:x86-windows-static + shell: cmd + - name: Download and Extract VCE9 release run: | $url = "https://github.com/djdiskmachine/VCE9/releases/download/v1.0.0/Microsoft.Visual.Studio.9.0.zip" From adbb530c295df2d20d71ef10abd59636609f5dd3 Mon Sep 17 00:00:00 2001 From: djdiskmachine Date: Sun, 19 Oct 2025 20:59:56 +0200 Subject: [PATCH 09/38] vcpkg installation ffmpeg --- .github/workflows/check.yml | 8 +++----- projects/lgpt.vcproj | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index e882f642..04881628 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -62,12 +62,10 @@ jobs: - name: Install build deps run: choco install -y directx-sdk zip ffmpeg-shared --no-progress --yes shell: powershell - - - name: Install FFmpeg development libraries via vcpkg + + - name: Install FFmpeg run: | - git clone https://github.com/Microsoft/vcpkg.git C:\vcpkg - C:\vcpkg\bootstrap-vcpkg.bat - C:\vcpkg\vcpkg.exe install ffmpeg[avcodec,avformat,avfilter,avutil]:x86-windows-static + vcpkg install ffmpeg[avcodec,avformat,avfilter,avutil]:x86-windows-static shell: cmd - name: Download and Extract VCE9 release diff --git a/projects/lgpt.vcproj b/projects/lgpt.vcproj index 30d70204..fb7deefc 100644 --- a/projects/lgpt.vcproj +++ b/projects/lgpt.vcproj @@ -42,7 +42,7 @@ Name="VCCLCompilerTool" AdditionalOptions="/MP" Optimization="0" - AdditionalIncludeDirectories="../sources/Externals;../sources/" + AdditionalIncludeDirectories="../sources/Externals;../sources/;C:\vcpkg\installed\x86-windows-static\include" PreprocessorDefinitions="WIN32;_DEBUG;__WINDOWS_DS__;__WINDOWS_ASIO__;_CRT_SECURE_NO_WARNINGS;__WINDOWS_MM__;CPP_MEMORY;_LGPT_NO_SCREEN_CACHE_;FFMPEG_ENABLED;FFMPEG_LEGACY_API" MinimalRebuild="false" BasicRuntimeChecks="3" @@ -125,7 +125,7 @@ Date: Sun, 19 Oct 2025 21:26:14 +0200 Subject: [PATCH 10/38] libav install fix --- .github/workflows/check.yml | 5 ++--- projects/lgpt.vcproj | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 04881628..0fc8e278 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -63,9 +63,8 @@ jobs: run: choco install -y directx-sdk zip ffmpeg-shared --no-progress --yes shell: powershell - - name: Install FFmpeg - run: | - vcpkg install ffmpeg[avcodec,avformat,avfilter,avutil]:x86-windows-static + - name: Install FFmpeg development libraries + run: vcpkg install ffmpeg[avcodec,avformat,avfilter]:x86-windows-static shell: cmd - name: Download and Extract VCE9 release diff --git a/projects/lgpt.vcproj b/projects/lgpt.vcproj index fb7deefc..6439789c 100644 --- a/projects/lgpt.vcproj +++ b/projects/lgpt.vcproj @@ -68,7 +68,7 @@ AdditionalDependencies="sdlmain.lib sdl.lib winmm.lib dsound.lib SDL_image.lib avformat.lib avcodec.lib avutil.lib avfilter.lib" OutputFile="$(OutDir)/lgptd.exe" LinkIncremental="2" - AdditionalLibraryDirectories="../libs/WSDL" + AdditionalLibraryDirectories="../libs/WSDL;C:\vcpkg\installed\x86-windows-static\lib" IgnoreDefaultLibraryNames="msvcrt.lib" GenerateDebugInformation="true" ProgramDatabaseFile="$(OutDir)/lgpt.pdb" @@ -148,7 +148,7 @@ AdditionalDependencies="sdlmain-release.lib sdl-release.lib winmm.lib dsound.lib avformat.lib avcodec.lib avutil.lib avfilter.lib" OutputFile="$(OutDir)/lgpt-W32.exe" LinkIncremental="1" - AdditionalLibraryDirectories="../libs/WSDL" + AdditionalLibraryDirectories="../libs/WSDL;C:\vcpkg\installed\x86-windows-static\lib" GenerateManifest="false" IgnoreDefaultLibraryNames="" GenerateDebugInformation="false" From f5d2bf8cff0ee1c29e3227710a3e2edfd77aa920 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Thu, 23 Oct 2025 15:20:01 +0000 Subject: [PATCH 11/38] Update miyoo toolchain & add back ffmpeg --- .github/workflows/check.yml | 2 +- projects/Makefile.MIYOO | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 0fc8e278..cd7c1478 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -364,7 +364,7 @@ jobs: - name: Install Miyoo Mini toolchain run: | sudo apt update && sudo apt install -y python3-pillow - wget -O /tmp/miyoomini-toolchain.tar.xz https://github.com/djdiskmachine/miyoomini-toolchain-buildroot/releases/download/1.0.0/miyoomini-toolchain.tar.xz + wget -O /tmp/miyoomini-toolchain.tar.xz https://github.com/djdiskmachine/miyoomini-toolchain-buildroot/releases/download/1.1/miyoomini-toolchain.tar.xz mkdir /opt/miyoomini-toolchain tar -xvf /tmp/miyoomini-toolchain.tar.xz -C /opt/miyoomini-toolchain --strip-components=1 diff --git a/projects/Makefile.MIYOO b/projects/Makefile.MIYOO index 759de6cf..e36bda73 100644 --- a/projects/Makefile.MIYOO +++ b/projects/Makefile.MIYOO @@ -6,6 +6,7 @@ DEFINES := \ -DCPP_MEMORY \ -DHAVE_STDINT_H \ -D_NDEBUG \ + -DFFMPEG_ENABLED \ -D_NO_JACK_ DEVKIT = /opt/miyoomini-toolchain/ @@ -18,15 +19,17 @@ SYSROOT := $(shell $(CROSS_COMPILE)gcc --print-sysroot) SDL_CFLAGS := $(shell $(SYSROOT)/usr/bin/sdl-config --cflags) SDL_LIBS := $(shell $(SYSROOT)/usr/bin/sdl-config --libs) -INCLUDES = -Iinclude $(SDL_CFLAGS) -I$(PWD)/../sources +INCLUDES = -Iinclude $(SDL_CFLAGS) $(FFMPEG_CFLAGS) -I$(PWD)/../sources OPT_FLAGS = -O3 -Ofast -fdata-sections -fdata-sections -fno-common -fno-PIC -flto -marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7ve+simd +-include $(PWD)/rules_libav + TOOLPATH=$(DEVKIT)/usr/bin PREFIX := arm-linux-gnueabihf- CFLAGS := $(DEFINES) $(INCLUDES) $(SDL_CFLAGS) $(OPT_FLAGS) -Wall CXXFLAGS:= $(CFLAGS) -std=gnu++03 -LIBS := -lSDL -lSDL_mixer -lpthread $(SDL_LIBS) +LIBS := -lSDL -lSDL_mixer -lpthread $(SDL_LIBS) $(FFMPEG_LIBS) LIBDIRS := $(DEKVIT)/usr/lib LIBDIRS += $(DEKVIT)/usr/include OUTPUT = ../lgpt-miyoo From b0b8325a847846142a569d8bab14e6cb688db45d Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Fri, 24 Oct 2025 05:20:06 +0000 Subject: [PATCH 12/38] Fix includes for miyoo --- .github/workflows/check.yml | 2 +- projects/Makefile.MIYOO | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index cd7c1478..8236221e 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -370,7 +370,7 @@ jobs: - name: Build Miyoo Mini working-directory: projects - run: | + run: | make PLATFORM=MIYOO - name: Package build diff --git a/projects/Makefile.MIYOO b/projects/Makefile.MIYOO index e36bda73..90f00aef 100644 --- a/projects/Makefile.MIYOO +++ b/projects/Makefile.MIYOO @@ -19,11 +19,21 @@ SYSROOT := $(shell $(CROSS_COMPILE)gcc --print-sysroot) SDL_CFLAGS := $(shell $(SYSROOT)/usr/bin/sdl-config --cflags) SDL_LIBS := $(shell $(SYSROOT)/usr/bin/sdl-config --libs) +FFMPEG_INCL= libavformat \ + libavfilter \ + libavcodec \ + libavutil \ + +LIBAV_PATH := arm-linux-gnueabihf/libc/usr/include +FFMPEG_CFLAGS := -I$(DEVKIT)/$(LIBAV_PATH)/libavformat -I$(DEVKIT)/$(LIBAV_PATH)/libavfilter -I$(DEVKIT)/$(LIBAV_PATH)/libavcodec -I$(SYSROOT)/$(LIBAV_PATH)/libavutil +FFMPEG_LIBS := -lavformat -lavfilter -lavcodec -lavutil + +$(info FFMPEG_CFLAGS: $(FFMPEG_CFLAGS)) +$(info FFMPEG_LIBS: $(FFMPEG_LIBS)) + INCLUDES = -Iinclude $(SDL_CFLAGS) $(FFMPEG_CFLAGS) -I$(PWD)/../sources OPT_FLAGS = -O3 -Ofast -fdata-sections -fdata-sections -fno-common -fno-PIC -flto -marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7ve+simd --include $(PWD)/rules_libav - TOOLPATH=$(DEVKIT)/usr/bin PREFIX := arm-linux-gnueabihf- From a1f451f1174279d7204dcc5687d659c0cd7ee5f2 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Fri, 24 Oct 2025 05:26:52 +0000 Subject: [PATCH 13/38] Fix check.ym --- .github/workflows/check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 8236221e..cd7c1478 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -370,7 +370,7 @@ jobs: - name: Build Miyoo Mini working-directory: projects - run: | + run: | make PLATFORM=MIYOO - name: Package build From 8cfb07fd311a2566e1fc5d184a50e5161654cdaa Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Fri, 24 Oct 2025 07:43:29 +0200 Subject: [PATCH 14/38] Add FFMPEG_LEGACY_API to Makefile.MIYOO --- projects/Makefile.MIYOO | 1 + 1 file changed, 1 insertion(+) diff --git a/projects/Makefile.MIYOO b/projects/Makefile.MIYOO index 90f00aef..6e127b27 100644 --- a/projects/Makefile.MIYOO +++ b/projects/Makefile.MIYOO @@ -7,6 +7,7 @@ DEFINES := \ -DHAVE_STDINT_H \ -D_NDEBUG \ -DFFMPEG_ENABLED \ + -DFFMPEG_LEGACY_API \ -D_NO_JACK_ DEVKIT = /opt/miyoomini-toolchain/ From c8cc287eaed7220ef285b9279eb60917b7ce456b Mon Sep 17 00:00:00 2001 From: djdiskmachine Date: Fri, 24 Oct 2025 19:50:46 +0200 Subject: [PATCH 15/38] vs2008->vs2019 --- .github/workflows/check.yml | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index cd7c1478..c920b44e 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -67,30 +67,11 @@ jobs: run: vcpkg install ffmpeg[avcodec,avformat,avfilter]:x86-windows-static shell: cmd - - name: Download and Extract VCE9 release - run: | - $url = "https://github.com/djdiskmachine/VCE9/releases/download/v1.0.0/Microsoft.Visual.Studio.9.0.zip" - $destination = "C:\Program Files (x86)\" - New-Item -ItemType Directory -Force -Path $destination | Out-Null - Invoke-WebRequest -Uri $url -OutFile "$env:TEMP\VCE9.zip" - Expand-Archive -Path "$env:TEMP\VCE9.zip" -DestinationPath $destination -Force - shell: pwsh - - - name: Install Visual Studio 2008 Express - run: | - Invoke-WebRequest -Uri "http://download.microsoft.com/download/8/B/5/8B5804AD-4990-40D0-A6AA-CE894CBBB3DC/VS2008ExpressENUX1397868.iso" -OutFile "$env:GITHUB_WORKSPACE\VS2008ExpressENUX1397868.iso" - $mountResult = Mount-DiskImage -ImagePath "$env:GITHUB_WORKSPACE\VS2008ExpressENUX1397868.iso" -PassThru - $driveLetter = ($mountResult | Get-Volume).DriveLetter - Write-Host "ISO mounted to drive letter $driveLetter" - $driveLetter = (Get-DiskImage -ImagePath "$env:GITHUB_WORKSPACE\VS2008ExpressENUX1397868.iso" | Get-Volume).DriveLetter - Start-Process -FilePath "${driveLetter}:\VCExpress\setup.exe" -ArgumentList '/q', '/norestart' -Wait - shell: pwsh - - name: Build Solution working-directory: projects run: | - & "C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat" - & "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcpackages\vcbuild.exe" "lgpt.sln" "Release|Win32" + & "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=x86 + & msbuild "lgpt.sln" /p:Configuration=Release /p:Platform=Win32 shell: pwsh - name: Package build From eb02d731de72abfffa3fdd610aa5aafe24534b97 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Fri, 31 Oct 2025 16:05:17 +0000 Subject: [PATCH 16/38] Logging and redundancy removal in LibavProcessor.c Make LibavProcessor errors more obvious Remove unnecessary channel forcing in libav parser Fix typo in makefiles Logging in rules file restore vs2008 build --- .github/workflows/check.yml | 23 +++++++- projects/Makefile.BITTBOY | 2 +- projects/Makefile.MIYOO | 17 +++--- projects/rules_libav | 2 +- sources/Application/FX/LibavProcessor.c | 72 ++++++++++++------------- 5 files changed, 64 insertions(+), 52 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index c920b44e..cd7c1478 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -67,11 +67,30 @@ jobs: run: vcpkg install ffmpeg[avcodec,avformat,avfilter]:x86-windows-static shell: cmd + - name: Download and Extract VCE9 release + run: | + $url = "https://github.com/djdiskmachine/VCE9/releases/download/v1.0.0/Microsoft.Visual.Studio.9.0.zip" + $destination = "C:\Program Files (x86)\" + New-Item -ItemType Directory -Force -Path $destination | Out-Null + Invoke-WebRequest -Uri $url -OutFile "$env:TEMP\VCE9.zip" + Expand-Archive -Path "$env:TEMP\VCE9.zip" -DestinationPath $destination -Force + shell: pwsh + + - name: Install Visual Studio 2008 Express + run: | + Invoke-WebRequest -Uri "http://download.microsoft.com/download/8/B/5/8B5804AD-4990-40D0-A6AA-CE894CBBB3DC/VS2008ExpressENUX1397868.iso" -OutFile "$env:GITHUB_WORKSPACE\VS2008ExpressENUX1397868.iso" + $mountResult = Mount-DiskImage -ImagePath "$env:GITHUB_WORKSPACE\VS2008ExpressENUX1397868.iso" -PassThru + $driveLetter = ($mountResult | Get-Volume).DriveLetter + Write-Host "ISO mounted to drive letter $driveLetter" + $driveLetter = (Get-DiskImage -ImagePath "$env:GITHUB_WORKSPACE\VS2008ExpressENUX1397868.iso" | Get-Volume).DriveLetter + Start-Process -FilePath "${driveLetter}:\VCExpress\setup.exe" -ArgumentList '/q', '/norestart' -Wait + shell: pwsh + - name: Build Solution working-directory: projects run: | - & "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=x86 - & msbuild "lgpt.sln" /p:Configuration=Release /p:Platform=Win32 + & "C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat" + & "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcpackages\vcbuild.exe" "lgpt.sln" "Release|Win32" shell: pwsh - name: Package build diff --git a/projects/Makefile.BITTBOY b/projects/Makefile.BITTBOY index 165fc21f..067ce5fc 100644 --- a/projects/Makefile.BITTBOY +++ b/projects/Makefile.BITTBOY @@ -32,7 +32,7 @@ INCLUDES = -I$(PWD)/../sources -Iinclude $(SDL_CFLAGS) $(FFMPEG_CFLAGS) CFLAGS := $(DEFINES) $(INCLUDES) $(OPT_FLAGS) $(SDL_CFLAGS) -Wall -DRS97 CXXFLAGS:= $(CFLAGS) -std=gnu++03 LIBS := $(SDL_LIBS) -lSDL -lSDL_mixer -lasound -lpthread $(FFMPEG_LIBS) -LIBDIRS := $(DEKVIT)/usr/lib +LIBDIRS := $(SYSROOT)/usr/lib OUTPUT = ../lgpt-bittboy EXTENSION:= elf diff --git a/projects/Makefile.MIYOO b/projects/Makefile.MIYOO index 6e127b27..9567f158 100644 --- a/projects/Makefile.MIYOO +++ b/projects/Makefile.MIYOO @@ -7,7 +7,7 @@ DEFINES := \ -DHAVE_STDINT_H \ -D_NDEBUG \ -DFFMPEG_ENABLED \ - -DFFMPEG_LEGACY_API \ + -DFFMPEG_LEGACY_API \ -D_NO_JACK_ DEVKIT = /opt/miyoomini-toolchain/ @@ -20,13 +20,12 @@ SYSROOT := $(shell $(CROSS_COMPILE)gcc --print-sysroot) SDL_CFLAGS := $(shell $(SYSROOT)/usr/bin/sdl-config --cflags) SDL_LIBS := $(shell $(SYSROOT)/usr/bin/sdl-config --libs) -FFMPEG_INCL= libavformat \ - libavfilter \ - libavcodec \ - libavutil \ - LIBAV_PATH := arm-linux-gnueabihf/libc/usr/include -FFMPEG_CFLAGS := -I$(DEVKIT)/$(LIBAV_PATH)/libavformat -I$(DEVKIT)/$(LIBAV_PATH)/libavfilter -I$(DEVKIT)/$(LIBAV_PATH)/libavcodec -I$(SYSROOT)/$(LIBAV_PATH)/libavutil +FFMPEG_CFLAGS := -I$(DEVKIT)/$(LIBAV_PATH)/libavformat \ + -I$(DEVKIT)/$(LIBAV_PATH)/libavfilter \ + -I$(DEVKIT)/$(LIBAV_PATH)/libavcodec \ + -I$(DEVKIT)/$(LIBAV_PATH)/libavutil \ + FFMPEG_LIBS := -lavformat -lavfilter -lavcodec -lavutil $(info FFMPEG_CFLAGS: $(FFMPEG_CFLAGS)) @@ -41,8 +40,8 @@ PREFIX := arm-linux-gnueabihf- CFLAGS := $(DEFINES) $(INCLUDES) $(SDL_CFLAGS) $(OPT_FLAGS) -Wall CXXFLAGS:= $(CFLAGS) -std=gnu++03 LIBS := -lSDL -lSDL_mixer -lpthread $(SDL_LIBS) $(FFMPEG_LIBS) -LIBDIRS := $(DEKVIT)/usr/lib -LIBDIRS += $(DEKVIT)/usr/include +LIBDIRS := $(DEVKIT)/usr/lib +LIBDIRS += $(DEVKIT)/usr/include OUTPUT = ../lgpt-miyoo EXTENSION:= elf diff --git a/projects/rules_libav b/projects/rules_libav index e8876171..b96ad7f7 100644 --- a/projects/rules_libav +++ b/projects/rules_libav @@ -3,7 +3,7 @@ FFMPEG_INCL= libavformat \ libavcodec \ libavutil \ -# Use SYSROOT for cross-compilation, fallback to system pkg-config for native builds +$(info SYSROOT: $(SYSROOT)) ifdef SYSROOT FFMPEG_CFLAGS := $(shell $(DEVKIT)/bin/pkg-config --cflags $(FFMPEG_INCL)) FFMPEG_LIBS := $(shell $(DEVKIT)/bin/pkg-config --libs $(FFMPEG_INCL)) diff --git a/sources/Application/FX/LibavProcessor.c b/sources/Application/FX/LibavProcessor.c index 8f0de6d2..44ca575e 100644 --- a/sources/Application/FX/LibavProcessor.c +++ b/sources/Application/FX/LibavProcessor.c @@ -30,19 +30,19 @@ static int open_input_file(const char *filename) int ret; if ((ret = avformat_open_input(&ifmt_ctx, filename, NULL, NULL)) < 0) { - av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Cannot open input file\n"); return ret; } if ((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0) { - av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Cannot find stream information\n"); return ret; } /* select the audio stream */ ret = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Cannot find an audio stream in the input file\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Cannot find an audio stream in the input file\n"); return ret; } @@ -56,7 +56,7 @@ static int open_input_file(const char *filename) /* init the audio decoder */ if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) { - av_log(NULL, AV_LOG_ERROR, "Cannot open audio decoder\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Cannot open audio decoder\n"); return ret; } @@ -83,19 +83,19 @@ static int open_ir_file(const char *filename) int ret; if ((ret = avformat_open_input(&ir_fmt_ctx, filename, NULL, NULL)) < 0) { - av_log(NULL, AV_LOG_ERROR, "Cannot open IR file\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Cannot open IR file\n"); return ret; } if ((ret = avformat_find_stream_info(ir_fmt_ctx, NULL)) < 0) { - av_log(NULL, AV_LOG_ERROR, "Cannot find stream information in IR file\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Cannot find stream information in IR file\n"); return ret; } /* select the audio stream */ ret = av_find_best_stream(ir_fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Cannot find an audio stream in the IR file\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Cannot find an audio stream in the IR file\n"); return ret; } @@ -109,7 +109,7 @@ static int open_ir_file(const char *filename) /* init the audio decoder */ if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) { - av_log(NULL, AV_LOG_ERROR, "Cannot open IR audio decoder\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Cannot open IR audio decoder\n"); return ret; } @@ -137,14 +137,14 @@ static int open_output_file(const char *filename) avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, filename); if (!ofmt_ctx) { - av_log(NULL, AV_LOG_ERROR, "Could not create output context\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Could not create output context\n"); return AVERROR_UNKNOWN; } in_stream = ifmt_ctx->streams[0]; out_stream = avformat_new_stream(ofmt_ctx, NULL); if (!out_stream) { - av_log(NULL, AV_LOG_ERROR, "Failed allocating output stream\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Failed allocating output stream\n"); return AVERROR_UNKNOWN; } @@ -197,12 +197,12 @@ static int open_output_file(const char *filename) /* Third parameter can be used to pass settings to encoder */ ret = avcodec_open2(enc_ctx, encoder, NULL); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Cannot open video encoder for stream\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Cannot open video encoder for stream\n"); return ret; } ret = avcodec_parameters_from_context(out_stream->codecpar, enc_ctx); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Failed to copy encoder parameters to output stream\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Failed to copy encoder parameters to output stream\n"); return ret; } @@ -214,7 +214,7 @@ static int open_output_file(const char *filename) if (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) { ret = avio_open(&ofmt_ctx->pb, filename, AVIO_FLAG_WRITE); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Could not open output file '%s'", filename); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Could not open output file '%s'", filename); return ret; } } @@ -222,7 +222,7 @@ static int open_output_file(const char *filename) /* init muxer, write output file header */ ret = avformat_write_header(ofmt_ctx, NULL); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Error occurred when opening output file\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Error occurred when opening output file\n"); return ret; } @@ -272,14 +272,14 @@ static int init_filters(int ir_wet, int ir_pad) /* buffer audio source: the decoded frames from the decoder will be inserted here. */ abuffer = avfilter_get_by_name("abuffer"); if (!abuffer) { - av_log(NULL, AV_LOG_ERROR, "Could not find the abuffer filter.\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Could not find the abuffer filter.\n"); ret = AVERROR_FILTER_NOT_FOUND; goto end; } buffersrc_ctx = avfilter_graph_alloc_filter(filter_graph, abuffer, "in"); if (!buffersrc_ctx) { - av_log(NULL, AV_LOG_ERROR, "Could not allocate the abuffer instance.\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Could not allocate the abuffer instance.\n"); ret = AVERROR(ENOMEM); goto end; } @@ -317,14 +317,14 @@ static int init_filters(int ir_wet, int ir_pad) ch_layout_str); ret = avfilter_init_str(buffersrc_ctx, args); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Could not initialize the abuffer filter.\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Could not initialize the abuffer filter.\n"); goto end; } /* buffer audio source for IR: the decoded IR frames will be inserted here. */ ir_buffersrc_ctx = avfilter_graph_alloc_filter(filter_graph, abuffer, "ir_in"); if (!ir_buffersrc_ctx) { - av_log(NULL, AV_LOG_ERROR, "Could not allocate the IR abuffer instance.\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Could not allocate the IR abuffer instance.\n"); ret = AVERROR(ENOMEM); goto end; } @@ -361,21 +361,21 @@ static int init_filters(int ir_wet, int ir_pad) ir_ch_layout_str); ret = avfilter_init_str(ir_buffersrc_ctx, ir_args); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Could not initialize the IR abuffer filter.\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Could not initialize the IR abuffer filter.\n"); goto end; } /* buffer audio sink: to terminate the filter chain. */ abuffersink = avfilter_get_by_name("abuffersink"); if (!abuffersink) { - av_log(NULL, AV_LOG_ERROR, "Could not find the abuffersink filter.\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Could not find the abuffersink filter.\n"); ret = AVERROR_FILTER_NOT_FOUND; goto end; } buffersink_ctx = avfilter_graph_alloc_filter(filter_graph, abuffersink, "out"); if (!buffersink_ctx) { - av_log(NULL, AV_LOG_ERROR, "Could not allocate the abuffersink instance.\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Could not allocate the abuffersink instance.\n"); ret = AVERROR(ENOMEM); goto end; } @@ -384,20 +384,14 @@ static int init_filters(int ir_wet, int ir_pad) static const enum AVSampleFormat out_sample_fmts[] = { AV_SAMPLE_FMT_S16, -1 }; ret = av_opt_set_int_list(buffersink_ctx, "sample_fmts", out_sample_fmts, -1, AV_OPT_SEARCH_CHILDREN); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Cannot set output sample format\n"); - goto end; - } - - ret = av_opt_set(buffersink_ctx, "ch_layouts", target_layout, AV_OPT_SEARCH_CHILDREN); - if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layout\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Cannot set output sample format\n"); goto end; } /* This filter takes no options. */ ret = avfilter_init_str(buffersink_ctx, NULL); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Could not initialize the abuffersink instance.\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Could not initialize the abuffersink instance.\n"); goto end; } @@ -514,7 +508,7 @@ static int filter_encode_write_frame(AVFrame *frame, AVFrame *ir_frame, unsigned if (frame) { ret = av_buffersrc_add_frame_flags(buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Error while feeding the input filtergraph\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Error while feeding the input filtergraph\n"); return ret; } } @@ -522,7 +516,7 @@ static int filter_encode_write_frame(AVFrame *frame, AVFrame *ir_frame, unsigned if (ir_frame) { ret = av_buffersrc_add_frame_flags(ir_buffersrc_ctx, ir_frame, AV_BUFFERSRC_FLAG_KEEP_REF); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Error while feeding the IR filtergraph\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Error while feeding the IR filtergraph\n"); return ret; } } @@ -623,7 +617,7 @@ int encode(const char *fi, const char *ir, const char *fo, int irWet, int irPad) ret = av_buffersrc_add_frame_flags(ir_buffersrc_ctx, ir_frame, AV_BUFFERSRC_FLAG_KEEP_REF); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Error while feeding the IR filtergraph\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Error while feeding the IR filtergraph\n"); goto end; } ir_loaded = 1; @@ -635,7 +629,7 @@ int encode(const char *fi, const char *ir, const char *fo, int irWet, int irPad) /* Signal end of IR stream */ ret = av_buffersrc_add_frame_flags(ir_buffersrc_ctx, NULL, 0); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Error closing IR filtergraph\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Error closing IR filtergraph\n"); goto end; } @@ -659,7 +653,7 @@ int encode(const char *fi, const char *ir, const char *fo, int irWet, int irPad) ret = av_buffersrc_add_frame_flags(buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Error while feeding the input filtergraph\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Error while feeding the input filtergraph\n"); goto end; } /* Pull filtered frames immediately */ @@ -692,21 +686,21 @@ int encode(const char *fi, const char *ir, const char *fo, int irWet, int irPad) /* flush the filter graph by sending EOF to input sources */ ret = av_buffersrc_add_frame_flags(buffersrc_ctx, NULL, 0); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Error while closing the input filtergraph\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Error while closing the input filtergraph\n"); goto end; } /* Pull any remaining frames from the filter graph */ ret = filter_encode_write_frame(NULL, NULL, 0); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Flushing filter failed\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Flushing filter failed\n"); goto end; } /* flush the encoder */ ret = avcodec_send_frame(enc_ctx, NULL); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Error sending NULL frame to encoder\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Error sending NULL frame to encoder\n"); goto end; } @@ -718,7 +712,7 @@ int encode(const char *fi, const char *ir, const char *fo, int irWet, int irPad) break; } else if (ret < 0) { av_packet_free(&enc_pkt); - av_log(NULL, AV_LOG_ERROR, "Error during encoder flush\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Error during encoder flush\n"); goto end; } @@ -727,7 +721,7 @@ int encode(const char *fi, const char *ir, const char *fo, int irWet, int irPad) ret = av_interleaved_write_frame(ofmt_ctx, enc_pkt); av_packet_free(&enc_pkt); if (ret < 0) { - av_log(NULL, AV_LOG_ERROR, "Error writing final packet\n"); + av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Error writing final packet\n"); goto end; } } From 2935da463968a894bc9df9250bd03f5f83afb42b Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Tue, 9 Dec 2025 19:48:03 +0100 Subject: [PATCH 17/38] Add contributing guideline --- CONTRIBUTING.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..bd945b08 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,38 @@ +# Contributing + +Thank you for considering contributing to this project! + +## Branch & Merge Strategy + +- **master** is the integration branch. It may contain unstable/experimental features. +- **Pull Requests** should target `master` +- **Releases** follow a release candidate workflow: + - Release candidates: `1.2.0-bacon0`, `1.2.0-bacon2`, etc. + - Stable releases: `v1.2.0` (after testing period) +- **Users should only use tagged releases**, build from master at your own peril, may contain half-done pork + +## Pull Request Requirements + +Before submitting a PR, ensure: + +- [ ] **Version bumped** in `sources/Application/Model/Project.h`: + - Bump BUILD_COUNT (`#define BUILD_COUNT "3-bacon3"`) for the most part + +- [ ] **Documentation updated**: + - Update `docs/wiki/What-is-LittlePiggyTracker.md` reflecting your changes + - Update CHANGELOG + +- [ ] **Clean commit history**: + - As changes are merged via squash commit, please provide a clear and descriptive commit message + +- [ ] **Testing**: + - Describe how you tested your changes in the PR description + - Include relevant test results + +## Merge Process + +Maintainer will review and merge approved PRs using **squash and merge**, combining your commits with a detailed merge message. + +## Questions? + +Open an issue or reach out to maintainers. From 119871d71577b3e09342608073a26cee9f01a5cd Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Tue, 9 Dec 2025 19:48:31 +0100 Subject: [PATCH 18/38] Revise pull request template Updated pull request template to improve clarity and add new checklist items. --- .github/pull_request_template.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index e308829b..aad9c03b 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -8,26 +8,28 @@ All PR:s are run through line-by-line clang-format and builds for all supported clang-format can be applied locally on commit by installing pre-commit from repo root: cp pre-commit .git/hooks/ -Fixes # (issue) - +In section below, delete any option that isn't relevant. ## Type of change - -Please delete option that isn't relevant. +- Fixes #(issue number) +- Feature - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) # How Has This Been Tested? -Please describe the tests that you ran to verify your changes. Provide instructions on how to reproduce. +Please describe the tests procedure by which you verified your changes. +Provide instructions on how to reproduce. **Test Configuration**: * Hardware: -* OS version: +* Test steps: # Checklist: - [ ] I have performed a self-review of my code - [ ] I have commented particularly in hard-to-understand areas -- [ ] I have updated documentation regarding my changes -- [ ] My changes generate no new warnings +- [ ] I have updated CHANGELOG +- [ ] I have updated docs/wiki/What-is-LittlePiggyTracker.md reflecting my changes +- [ ] I have version bumped in `sources/Application/Model/Project.h` +- [ ] My changes generate no new warnings (build without your change then apply your change to check this) From 9bc7849fe3fb848c87d29129813b4b6ad2d5b328 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Tue, 9 Dec 2025 19:50:11 +0100 Subject: [PATCH 19/38] Revise issue template --- .github/ISSUE_TEMPLATE/issue-template.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/issue-template.md b/.github/ISSUE_TEMPLATE/issue-template.md index 73ec7631..7e6a909c 100644 --- a/.github/ISSUE_TEMPLATE/issue-template.md +++ b/.github/ISSUE_TEMPLATE/issue-template.md @@ -1,8 +1,7 @@ --- name: Issue template about: Create issue from template -title: "[BUG] - short description of your issue" -labels: bug +title: "[BUG/FEATURE/OTHER] - short description of your issue" assignees: '' --- @@ -10,7 +9,7 @@ assignees: '' Thank you for helping to improve Little Piggy Tracker by making this report. #### All feature requests made here will be treated as a request from the reporter to implement said feature. -When creating issues please provide the following items: +When creating issues please provide the following items where applicable: - Attach or paste contents of **lgpt.log** of when the issue occurred - Declare **platform configuration** such as desktop/console, OS version and audio configuration if applicable From 042c0b3e51b984a589da3de38e01a101434326c4 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Thu, 11 Dec 2025 07:57:30 +0100 Subject: [PATCH 20/38] Fix packaging for MacOS (#209) * Fix packaging for MacOS Moving folders named pattern*/ is apparently illegal in macOs 15 * clang-format fixed It broke for some reason. Got rid of an unnecessary fetch while at it * Disable shallow clone Switch to master * Fix grep exit with 0 on no files * Bump and format Project.h * Change how macos downloads to avoid the globbing issue --- .github/workflows/build.yml | 4 +-- .github/workflows/check.yml | 14 ++++---- sources/Application/Model/Project.h | 50 ++++++++++++++--------------- 3 files changed, 33 insertions(+), 35 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fb66de3e..ff6e5422 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -460,11 +460,11 @@ jobs: shell: bash run: | TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + cd resources/packaging curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip - mv lgpt-resources-${TAG}/*/ ./resources/packaging rm -rf lgpt-resources* - ./resources/packaging/lgpt_package.sh + cd - && ./resources/packaging/lgpt_package.sh - name: Extract Git tag name id: extract_tag diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 0a8a06c8..d9485cf4 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -9,14 +9,12 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 - - - name: Fetch all branches - run: git fetch + with: + fetch-depth: 0 - name: Check formatting run: | - git fetch origin master:master - CHANGED_FILES=$(git diff --name-only master --diff-filter=ACM | grep -iE '\.(cpp|h|c|hpp)$') + CHANGED_FILES=$(git diff --name-only origin/master...HEAD --diff-filter=ACM | grep -iE '\.(cpp|h|c|hpp)$' || true) if [ -z "$CHANGED_FILES" ]; then echo "No C/C++ files changed." @@ -28,7 +26,7 @@ jobs: # Run clang-format on the changed lines of each staged file for FILE in $CHANGED_FILES; do # Get the changed lines in the file - CHANGED_LINES=$(git diff -U0 master -- $FILE | grep -E '^@@' | awk '{print $3}' | cut -d',' -f1) + CHANGED_LINES=$(git diff -U0 origin/master -- $FILE | grep -E '^@@' | awk '{print $3}' | cut -d',' -f1) # Format each changed line in the file for LINE in $CHANGED_LINES; do @@ -450,11 +448,11 @@ jobs: shell: bash run: | TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + cd resources/packaging curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip - mv lgpt-resources-${TAG}/*/ ./resources/packaging rm -rf lgpt-resources* - ./resources/packaging/lgpt_package.sh + cd - && ./resources/packaging/lgpt_package.sh - name: Upload artifact uses: actions/upload-artifact@v4 diff --git a/sources/Application/Model/Project.h b/sources/Application/Model/Project.h index f4bb4410..f75454d6 100644 --- a/sources/Application/Model/Project.h +++ b/sources/Application/Model/Project.h @@ -20,40 +20,40 @@ #define PROJECT_NUMBER "1" #define PROJECT_RELEASE "5" -#define BUILD_COUNT "0-bacon3" +#define BUILD_COUNT "0" #define MAX_TAP 3 class Project: public Persistent,public VariableContainer,I_Observer { public: - Project() ; - ~Project() ; - void Purge() ; - void PurgeInstruments(bool removeFromDisk) ; + Project(); + ~Project(); + void Purge(); + void PurgeInstruments(bool removeFromDisk); - Song *song_ ; - - int GetMasterVolume() ; - bool Wrap() ; - void OnTempoTap(); - void NudgeTempo(int value) ; - int GetScale(); - int GetTempo() ; // Takes nudging into account - int GetTranspose() ; - int GetSoftclip(); - int GetSoftclipGain(); - int GetPregain(); + Song *song_; - void Trigger(); + int GetMasterVolume(); + bool Wrap(); + void OnTempoTap(); + void NudgeTempo(int value); + int GetScale(); + int GetTempo(); // Takes nudging into account + int GetTranspose(); + int GetSoftclip(); + int GetSoftclipGain(); + int GetPregain(); - // I_Observer - virtual void Update(Observable &o,I_ObservableData *d); - - InstrumentBank* GetInstrumentBank() ; - virtual void SaveContent(TiXmlNode *node) ; - virtual void RestoreContent(TiXmlElement *element); + void Trigger(); - void LoadFirstGen(const char *root) ; + // I_Observer + virtual void Update(Observable &o, I_ObservableData *d); + + InstrumentBank *GetInstrumentBank(); + virtual void SaveContent(TiXmlNode *node); + virtual void RestoreContent(TiXmlElement *element); + + void LoadFirstGen(const char *root); protected: void buildMidiDeviceList() ; From ec45e8bd9e72fca62f6d530b785af807d4a036f3 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Mon, 15 Dec 2025 22:20:52 +0100 Subject: [PATCH 21/38] CI packaging and building big refactor (#210) Fix the many errors that happened when moving to MacOS 15 Use find to locate resource folders Authenticate latest tag fetching Use jq instead of grep / head / cut extract version number Move and rename Garlicplus shell scripts to add them to build --- .github/workflows/build.yml | 39 +++++++++++-------- .github/workflows/check.yml | 39 +++++++++++-------- ...Tracker.sh => LittleGPTracker-garlicos.sh} | 0 ...leGPTracker.sh => LittleGPTracker-muos.sh} | 0 projects/resources/packaging/lgpt_package.sh | 4 +- 5 files changed, 49 insertions(+), 33 deletions(-) rename projects/resources/GARLICPLUS/{garlicos/LittleGPTracker.sh => LittleGPTracker-garlicos.sh} (100%) rename projects/resources/GARLICPLUS/{muos/LittleGPTracker.sh => LittleGPTracker-muos.sh} (100%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ff6e5422..8e02e002 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -47,7 +47,7 @@ jobs: shell: bash working-directory: projects run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + TAG=$(curl "https://api.github.com/repos/djdiskmachine/lgpt-resources/tags" | jq -r '.[0].name') curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip mv lgpt-resources-${TAG}/*/ ./resources/packaging @@ -86,7 +86,7 @@ jobs: - name: Package build working-directory: projects run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + TAG=$(curl "https://api.github.com/repos/djdiskmachine/lgpt-resources/tags" | jq -r '.[0].name') curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip mv lgpt-resources-${TAG}/*/ ./resources/packaging @@ -125,7 +125,7 @@ jobs: - name: Package build working-directory: projects run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + TAG=$(curl "https://api.github.com/repos/djdiskmachine/lgpt-resources/tags" | jq -r '.[0].name') curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip mv lgpt-resources-${TAG}/*/ ./resources/packaging @@ -163,7 +163,7 @@ jobs: - name: Package build working-directory: projects run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + TAG=$(curl "https://api.github.com/repos/djdiskmachine/lgpt-resources/tags" | jq -r '.[0].name') curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip mv lgpt-resources-${TAG}/*/ ./resources/packaging @@ -208,7 +208,7 @@ jobs: - name: Package build working-directory: projects run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + TAG=$(curl "https://api.github.com/repos/djdiskmachine/lgpt-resources/tags" | jq -r '.[0].name') curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip mv lgpt-resources-${TAG}/*/ ./resources/packaging @@ -248,7 +248,7 @@ jobs: - name: Package build working-directory: projects run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + TAG=$(curl "https://api.github.com/repos/djdiskmachine/lgpt-resources/tags" | jq -r '.[0].name') curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip mv lgpt-resources-${TAG}/*/ ./resources/packaging @@ -288,7 +288,7 @@ jobs: - name: Package build working-directory: projects run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + TAG=$(curl "https://api.github.com/repos/djdiskmachine/lgpt-resources/tags" | jq -r '.[0].name') curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip mv lgpt-resources-${TAG}/*/ ./resources/packaging @@ -336,7 +336,7 @@ jobs: - name: Package build working-directory: ./workspace/projects run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + TAG=$(curl "https://api.github.com/repos/djdiskmachine/lgpt-resources/tags" | jq -r '.[0].name') curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip mv lgpt-resources-${TAG}/*/ ./resources/packaging @@ -377,7 +377,7 @@ jobs: - name: Package build working-directory: projects run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + TAG=$(curl "https://api.github.com/repos/djdiskmachine/lgpt-resources/tags" | jq -r '.[0].name') curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip mv lgpt-resources-${TAG}/*/ ./resources/packaging @@ -418,7 +418,7 @@ jobs: - name: Package build working-directory: projects run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + TAG=$(curl "https://api.github.com/repos/djdiskmachine/lgpt-resources/tags" | jq -r '.[0].name') curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip mv lgpt-resources-${TAG}/*/ ./resources/packaging @@ -456,15 +456,22 @@ jobs: cp -R bin/LittleGPTracker.app projects/ - name: Package build - working-directory: projects + working-directory: projects/resources/packaging shell: bash + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) - cd resources/packaging - curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip + TAG=$(curl -fsSL \ + -H "Authorization: Bearer ${GITHUB_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + https://api.github.com/repos/djdiskmachine/lgpt-resources/tags) + echo TAG==$TAG + TAG=$(echo $TAG | jq -r '.[0].name') + echo TAG==$TAG + curl -fL -o lgpt-resources.zip \ + https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip - rm -rf lgpt-resources* - cd - && ./resources/packaging/lgpt_package.sh + ./lgpt_package.sh - name: Extract Git tag name id: extract_tag diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index d9485cf4..e4ad0317 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -91,7 +91,7 @@ jobs: shell: bash working-directory: projects run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + TAG=$(curl "https://api.github.com/repos/djdiskmachine/lgpt-resources/tags" | jq -r '.[0].name') curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip mv lgpt-resources-${TAG}/*/ ./resources/packaging @@ -124,7 +124,7 @@ jobs: - name: Package build working-directory: projects run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + TAG=$(curl "https://api.github.com/repos/djdiskmachine/lgpt-resources/tags" | jq -r '.[0].name') curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip mv lgpt-resources-${TAG}/*/ ./resources/packaging @@ -157,7 +157,7 @@ jobs: - name: Package build working-directory: projects run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + TAG=$(curl "https://api.github.com/repos/djdiskmachine/lgpt-resources/tags" | jq -r '.[0].name') curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip mv lgpt-resources-${TAG}/*/ ./resources/packaging @@ -196,7 +196,7 @@ jobs: - name: Package build working-directory: projects run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + TAG=$(curl "https://api.github.com/repos/djdiskmachine/lgpt-resources/tags" | jq -r '.[0].name') curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip mv lgpt-resources-${TAG}/*/ ./resources/packaging @@ -230,7 +230,7 @@ jobs: - name: Package build working-directory: projects run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + TAG=$(curl "https://api.github.com/repos/djdiskmachine/lgpt-resources/tags" | jq -r '.[0].name') curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip mv lgpt-resources-${TAG}/*/ ./resources/packaging @@ -272,7 +272,7 @@ jobs: - name: Package build working-directory: ./workspace/projects run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + TAG=$(curl "https://api.github.com/repos/djdiskmachine/lgpt-resources/tags" | jq -r '.[0].name') curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip mv lgpt-resources-${TAG}/*/ ./resources/packaging @@ -307,7 +307,7 @@ jobs: - name: Package build working-directory: projects run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + TAG=$(curl "https://api.github.com/repos/djdiskmachine/lgpt-resources/tags" | jq -r '.[0].name') curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip mv lgpt-resources-${TAG}/*/ ./resources/packaging @@ -342,7 +342,7 @@ jobs: - name: Package build working-directory: projects run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + TAG=$(curl "https://api.github.com/repos/djdiskmachine/lgpt-resources/tags" | jq -r '.[0].name') curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip mv lgpt-resources-${TAG}/*/ ./resources/packaging @@ -378,7 +378,7 @@ jobs: - name: Package build working-directory: projects run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + TAG=$(curl "https://api.github.com/repos/djdiskmachine/lgpt-resources/tags" | jq -r '.[0].name') curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip mv lgpt-resources-${TAG}/*/ ./resources/packaging @@ -412,7 +412,7 @@ jobs: - name: Package build working-directory: projects run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) + TAG=$(curl "https://api.github.com/repos/djdiskmachine/lgpt-resources/tags" | jq -r '.[0].name') curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip mv lgpt-resources-${TAG}/*/ ./resources/packaging @@ -444,15 +444,22 @@ jobs: cp -R bin/LittleGPTracker.app projects/ - name: Package build - working-directory: projects + working-directory: projects/resources/packaging shell: bash + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4) - cd resources/packaging - curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip + TAG=$(curl -fsSL \ + -H "Authorization: Bearer ${GITHUB_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + https://api.github.com/repos/djdiskmachine/lgpt-resources/tags) + echo TAG==$TAG + TAG=$(echo $TAG | jq -r '.[0].name') + echo TAG==$TAG + curl -fL -o lgpt-resources.zip \ + https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip unzip lgpt-resources.zip - rm -rf lgpt-resources* - cd - && ./resources/packaging/lgpt_package.sh + ./lgpt_package.sh - name: Upload artifact uses: actions/upload-artifact@v4 diff --git a/projects/resources/GARLICPLUS/garlicos/LittleGPTracker.sh b/projects/resources/GARLICPLUS/LittleGPTracker-garlicos.sh similarity index 100% rename from projects/resources/GARLICPLUS/garlicos/LittleGPTracker.sh rename to projects/resources/GARLICPLUS/LittleGPTracker-garlicos.sh diff --git a/projects/resources/GARLICPLUS/muos/LittleGPTracker.sh b/projects/resources/GARLICPLUS/LittleGPTracker-muos.sh similarity index 100% rename from projects/resources/GARLICPLUS/muos/LittleGPTracker.sh rename to projects/resources/GARLICPLUS/LittleGPTracker-muos.sh diff --git a/projects/resources/packaging/lgpt_package.sh b/projects/resources/packaging/lgpt_package.sh index cedd7b1d..f154c116 100755 --- a/projects/resources/packaging/lgpt_package.sh +++ b/projects/resources/packaging/lgpt_package.sh @@ -32,7 +32,9 @@ collect_resources() { #1PLATFORM #2lgpt.*-exe zip -9 $PACKAGE bin/* && rm -r bin/ fi cd ./resources/packaging - CONTENTS="../../../README.md ../../../CHANGELOG ../../../LICENSE samplelib/ lgpt_BETA/" + CONTENTS="../../../README.md ../../../CHANGELOG ../../../LICENSE" + CONTENTS+=" $(find . -name "samplelib" -type d)" + CONTENTS+=" $(find . -name "lgpt_*" -type d)" zip -9 -r ../../$PACKAGE $CONTENTS CONTENTS="../../../docs/wiki/What-is-LittlePiggyTracker.md" CONTENTS+=" ../../../docs/wiki/config_xml.md" From e0a4ef720a5771f49660f3d772357330d404f89e Mon Sep 17 00:00:00 2001 From: Ben Clegg-Li Date: Sun, 21 Dec 2025 21:53:42 +0000 Subject: [PATCH 22/38] Add 64 bit soundfont support (#211) * task: add ADDR type * task: use ADDR for soundfont samples * fix: load bank using correct type * fix: use ADDR for loading riff * task: run clang-format * fix: win32 build * task: update CHANGELOG * task: bump version in project.h * task: update README * task: change version to 1.6.0-bacon0 --------- Co-authored-by: Ben Clegg-Li --- CHANGELOG | 36 ++-- README.md | 8 +- .../Instruments/SoundFontManager.cpp | 15 +- sources/Application/Model/Project.h | 7 +- sources/Externals/Soundfont/DATATYPE.H | 156 ++++++++++-------- sources/Externals/Soundfont/HYDRA.H | 8 +- sources/Externals/Soundfont/RIFF.CPP | 59 ++++--- sources/Externals/Soundfont/RIFF.H | 2 +- sources/Externals/Soundfont/SFDATA.H | 8 +- sources/Externals/Soundfont/SFNAV.CPP | 17 +- sources/Externals/Soundfont/SFREADER.CPP | 58 ++++--- 11 files changed, 203 insertions(+), 171 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 2be5d1f0..9f625a3b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,11 @@ +1.6.0-bacon0 + Contributions: + drbscl + Add 64 bit soundfont support (#211) + + Fixes: + Add 64 bit soundfont support (#211) + 1.5.0-bacon3 Contributions: purelygrey @@ -15,9 +23,9 @@ * instrumentation by clsource simotek - Add color options for Border Play and Mute (#143) + Add color options for Border Play and Mute (#143) * Adds different color for the > play and _ mute indicators - Fix rg35xx mapping (#139) + Fix rg35xx mapping (#139) * rshoulder and lshoulder were the wrong way kompadre @@ -40,7 +48,7 @@ Nudge functionality (#130) * In Project view, select tempo and hold B+LEFT/RIGHT to nudge slower/faster * In Song view, pressing LT+LEFT/RIGHT will do the same - + Printable fx in InstrumentView (#155) * Uses ffmpeg to print reverb to currently selected sample * New sample with fx is created and assigned to the current instrument @@ -63,7 +71,7 @@ Set songview b jumping length to 16 rows in correspondence with LSDJ and M8 Scales no longer affect instrument numbers ([djdiskmachine/LittleGPTracker#172](https://github.com/djdiskmachine/LittleGPTracker/issues/172)) Bug in Variable:SetString [djdiskmachine/LittleGPTracker#169](https://github.com/djdiskmachine/LittleGPTracker/issues/169) - + Issue in deep clone (#135) Was possible to accidentally deep clone position into another position @@ -108,27 +116,27 @@ Fixes: RG35XX no longer segfaults on boot USB MIDI disabled due to missing OS dependencies - + 1.4.0 Adds: Automated build for bittboy, Win32, PSP, Miyoo, Deb32, RG35XX Shoutout to xquader for the initial RG35XX port (https://boosty.to/xquader) License changed from CC-BY-SA-NC to GPL-3 - * MVEL cmd + * MVEL cmd Set step velocity for MIDI instruments https://github.com/democloid/picoTracker/pull/163 - + Author: @maks@fluttercommunity.social Co-authored-by: djdiskmachine * Config option to set major beat color in phrase screen Author: koisignal - + * Deep clone Clones selected chain and the phrases within - + Author: koisignal Co-authored-by: djdiskmachine @@ -190,29 +198,29 @@ 1.3o-beta-1 Pingpong loop now stable - Courtesy of djdiskmachine + Courtesy of djdiskmachine Add ability to change font USAGE: ./mkfont.py FONT_BMP [OUTPUT_FILE] FONT_BMP must be a black/white (#000000, #FFFFFF) 128x64px bmp if OUTPUT_FILE is omitted, will print to stdout - Courtesy of subnixr + Courtesy of subnixr Adds Miyoo mini build Courtesy of Nine-H Changes filter attenuation to attenuation - Adjust volume post scream filter + Adjust volume post scream filter https://github.com/Mdashdotdashn/LittleGPTracker/issues/22 Missing wiki content dumped to repo - Courtesy of Peter Swimm + Courtesy of Peter Swimm 1.3o-alpha-5 Adds native SteamOS build Adds Bittboy/RS97/RG350 builds Merge of Gameblaba, CalebCDE and RafaVicos work - Shoutouts! + Shoutouts! 1.3o-alpha-4 Adds Save As menu item - save a copy of your project with a new name Courtesy of yoyz (https://github.com/yoyz), biggup! diff --git a/README.md b/README.md index ce6d7ee7..a53b7ca7 100644 --- a/README.md +++ b/README.md @@ -44,9 +44,9 @@ Recommended reading to get you started: |-------------|---------------|--------------|------------|--------------------------------------| | PSP | NO | NO | YES | [See notes](projects/resources/PSP/INSTALL_HOW_TO.txt) | | DEB | YES | YES | YES | | -| X64 | YES | YES | NO | | +| X64 | YES | YES | MAYBE | | | X86 | YES | YES | YES | | -| STEAM | YES | YES | NO | | +| STEAM | YES | YES | MAYBE | | | MIYOO | NO | NO | YES | Port by [Nine-H](https://ninethehacker.xyz) | | W32 | YES | YES | YES | Built in VS2008 with love | | RASPI | YES | YES | YES | Versatile platform | @@ -55,10 +55,8 @@ Recommended reading to get you started: | GARLIC | MAYBE | NO | YES | Port by [Simotek](http://simotek.net)| | GARLICPLUS | MAYBE | NO | YES | Port by [Simotek](http://simotek.net)| | RG35XXPLUS | MAYBE | NO | YES | Port by [Simotek](http://simotek.net)| -| MACOS | YES | YES | NO | Port by [clsource](https://genserver.social/clsource) | +| MACOS | YES | YES | MAYBE | Port by [clsource](https://genserver.social/clsource) | - -* **Soundfont library is currently not ported for 64bit OS** * **MIDI functionality __greatly__ depends on kernel support, please feature request your favourite OS maintainer =)** * **Install ffmpeg by following install instructions for your platform [here](https://www.ffmpeg.org/download.html)** * **PrintFX requires full ffmpeg. If marked as TBA, it requires a redesign using [libav](https://trac.ffmpeg.org/wiki/Using%20libav*)** diff --git a/sources/Application/Instruments/SoundFontManager.cpp b/sources/Application/Instruments/SoundFontManager.cpp index 0acec549..d56a4efc 100644 --- a/sources/Application/Instruments/SoundFontManager.cpp +++ b/sources/Application/Instruments/SoundFontManager.cpp @@ -2,10 +2,6 @@ #include "System/System/System.h" #include "System/FileSystem/FileSystem.h" -#ifdef _64BIT -#include -#endif - SoundFontManager::SoundFontManager() { } ; @@ -66,14 +62,11 @@ sfBankID SoundFontManager::LoadBank(const char *path) { current.dwEnd=(current.dwEnd-current.dwStart) ; current.dwStartloop=(current.dwStartloop-current.dwStart) ; current.dwEndloop=(current.dwEndloop-current.dwStart) ; -#ifdef _64BIT - current.dwStart=(intptr_t)buffer ; -#else - current.dwStart=(DWORD)buffer ; -#endif + // ADDR is pointer-sized, works on both 32-bit and 64-bit + current.dwStart = (ADDR)buffer; - sampleData_.push_back(buffer) ; - } + sampleData_.push_back(buffer); + } fin->Close() ; SAFE_DELETE(fin) ; diff --git a/sources/Application/Model/Project.h b/sources/Application/Model/Project.h index f75454d6..4a5d813f 100644 --- a/sources/Application/Model/Project.h +++ b/sources/Application/Model/Project.h @@ -19,8 +19,8 @@ #define VAR_SCALE MAKE_FOURCC('S', 'C', 'A', 'L') #define PROJECT_NUMBER "1" -#define PROJECT_RELEASE "5" -#define BUILD_COUNT "0" +#define PROJECT_RELEASE "6" +#define BUILD_COUNT "0-bacon0" #define MAX_TAP 3 @@ -63,8 +63,7 @@ class Project: public Persistent,public VariableContainer,I_Observer { int midiDeviceListSize_ ; int tempoNudge_ ; unsigned long lastTap_[MAX_TAP] ; - unsigned int tempoTapCount_ ; + unsigned int tempoTapCount_; } ; #endif - diff --git a/sources/Externals/Soundfont/DATATYPE.H b/sources/Externals/Soundfont/DATATYPE.H index ef5bcf23..06d6d6e8 100644 --- a/sources/Externals/Soundfont/DATATYPE.H +++ b/sources/Externals/Soundfont/DATATYPE.H @@ -36,13 +36,25 @@ #include +#if defined(_MSC_VER) && _MSC_VER < 1600 + /* Workaround for MSVC 2008 and earlier */ + typedef signed __int32 int32_t; + typedef unsigned __int32 uint32_t; +#ifdef _WIN64 + typedef unsigned __int64 uintptr_t; +#else + typedef unsigned __int32 uintptr_t; +#endif +#else +#include +#endif -/************ -* Defines -************/ + /************ + * Defines + ************/ -#ifndef __BYTE_INCOHERENT /* Big Endian (IE 680x0) */ -#define __BYTE_COHERENT /* Little Endian (IE 80x86) */ +#ifndef __BYTE_INCOHERENT /* Big Endian (IE 680x0) */ +#define __BYTE_COHERENT /* Little Endian (IE 80x86) */ #endif #ifdef _UNIX_STUB_ @@ -51,90 +63,92 @@ #endif #ifdef EMU_WINDOWS - #include +#include #else - #define _export +#define _export #endif -/* Expected data values */ -#define CHAR_MINVAL -127 -#define CHAR_MAXVAL 127 -#define BYTE_MAXVAL 255 -#define SHRT_MINVAL -32767 -#define SHRT_MAXVAL 32767 -#define LONG_MINVAL -2147483647L -#define LONG_MAXVAL 2147483647L -#define DWORD_MAXVAL 4294967295L + /* Expected data values */ +#define CHAR_MINVAL -127 +#define CHAR_MAXVAL 127 +#define BYTE_MAXVAL 255 +#define SHRT_MINVAL -32767 +#define SHRT_MAXVAL 32767 +#define LONG_MINVAL -2147483647L +#define LONG_MAXVAL 2147483647L +#define DWORD_MAXVAL 4294967295L #ifndef FALSE - #define FALSE 0 +#define FALSE 0 #endif #ifndef TRUE - #define TRUE 1 +#define TRUE 1 #endif #ifndef EMU_WINDOWS // windows.h defines these already -// #define LOBYTE(x) ((x) & 0x00FF) -// #define HIBYTE(x) (((x) & 0xFF00) >> 8) + // #define LOBYTE(x) ((x) & 0x00FF) + // #define HIBYTE(x) (((x) & 0xFF00) >> 8) #endif + /************* + * Typedefs + *************/ -/************* -* Typedefs -*************/ - -typedef char CHAR; /* 8 bit signed value */ -typedef short SHORT; /* 16 bit signed value was: INT */ + typedef char CHAR; /* 8 bit signed value */ + typedef short SHORT; /* 16 bit signed value was: INT */ #ifdef EMU_WINDOWS - /***************************************************************** - * These idiosyncratic pointer definitions for memory allocations - * which are greater than 64K and are Intel-centric compiling - * environment necessities, at least for Windows environments. - * Perhaps, however, Windows NT will eliminate the 'huge' keyword - * requirement altogether. - *****************************************************************/ - typedef BYTE huge* BYTEPTR; - typedef WORD huge* UINTPTR; - typedef DWORD huge* DWORDPTR; - typedef void huge* VOIDPTR; + /***************************************************************** + * These idiosyncratic pointer definitions for memory allocations + * which are greater than 64K and are Intel-centric compiling + * environment necessities, at least for Windows environments. + * Perhaps, however, Windows NT will eliminate the 'huge' keyword + * requirement altogether. + *****************************************************************/ + typedef BYTE huge *BYTEPTR; + typedef WORD huge *UINTPTR; + typedef DWORD huge *DWORDPTR; + typedef void huge *VOIDPTR; + /* Pointer-sized type for runtime memory addresses (32 or 64-bit) */ + typedef uintptr_t ADDR; #else - typedef unsigned char BYTE; /* 8 bit unsigned value */ + typedef unsigned char BYTE; /* 8 bit unsigned value */ #ifndef BOOL - typedef int BOOL; /* 16 bit signed value */ + typedef int BOOL; /* 16 bit signed value */ #endif - typedef unsigned short WORD; /* 16 bit signed value */ - typedef signed long LONG; /* 32 bit signed value */ - typedef unsigned long DWORD; /* 32 bit unsigned value */ - typedef float FLOAT; /* 32 bit floating point value */ - typedef double DOUBLE; /* 64 bit floating point value */ - typedef long double LDOUBLE; /* 80 bit floating point value */ - - typedef BYTE* BYTEPTR; - typedef WORD* UINTPTR; - typedef DWORD* DWORDPTR; - typedef void* VOIDPTR; + typedef unsigned short WORD; /* 16 bit unsigned value */ + typedef int32_t LONG; /* 32 bit signed value (fixed-size) */ + typedef uint32_t DWORD; /* 32 bit unsigned value (fixed-size) */ + typedef float FLOAT; /* 32 bit floating point value */ + typedef double DOUBLE; /* 64 bit floating point value */ + typedef long double LDOUBLE; /* 80 bit floating point value */ + + /* Pointer-sized type for runtime memory addresses (32 or 64-bit) */ + typedef uintptr_t ADDR; + + typedef BYTE *BYTEPTR; + typedef WORD *UINTPTR; + typedef DWORD *DWORDPTR; + typedef void *VOIDPTR; #endif /* EMU_WINDOWS */ -/******************************************************************** -* This 16 bit unsigned value is used for routines which return -* standard E-mu error codes (see emuerrs.h) -********************************************************************/ -typedef unsigned short EMUSTAT; + /******************************************************************** + * This 16 bit unsigned value is used for routines which return + * standard E-mu error codes (see emuerrs.h) + ********************************************************************/ + typedef unsigned short EMUSTAT; #ifdef __BYTE_COHERENT -/******************************************************************** -* Convenient union datatypes to use for byte swapping or extracting -* bytes and/or shorts within a short or long value without using -* bit shifting. -********************************************************************/ -typedef struct twoBytesTag -{ - BYTE by0; - BYTE by1; -} twoBytes; - + /******************************************************************** + * Convenient union datatypes to use for byte swapping or extracting + * bytes and/or shorts within a short or long value without using + * bit shifting. + ********************************************************************/ + typedef struct twoBytesTag { + BYTE by0; + BYTE by1; + } twoBytes; typedef struct fourBytesTag { @@ -153,12 +167,10 @@ typedef struct twoWordsTag #elif defined(__BYTE_INCOHERENT) -typedef struct twoBytesTag -{ - BYTE by1; - BYTE by0; -} twoBytes; - + typedef struct twoBytesTag { + BYTE by1; + BYTE by0; + } twoBytes; typedef struct fourBytesTag { diff --git a/sources/Externals/Soundfont/HYDRA.H b/sources/Externals/Soundfont/HYDRA.H index 23d4672a..3f686570 100644 --- a/sources/Externals/Soundfont/HYDRA.H +++ b/sources/Externals/Soundfont/HYDRA.H @@ -206,10 +206,10 @@ typedef struct sfSampleHdrTag { CHAR achSampleName[SAMPLENAMESIZE]; - DWORD dwStart; // Sample addresses - DWORD dwEnd; - DWORD dwStartloop; - DWORD dwEndloop; + ADDR dwStart; // Sample addresses + ADDR dwEnd; + ADDR dwStartloop; + ADDR dwEndloop; DWORD dwSampleRate; // In Hz, IE 44100, 22050, etc BYTE byOriginalKey; // MIDI Key, 0 to 127 CHAR chFineCorrection; // Tuning correction in cents diff --git a/sources/Externals/Soundfont/RIFF.CPP b/sources/Externals/Soundfont/RIFF.CPP index cc092bd5..494c087e 100644 --- a/sources/Externals/Soundfont/RIFF.CPP +++ b/sources/Externals/Soundfont/RIFF.CPP @@ -235,10 +235,9 @@ WORD RIFFClass::OpenRIFF(CHAR* pName) { byWhereIsRIFFData = RIFF_ONDISK; - if ((RIFFOpen((LONG)pName) != SUCCESS ) || (pFile == NULL)) - { - SetError(errno); // Set inside RIFFOpen - return (uiErrorNdx = RIFF_OPENFILEERROR); + if ((RIFFOpen((ADDR)pName) != SUCCESS) || (pFile == NULL)) { + SetError(errno); // Set inside RIFFOpen + return (uiErrorNdx = RIFF_OPENFILEERROR); } return (InitRIFF()); @@ -253,10 +252,10 @@ WORD RIFFClass::OpenRIFF(CHAR* pName) WORD RIFFClass::OpenRIFF(FSSpec* pSpecifier) { byWhereIsRIFFData = RIFF_ONMACDISK; - - if (RIFFOpen((LONG)pSpecifier) != SUCCESS) - return (RIFF_OPENFILEERROR); - + + if (RIFFOpen((ADDR)pSpecifier) != SUCCESS) + return (RIFF_OPENFILEERROR); + return(InitRIFF()); } #endif // USE_MACINTOSH @@ -443,28 +442,26 @@ DWORD RIFFClass::GetCkFormID(void) { return (dwLastFormID); } // is a pointer to the File System Specifier (FSSpec) // data structure. //*************************************************** -SHORT RIFFClass::RIFFOpen(LONG lPointer) -{ - //*************************************************** - // Keep in mind that whenever a system call is made and - // _no_ error takes place, errno is _not_ set to 0. - // Obviously, this means that any previous system call - // will set errno upon an error, one which is innocuous, - // but will cause fopen to _appear_ as though it failed. - // For example, open a temporary file which might not - // exist: - // - // fopen("tempfile", "wb"); - // - // If it doesn't exist, errno become 2 (in DOS, at - // least). Now call the fopen below for a preexisting - // RIFF file. Guess what! If you didn't reset errno - // to 0, your return value will be 2, an apparent error. - //*************************************************** - errno = 0; - - switch (byWhereIsRIFFData) - { +SHORT RIFFClass::RIFFOpen(ADDR lPointer) { + //*************************************************** + // Keep in mind that whenever a system call is made and + // _no_ error takes place, errno is _not_ set to 0. + // Obviously, this means that any previous system call + // will set errno upon an error, one which is innocuous, + // but will cause fopen to _appear_ as though it failed. + // For example, open a temporary file which might not + // exist: + // + // fopen("tempfile", "wb"); + // + // If it doesn't exist, errno become 2 (in DOS, at + // least). Now call the fopen below for a preexisting + // RIFF file. Guess what! If you didn't reset errno + // to 0, your return value will be 2, an apparent error. + //*************************************************** + errno = 0; + + switch (byWhereIsRIFFData) { case RIFF_ONDISK: pFile = fopen((CHAR *)lPointer, "rb"); return (errno); @@ -476,7 +473,7 @@ SHORT RIFFClass::RIFFOpen(LONG lPointer) default: return (1); - } + } } SHORT RIFFClass::RIFFClose() diff --git a/sources/Externals/Soundfont/RIFF.H b/sources/Externals/Soundfont/RIFF.H index ff12655d..0763b5ec 100644 --- a/sources/Externals/Soundfont/RIFF.H +++ b/sources/Externals/Soundfont/RIFF.H @@ -191,7 +191,7 @@ class RIFFClass DWORD RIFFTell(void); DWORD RIFFTellAbs(void); - SHORT RIFFOpen(LONG); + SHORT RIFFOpen(ADDR); SHORT RIFFClose(void); diff --git a/sources/Externals/Soundfont/SFDATA.H b/sources/Externals/Soundfont/SFDATA.H index 1c4ff1c8..9540f8e3 100644 --- a/sources/Externals/Soundfont/SFDATA.H +++ b/sources/Externals/Soundfont/SFDATA.H @@ -53,10 +53,10 @@ typedef enum sfSampleFlagsTag typedef struct sfDataTag { //// Oscillator //// - DWORD dwStart; //// sample start address - DWORD dwEnd; - DWORD dwStartloop; //// loop start address - DWORD dwEndloop; //// loop end address + ADDR dwStart; //// sample start address (pointer-sized for 64-bit) + ADDR dwEnd; + ADDR dwStartloop; //// loop start address (pointer-sized for 64-bit) + ADDR dwEndloop; //// loop end address (pointer-sized for 64-bit) DWORD dwSampleRate; SHORT shOrigKeyAndCorr; SHORT shSampleModes; diff --git a/sources/Externals/Soundfont/SFNAV.CPP b/sources/Externals/Soundfont/SFNAV.CPP index d16cc892..af023797 100644 --- a/sources/Externals/Soundfont/SFNAV.CPP +++ b/sources/Externals/Soundfont/SFNAV.CPP @@ -468,8 +468,8 @@ void SoundFontNavigator::Navigate(WORD uiSFID, WORD uiKey, WORD uiVel) // This step necessary for Big Endian systems if (uiInstGenOper <= endloopAddrsOffset) - *(LONG*)((BYTE*)&(psfVectorCurrOsc->dwStart) + - soundFontLookup[uiInstGenOper]) = (LONG)iInstGenAmt; + *(ADDR *)((BYTE *)&(psfVectorCurrOsc->dwStart) + + soundFontLookup[uiInstGenOper]) = (ADDR)iInstGenAmt; else *(SHORT*)((BYTE*)&(psfVectorCurrOsc->dwStart) + soundFontLookup[uiInstGenOper]) = iInstGenAmt; @@ -520,8 +520,8 @@ void SoundFontNavigator::Navigate(WORD uiSFID, WORD uiKey, WORD uiVel) // Necessary for 'byte-incoherent' systems if (uiGenOper <= endloopAddrsOffset) - *(LONG*)((BYTE*)&sfCurrPreset.dwStart + - soundFontLookup[uiGenOper]) = (LONG)iGenAmt; + *(ADDR *)((BYTE *)&sfCurrPreset.dwStart + + soundFontLookup[uiGenOper]) = (ADDR)iGenAmt; else *(SHORT*)((BYTE*)&sfCurrPreset.dwStart + soundFontLookup[uiGenOper]) = iGenAmt; @@ -815,8 +815,13 @@ SoundFontNavigator::AddSoundFonts(sfData * sfSoundFontReturned, { uiOffset = (WORD) soundFontLookup[wCount]; - *(SHORT*)((BYTE*)&(sfSoundFontReturned->dwStart) + uiOffset) += - *(SHORT*)((BYTE*)&(sfSFPresetAdd->dwStart) + uiOffset); + if (wCount <= endloopAddrsOffset) { + *(ADDR *)((BYTE *)&(sfSoundFontReturned->dwStart) + uiOffset) += + *(ADDR *)((BYTE *)&(sfSFPresetAdd->dwStart) + uiOffset); + } else { + *(SHORT *)((BYTE *)&(sfSoundFontReturned->dwStart) + uiOffset) += + *(SHORT *)((BYTE *)&(sfSFPresetAdd->dwStart) + uiOffset); + } } } diff --git a/sources/Externals/Soundfont/SFREADER.CPP b/sources/Externals/Soundfont/SFREADER.CPP index 5004ae16..94e4d368 100644 --- a/sources/Externals/Soundfont/SFREADER.CPP +++ b/sources/Externals/Soundfont/SFREADER.CPP @@ -667,11 +667,27 @@ ReadSFBData (CHAR * pchReqdWaveTable) //// Sample Headers //// for (uiCount = 0; uiCount < hf->awStructSize[sampHdr]; uiCount++) { - - tRIFF.SwapDWORD(&hf->pSHdr[uiCount].dwStart); - tRIFF.SwapDWORD(&hf->pSHdr[uiCount].dwEnd); - tRIFF.SwapDWORD(&hf->pSHdr[uiCount].dwStartloop); - tRIFF.SwapDWORD(&hf->pSHdr[uiCount].dwEndloop); + // For ADDR fields, we need to swap using temporary 32-bit variables + // since the file format uses 32-bit values but we store in pointer-sized + // fields + { + DWORD tmp; + tmp = (DWORD)hf->pSHdr[uiCount].dwStart; + tRIFF.SwapDWORD(&tmp); + hf->pSHdr[uiCount].dwStart = tmp; + + tmp = (DWORD)hf->pSHdr[uiCount].dwEnd; + tRIFF.SwapDWORD(&tmp); + hf->pSHdr[uiCount].dwEnd = tmp; + + tmp = (DWORD)hf->pSHdr[uiCount].dwStartloop; + tRIFF.SwapDWORD(&tmp); + hf->pSHdr[uiCount].dwStartloop = tmp; + + tmp = (DWORD)hf->pSHdr[uiCount].dwEndloop; + tRIFF.SwapDWORD(&tmp); + hf->pSHdr[uiCount].dwEndloop = tmp; + } tRIFF.SwapDWORD(&hf->pSHdr[uiCount].dwSampleRate); @@ -794,25 +810,29 @@ WORD mono = monoSample; // Element for element read of data, to serve as an example of a possible // issue with cross platform code. See comments below. // - for(WORD curHdr=0; curHdr < hf->awStructSize[iHydraSymbol]; curHdr++) { + for (WORD curHdr = 0; curHdr < hf->awStructSize[iHydraSymbol]; curHdr++) { + + rcnt = 0; - rcnt = 0; + rcnt += tRIFF.RIFFRead((VOIDPTR) & + ((sfSampleHdr *)pData)[curHdr].achSampleName, + 1, SAMPLENAMESIZE); - rcnt += tRIFF.RIFFRead((VOIDPTR) - &((sfSampleHdr*)pData)[curHdr].achSampleName, - 1, SAMPLENAMESIZE); + // Read 32-bit file values into temporaries, then assign to + // pointer-sized fields + uint32_t tmp_dwStart, tmp_dwEnd, tmp_dwStartloop, tmp_dwEndloop; - rcnt += tRIFF.RIFFRead( &((sfSampleHdr*)pData)[curHdr].dwStart, - 1, sizeof(DWORD)); + rcnt += tRIFF.RIFFRead(&tmp_dwStart, 1, sizeof(uint32_t)); + ((sfSampleHdr *)pData)[curHdr].dwStart = tmp_dwStart; - rcnt += tRIFF.RIFFRead( &((sfSampleHdr*)pData)[curHdr].dwEnd, - 1, sizeof(DWORD)); + rcnt += tRIFF.RIFFRead(&tmp_dwEnd, 1, sizeof(uint32_t)); + ((sfSampleHdr *)pData)[curHdr].dwEnd = tmp_dwEnd; - rcnt += tRIFF.RIFFRead( &((sfSampleHdr*)pData)[curHdr].dwStartloop, - 1, sizeof(DWORD)); + rcnt += tRIFF.RIFFRead(&tmp_dwStartloop, 1, sizeof(uint32_t)); + ((sfSampleHdr *)pData)[curHdr].dwStartloop = tmp_dwStartloop; - rcnt += tRIFF.RIFFRead( &((sfSampleHdr*)pData)[curHdr].dwEndloop, - 1, sizeof(DWORD)); + rcnt += tRIFF.RIFFRead(&tmp_dwEndloop, 1, sizeof(uint32_t)); + ((sfSampleHdr *)pData)[curHdr].dwEndloop = tmp_dwEndloop; rcnt += tRIFF.RIFFRead( &((sfSampleHdr*)pData)[curHdr].dwSampleRate, 1, sizeof(DWORD)); @@ -837,7 +857,7 @@ WORD mono = monoSample; SetError(SF_INVALIDBANK); return (NULL); } - }// end for all elements + } // end for all elements } // do sampleHdr reading, else { From a7b496c4cee3ce8b0828ba3badf416962882f46f Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Sun, 21 Dec 2025 22:04:35 +0000 Subject: [PATCH 23/38] Fix unallocated crash, segmentation fault --- sources/Application/FX/FxPrinter.cpp | 2 +- sources/Application/FX/LibavProcessor.c | 76 +++++++++++++------ .../Instruments/SampleInstrument.cpp | 11 +++ .../Instruments/SampleInstrument.h | 16 ++-- 4 files changed, 73 insertions(+), 32 deletions(-) diff --git a/sources/Application/FX/FxPrinter.cpp b/sources/Application/FX/FxPrinter.cpp index 40b3b368..cdf7426c 100644 --- a/sources/Application/FX/FxPrinter.cpp +++ b/sources/Application/FX/FxPrinter.cpp @@ -16,7 +16,7 @@ void FxPrinter::setParams() { } void FxPrinter::setPaths() { - fi_ = std::string(instrument_->GetName()); + fi_ = std::string(instrument_->GetFullName()); fiPath_ = samples_dir.GetPath() + '/' + fi_; fo_ = fi_.substr(0, fi_.find_last_of('.')) + "_.wav"; diff --git a/sources/Application/FX/LibavProcessor.c b/sources/Application/FX/LibavProcessor.c index 44ca575e..2c894cf5 100644 --- a/sources/Application/FX/LibavProcessor.c +++ b/sources/Application/FX/LibavProcessor.c @@ -24,7 +24,7 @@ static AVCodecContext *enc_ctx = NULL; static int open_input_file(const char *filename) { - AVCodec *dec; + const AVCodec *dec; AVCodecContext *dec_ctx; AVStream *stream; int ret; @@ -77,7 +77,7 @@ static int open_input_file(const char *filename) static int open_ir_file(const char *filename) { - AVCodec *dec; + const AVCodec *dec; AVCodecContext *dec_ctx; AVStream *stream; int ret; @@ -131,7 +131,6 @@ static int open_ir_file(const char *filename) static int open_output_file(const char *filename) { AVStream *out_stream; - AVStream *in_stream; const AVCodec *encoder; int ret; @@ -140,8 +139,6 @@ static int open_output_file(const char *filename) av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Could not create output context\n"); return AVERROR_UNKNOWN; } - - in_stream = ifmt_ctx->streams[0]; out_stream = avformat_new_stream(ofmt_ctx, NULL); if (!out_stream) { av_log(NULL, AV_LOG_ERROR, "[LibAvProc] Failed allocating output stream\n"); @@ -306,7 +303,8 @@ static int init_filters(int ir_wet, int ir_pad) snprintf(ch_layout_str, sizeof(ch_layout_str), "%dc", ifmt_ctx->streams[0]->codecpar->channels); } } else { - av_channel_layout_describe(&buffersink_ctx->inputs[0]->ch_layout, + // Use the input stream's channel layout + av_channel_layout_describe(&ifmt_ctx->streams[0]->codecpar->ch_layout, ch_layout_str, sizeof(ch_layout_str)); } #endif @@ -350,7 +348,8 @@ static int init_filters(int ir_wet, int ir_pad) snprintf(ir_ch_layout_str, sizeof(ir_ch_layout_str), "%dc", ir_fmt_ctx->streams[0]->codecpar->channels); } } else { - av_channel_layout_describe(&buffersink_ctx->inputs[0]->ch_layout, + // Use the IR stream's channel layout + av_channel_layout_describe(&ir_fmt_ctx->streams[0]->codecpar->ch_layout, ir_ch_layout_str, sizeof(ir_ch_layout_str)); } #endif @@ -429,12 +428,21 @@ static int init_filters(int ir_wet, int ir_pad) /* Apply convolution reverb using afir filter with format normalization */ char filters_descr[512]; + /* Scale ir_wet from 0-100 to 0-10 for afir filter */ + int afir_wet = (ir_wet * 10) / 100; + if (afir_wet > 10) afir_wet = 10; + if (afir_wet < 0) afir_wet = 0; + snprintf(filters_descr, sizeof(filters_descr), - "[ir_in]aresample=%d,aformat=sample_fmts=fltp:channel_layouts=%s[ir_norm];" - "[in]aresample=%d,aformat=sample_fmts=fltp:channel_layouts=%s,asplit[in_1][in_2];" - "[in_1][ir_norm]afir=dry=10:wet=10[reverb];" - "[in_2][reverb]amix=inputs=2:weights=100 %d,volume=1.5,aformat=sample_fmts=s16:channel_layouts=%s[out]", - target_sample_rate, target_layout, target_sample_rate, target_layout, ir_wet, target_layout); + "[ir_in]aresample=%d,aformat=sample_fmts=fltp:channel_layouts=%s[" + "ir_norm];" + "[in]aresample=%d,aformat=sample_fmts=fltp:channel_layouts=%s," + "asplit[in_1][in_2];" + "[in_1][ir_norm]afir=dry=10:wet=%d[reverb];" + "[in_2][reverb]amix=inputs=2:weights=1 " + "1,volume=2.5,aformat=sample_fmts=s16:channel_layouts=%s[out]", + target_sample_rate, target_layout, target_sample_rate, + target_layout, afir_wet, target_layout); av_log(NULL, AV_LOG_INFO, "Filter graph: %s\n", filters_descr); @@ -558,13 +566,12 @@ static int filter_encode_write_frame(AVFrame *frame, AVFrame *ir_frame, unsigned return ret; } -int encode(const char *fi, const char *ir, const char *fo, int irWet, int irPad) -{ +int encode(const char *fi, const char *ir, const char *fo, int irWet, + int irPad) { int ret; AVPacket *packet = NULL, *ir_packet = NULL; AVFrame *frame = NULL, *ir_frame = NULL; AVCodecContext *dec_ctx = NULL, *ir_dec_ctx = NULL; - unsigned int stream_index; int ir_loaded = 0; if ((ret = open_input_file(fi)) < 0) @@ -582,22 +589,45 @@ int encode(const char *fi, const char *ir, const char *fo, int irWet, int irPad) ir_frame = av_frame_alloc(); if (!packet || !ir_packet || !frame || !ir_frame) { fprintf(stderr, "Could not allocate frame or packet\n"); - return(1); + ret = AVERROR(ENOMEM); + goto end; } /* Set up decoder contexts */ - AVCodec *dec = + const AVCodec *dec = avcodec_find_decoder(ifmt_ctx->streams[0]->codecpar->codec_id); - AVCodec *ir_dec = avcodec_find_decoder(ir_fmt_ctx->streams[0]->codecpar->codec_id); - + const AVCodec *ir_dec = + avcodec_find_decoder(ir_fmt_ctx->streams[0]->codecpar->codec_id); + + if (!dec || !ir_dec) { + fprintf(stderr, "Could not find decoders (dec=%p, ir_dec=%p)\n", dec, ir_dec); + ret = AVERROR_DECODER_NOT_FOUND; + goto end; + } + dec_ctx = avcodec_alloc_context3(dec); ir_dec_ctx = avcodec_alloc_context3(ir_dec); - + + if (!dec_ctx || !ir_dec_ctx) { + fprintf(stderr, "Could not allocate decoder contexts\n"); + ret = AVERROR(ENOMEM); + goto end; + } + avcodec_parameters_to_context(dec_ctx, ifmt_ctx->streams[0]->codecpar); avcodec_parameters_to_context(ir_dec_ctx, ir_fmt_ctx->streams[0]->codecpar); - - avcodec_open2(dec_ctx, dec, NULL); - avcodec_open2(ir_dec_ctx, ir_dec, NULL); + + ret = avcodec_open2(dec_ctx, dec, NULL); + if (ret < 0) { + fprintf(stderr, "Could not open decoder: %s\n", av_err2str(ret)); + goto end; + } + + ret = avcodec_open2(ir_dec_ctx, ir_dec, NULL); + if (ret < 0) { + fprintf(stderr, "Could not open IR decoder: %s\n", av_err2str(ret)); + goto end; + } /* Process both streams - load ALL IR data first, then process main audio */ int ir_eof = 0, main_eof = 0; diff --git a/sources/Application/Instruments/SampleInstrument.cpp b/sources/Application/Instruments/SampleInstrument.cpp index c1b4f6b6..6d08e834 100644 --- a/sources/Application/Instruments/SampleInstrument.cpp +++ b/sources/Application/Instruments/SampleInstrument.cpp @@ -1410,6 +1410,17 @@ const char *SampleInstrument::GetName() { return src; } +/* + Get full name, don't shorten it for + display width limitation purposes +*/ +const char *SampleInstrument::GetFullName() { + Variable *v = FindVariable(SIP_SAMPLE); + const char *src = v->GetString(); + + return src; +} + void SampleInstrument::Purge() { IteratorPtr it(GetIterator()) ; for (it->Begin();!it->IsDone();it->Next()) { diff --git a/sources/Application/Instruments/SampleInstrument.h b/sources/Application/Instruments/SampleInstrument.h index ebf47e28..ea0e2166 100644 --- a/sources/Application/Instruments/SampleInstrument.h +++ b/sources/Application/Instruments/SampleInstrument.h @@ -92,16 +92,16 @@ class SampleInstrument: public I_Instrument,I_Observer { int GetLoopEnd(); virtual const char *GetName() ; // returns sample name until real // namer is implemented - - static void EnableDownsamplingLegacy(); + virtual const char *GetFullName(); + static void EnableDownsamplingLegacy(); -protected: - void updateInstrumentData(bool search) ; - void doTickUpdate(int channel) ; - void doKRateUpdate(int channel) ; - void updateFeedback(renderParams *rp) ; + protected: + void updateInstrumentData(bool search); + void doTickUpdate(int channel); + void doKRateUpdate(int channel); + void updateFeedback(renderParams *rp); -private: + private: SoundSource *source_ ; struct renderParams renderParams_[SONG_CHANNEL_COUNT] ; bool running_ ; From ca8313ea2dd63c1515b618386e5e3d69b7ea416c Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Wed, 24 Dec 2025 22:19:53 +0100 Subject: [PATCH 24/38] Support concatenating notifications (#214) * Support concatenating notifications When concatenating strings, display notification will no longer be only junk * Change notification from char* to string Solves both junk concatenation issue as well as memory leaks. * Enable y offset for notifications Useful if not in a loaded project Allows negative offsets, use with care * Set default xoffset for notifications https://github.com/djdiskmachine/LittleGPTracker/issues/213 --- .../Application/Views/BaseClasses/View.cpp | 20 +++++++++++-------- sources/Application/Views/BaseClasses/View.h | 5 +++-- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/sources/Application/Views/BaseClasses/View.cpp b/sources/Application/Views/BaseClasses/View.cpp index 625fa1b9..689ae8ef 100644 --- a/sources/Application/Views/BaseClasses/View.cpp +++ b/sources/Application/Views/BaseClasses/View.cpp @@ -243,18 +243,22 @@ void View::EnableNotification() { if ((SDL_GetTicks() - notificationTime_) <= NOTIFICATION_TIMEOUT) { SetColor(CD_NORMAL); GUITextProperties props; - DrawString(10, 2, displayNotification_, props); - } else { + int xOffset = 4; + DrawString(xOffset, notiDistY_, displayNotification_.c_str(), props); + } else { displayNotification_ = ""; } } /* - Set displayed notification and save the current time + Set displayed notification + Saves the current time + Optionally set display y offset if not in a project (default == 2) + Allows negative offsets, use with care! */ -void View::SetNotification(const char *notification) { - notificationTime_ = SDL_GetTicks(); - displayNotification_ = (char*) notification; - isDirty_ = true; +void View::SetNotification(const char *notification, int offset) { + notificationTime_ = SDL_GetTicks(); + displayNotification_ = notification; + notiDistY_ = offset; + isDirty_ = true; } - diff --git a/sources/Application/Views/BaseClasses/View.h b/sources/Application/Views/BaseClasses/View.h index b7fff153..3d0f787f 100644 --- a/sources/Application/Views/BaseClasses/View.h +++ b/sources/Application/Views/BaseClasses/View.h @@ -119,7 +119,7 @@ class View : public Observable { void DoModal(ModalView *view, ModalViewCallback cb = 0); void EnableNotification(); - void SetNotification(const char *notification); + void SetNotification(const char *notification, int offset = 2); protected: virtual void ProcessButtonMask(unsigned short mask, bool pressed) = 0; @@ -161,7 +161,8 @@ class View : public Observable { bool locked_; uint32_t notificationTime_; uint16_t NOTIFICATION_TIMEOUT; - char *displayNotification_; + std::string displayNotification_; + int notiDistY_; static bool initPrivate_; ModalView *modalView_; ModalViewCallback modalViewCallback_; From eb5551598e334e6dcdc1fa42d75107af79046845 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Thu, 25 Dec 2025 10:01:57 +0100 Subject: [PATCH 25/38] Don't allow creating a new project with the same name in the same place (#215) * Don't allow creating a new project with the same name in the same place Allow creating a project with the same name in a different path Pass currentDirectory to NewProjectDialog Path field added to NewProjectDialog When randomising a project name, re run randomizer if name already in use Adresses https://github.com/djdiskmachine/LittleGPTracker/issues/175 --- CHANGELOG | 3 +- docs/wiki/What-is-LittlePiggyTracker.md | 3 +- sources/Application/Model/Project.h | 2 +- .../Views/ModalDialogs/NewProjectDialog.cpp | 40 +++--- .../Views/ModalDialogs/NewProjectDialog.h | 24 ++-- .../ModalDialogs/SelectProjectDialog.cpp | 128 +++++++++--------- 6 files changed, 105 insertions(+), 95 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9f625a3b..4e6ba592 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,10 +1,11 @@ -1.6.0-bacon0 +1.6.0-bacon1 Contributions: drbscl Add 64 bit soundfont support (#211) Fixes: Add 64 bit soundfont support (#211) + Skip randomly generated project name if a directory with that name already exists (#175) 1.5.0-bacon3 Contributions: diff --git a/docs/wiki/What-is-LittlePiggyTracker.md b/docs/wiki/What-is-LittlePiggyTracker.md index 13641f55..a3adff3b 100644 --- a/docs/wiki/What-is-LittlePiggyTracker.md +++ b/docs/wiki/What-is-LittlePiggyTracker.md @@ -51,7 +51,8 @@ After that you can copy additional wavs to the lgptRoot/lgptProject/samples dire ## New project -When creating a new project, use the regen button to generate a random name. Generate a new name with Regen or edit it manually selecting characters with A and pressing up/down +When creating a new project, use the Random button to generate a random name. Generate a new name with Random or edit it manually selecting characters with A and pressing up/down +Attempting to create a project with the same name in the same location produces a notification that this operation is denied ## Multiple Projects diff --git a/sources/Application/Model/Project.h b/sources/Application/Model/Project.h index 4a5d813f..3a3c6d68 100644 --- a/sources/Application/Model/Project.h +++ b/sources/Application/Model/Project.h @@ -20,7 +20,7 @@ #define PROJECT_NUMBER "1" #define PROJECT_RELEASE "6" -#define BUILD_COUNT "0-bacon0" +#define BUILD_COUNT "0-bacon1" #define MAX_TAP 3 diff --git a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp index 3be2afcc..132a63ca 100644 --- a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp +++ b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp @@ -2,18 +2,15 @@ #include "NewProjectDialog.h" #include "Application/Utils/RandomNames.h" -static char *buttonText[BUTTONS_LENGTH] = { - (char *)"Regen", - (char *)"Ok", - (char *)"Cancel" -} ; +static char *buttonText[BUTTONS_LENGTH] = {(char *)"Random", (char *)"Ok", + (char *)"Cancel"}; #define DIALOG_WIDTH 20 -NewProjectDialog::NewProjectDialog(View &view):ModalView(view) {} +NewProjectDialog::NewProjectDialog(View &view, Path currentPath) + : ModalView(view), currentPath_(currentPath) {} -NewProjectDialog::~NewProjectDialog() { -} +NewProjectDialog::~NewProjectDialog() {} void NewProjectDialog::DrawView() { @@ -49,10 +46,11 @@ void NewProjectDialog::DrawView() { props.invert_=(selected_==i+1) ; DrawString(x,4,text,props) ; } -}; + View::EnableNotification(); +} -void NewProjectDialog::OnPlayerUpdate(PlayerEventType ,unsigned int currentTick) { -}; +void NewProjectDialog::OnPlayerUpdate(PlayerEventType, + unsigned int currentTick) {}; void NewProjectDialog::OnFocus() { selected_=currentChar_=0; @@ -71,7 +69,7 @@ void NewProjectDialog::ProcessButtonMask(unsigned short mask,bool pressed) { // A modifier if (mask & EPBM_A) { if (mask == EPBM_A) { - std::string randomName = getRandomName(); + std::string randomName = ""; switch (selected_) { case 0: if (name_[currentChar_] == ' ') { @@ -80,14 +78,22 @@ void NewProjectDialog::ProcessButtonMask(unsigned short mask,bool pressed) { isDirty_ = true; break; case 1: - std::fill(name_ + randomName.length(), - name_ + sizeof(name_) / sizeof(name_[0]), ' '); - strncpy(name_, randomName.c_str(), randomName.length()); - lastChar_ = currentChar_ = randomName.length() - 1; + do { + randomName = getRandomName(); + std::fill(name_ + randomName.length(), + name_ + sizeof(name_) / sizeof(name_[0]), ' '); + strncpy(name_, randomName.c_str(), randomName.length()); + lastChar_ = currentChar_ = randomName.length() - 1; + } while (currentPath_.Descend(GetName()).Exists()); isDirty_ = true; break; case 2: - EndModal(1); + if (currentPath_.Descend(GetName()).Exists()) { + std::string res("Name " + std::string(name_) + " busy"); + View::SetNotification(res.c_str(), -6); + } else { + EndModal(1); + } break; case 3: EndModal(0); diff --git a/sources/Application/Views/ModalDialogs/NewProjectDialog.h b/sources/Application/Views/ModalDialogs/NewProjectDialog.h index ba1aa9c7..457f8692 100644 --- a/sources/Application/Views/ModalDialogs/NewProjectDialog.h +++ b/sources/Application/Views/ModalDialogs/NewProjectDialog.h @@ -9,20 +9,22 @@ class NewProjectDialog:public ModalView { public: - NewProjectDialog(View &view) ; - virtual ~NewProjectDialog() ; + NewProjectDialog(View &view, Path currentPath = ""); + virtual ~NewProjectDialog(); - virtual void DrawView() ; - virtual void OnPlayerUpdate(PlayerEventType ,unsigned int currentTick) ; - virtual void OnFocus() ; - virtual void ProcessButtonMask(unsigned short mask,bool pressed) ; + virtual void DrawView(); + virtual void OnPlayerUpdate(PlayerEventType, unsigned int currentTick); + virtual void OnFocus(); + virtual void ProcessButtonMask(unsigned short mask, bool pressed); + + std::string GetName(); - std::string GetName() ; private: - int selected_ ; - int lastChar_ ; - char name_[MAX_NAME_LENGTH+1] ; - int currentChar_ ; + Path currentPath_; + int selected_; + int lastChar_; + char name_[MAX_NAME_LENGTH + 1]; + int currentChar_; } ; #endif diff --git a/sources/Application/Views/ModalDialogs/SelectProjectDialog.cpp b/sources/Application/Views/ModalDialogs/SelectProjectDialog.cpp index 218050f4..7c0dc506 100644 --- a/sources/Application/Views/ModalDialogs/SelectProjectDialog.cpp +++ b/sources/Application/Views/ModalDialogs/SelectProjectDialog.cpp @@ -9,11 +9,7 @@ #define LIST_SIZE 20 #define LIST_WIDTH 32 -static char *buttonText[3]= { - "Load", - "New", - "Exit" -} ; +static char *buttonText[3] = {"Load", "New", "Exit"}; Path SelectProjectDialog::lastFolder_("root:") ; int SelectProjectDialog::lastProject_ = 0 ; @@ -25,12 +21,11 @@ static void NewProjectCallback(View &v,ModalView &dialog) { std::string selected=npd.GetName() ; SelectProjectDialog &spd=(SelectProjectDialog&)v ; Result result = spd.OnNewProject(selected) ; - if (result.Failed()) - { - Trace::Error(result.GetDescription().c_str()); + if (result.Failed()) { + Trace::Error(result.GetDescription().c_str()); + } } - } -} ; +}; SelectProjectDialog::SelectProjectDialog(View &view):ModalView(view),content_(true) { } @@ -45,16 +40,17 @@ void SelectProjectDialog::DrawView() { GUITextProperties props ; SetColor(CD_NORMAL) ; + View::EnableNotification(); -// Draw projects + // Draw projects - int x=1 ; - int y=1 ; + int x = 1; + int y = 1; - if (currentProject_=topIndex_+LIST_SIZE) { + if (currentProject_ < topIndex_) { + topIndex_ = currentProject_; + }; + if (currentProject_>=topIndex_+LIST_SIZE) { topIndex_=currentProject_-LIST_SIZE+1 ; } ; @@ -113,12 +109,11 @@ void SelectProjectDialog::DrawView() { x=offset*(i+1)-strlen(text)/2 ; props.invert_=(i==selected_)?true:false ; DrawString(x,y,text,props) ; - } - + } }; -void SelectProjectDialog::OnPlayerUpdate(PlayerEventType ,unsigned int currentTick) { -}; +void SelectProjectDialog::OnPlayerUpdate(PlayerEventType, + unsigned int currentTick) {}; void SelectProjectDialog::OnFocus() { @@ -129,29 +124,30 @@ void SelectProjectDialog::OnFocus() { void SelectProjectDialog::ProcessButtonMask(unsigned short mask,bool pressed) { if (!pressed) return ; - - if (mask&EPBM_B) { - if (mask&EPBM_UP) warpToNextProject(-LIST_SIZE) ; - if (mask&EPBM_DOWN) warpToNextProject(LIST_SIZE) ; - } else { - - // A modifier - if (mask&EPBM_A) { - switch(selected_) { + + if (mask&EPBM_B) { + if (mask & EPBM_UP) + warpToNextProject(-LIST_SIZE); + if (mask&EPBM_DOWN) warpToNextProject(LIST_SIZE) ; + } else { + + // A modifier + if (mask & EPBM_A) { + switch (selected_) { case 0: // load { - //locate folder user had selected when they hit a - int count=0 ; - Path *current=0 ; - - IteratorPtr it(content_.GetIterator()) ; - for(it->Begin();!it->IsDone();it->Next()) { - if (count==currentProject_) { - current=&it->CurrentItem() ; - break ; - } - count++ ; - } + // locate folder user had selected when they hit a + int count = 0; + Path *current = 0; + + IteratorPtr it(content_.GetIterator()); + for (it->Begin(); !it->IsDone(); it->Next()) { + if (count == currentProject_) { + current = &it->CurrentItem(); + break; + } + count++; + } //check if folder is a project, indicated by 'lgpt' being the first 4 characters of the folder name std::string name = current->GetName() ; @@ -178,20 +174,21 @@ void SelectProjectDialog::ProcessButtonMask(unsigned short mask,bool pressed) { } case 1: // new { - NewProjectDialog *npd=new NewProjectDialog(*this) ; - DoModal(npd,NewProjectCallback) ; + NewProjectDialog *npd = + new NewProjectDialog(*this, currentPath_); + DoModal(npd,NewProjectCallback) ; break ; - } - case 2: // Exit ; - EndModal(0) ; + } + case 2: // Exit ; + EndModal(0) ; break ; } - } else { + } else { - // R Modifier + // R Modifier - if (mask&EPBM_R) { - } else { + if (mask & EPBM_R) { + } else { // No modifier if (mask==EPBM_UP) warpToNextProject(-1) ; if (mask==EPBM_DOWN) warpToNextProject(1) ; @@ -204,16 +201,16 @@ void SelectProjectDialog::ProcessButtonMask(unsigned short mask,bool pressed) { selected_=(selected_+1)%3 ; isDirty_=true ; } - } - } - } + } + } + } }; void SelectProjectDialog::warpToNextProject(int amount) { - int offset=currentProject_-topIndex_ ; - int size=content_.Size() ; - currentProject_+=amount ; + int offset = currentProject_ - topIndex_; + int size = content_.Size(); + currentProject_+=amount ; if (currentProject_<0) currentProject_+=size ; if (currentProject_>=size) currentProject_-=size ; @@ -223,8 +220,7 @@ void SelectProjectDialog::warpToNextProject(int amount) { topIndex_=0 ; } ; } - isDirty_=true ; - + isDirty_ = true; } Path SelectProjectDialog::GetSelection() { @@ -233,8 +229,14 @@ Path SelectProjectDialog::GetSelection() { Result SelectProjectDialog::OnNewProject(std::string &name) { - Path path = currentPath_.Descend(name); - Trace::Log("TMP","creating project at %s",path.GetPath().c_str()); + Path path = currentPath_.Descend(name); + if (path.Exists()) { + Trace::Log("SelectProjectDialog:OnNewProj","path already exists %s", path.GetPath().c_str()); + std::string res("Name " + name + " busy"); + View::SetNotification(res.c_str(), 0); + return Result(res); + } + Trace::Log("TMP","creating project at %s",path.GetPath().c_str()); selection_ = path ; Result result = FileSystem::GetInstance()->MakeDir(path.GetPath().c_str()) ; RETURN_IF_FAILED(result, ("Failed to create project dir for '%s", path.GetPath().c_str())); @@ -289,7 +291,5 @@ void SelectProjectDialog::setCurrentFolder(Path &path) { //reset & redraw screen topIndex_=0 ; currentProject_=0 ; - isDirty_=true ; + isDirty_ = true; } - - From e701a4d6ace4b9f7e0dd1d61abfe7a3611c8f722 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Sat, 27 Dec 2025 00:48:35 +0100 Subject: [PATCH 26/38] Interpolate vals (#204) * Interpolate selection Select rectangle of value columns then R+B will fill in values from the lowest to the highest. Available in tables and for note values Removes help legend in value columns, keep only in command cols --- CHANGELOG | 5 +- docs/wiki/What-is-LittlePiggyTracker.md | 9 +++ sources/Application/Model/Project.h | 2 +- sources/Application/Views/PhraseView.cpp | 72 +++++++++++++++++++++++- sources/Application/Views/PhraseView.h | 1 + sources/Application/Views/TableView.cpp | 59 ++++++++++++++++++- sources/Application/Views/TableView.h | 1 + 7 files changed, 142 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4e6ba592..9a7b7e80 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,7 @@ -1.6.0-bacon1 +1.6.0-bacon2 + Interpolate values in tables and phrases + R + B on single-column selection will fill values from lowest to highest + Contributions: drbscl Add 64 bit soundfont support (#211) diff --git a/docs/wiki/What-is-LittlePiggyTracker.md b/docs/wiki/What-is-LittlePiggyTracker.md index a3adff3b..52c6fd3c 100644 --- a/docs/wiki/What-is-LittlePiggyTracker.md +++ b/docs/wiki/What-is-LittlePiggyTracker.md @@ -118,6 +118,7 @@ Note: CTRL Key mappings of RT and LT are inverted. Since the keyboard's Arrow Ke - B+LEFT/RIGHT: Next/Previous Channel in Chain/Phrase Screen. Navigation +/- 1 in Instrument/Table Screen. Switch between Song and Live Modes in Song Screen. - RT+ARROWS: Navigate between the Screens. - LT+UP/DOWN: Jump up/down to next populated row after a blank row (great for live mode entire row queuing!) +- RT+B: in chains or tables, a single-column selection will fill values from lowest to highest ## Selections @@ -137,6 +138,14 @@ And then: - LT+A: paste the clipboard content at current location +- RT+B: in chains or tables, a single-column selection will fill values from lowest to highest + +00 01 00 01 +01 -- => 01 02 +02 -- 02 03 +03 04 03 04 + + ## Playback Modes and Controls There are two modes for playback, Song and Live. The controls in each mode differ slightly. diff --git a/sources/Application/Model/Project.h b/sources/Application/Model/Project.h index 3a3c6d68..5b8f5c1a 100644 --- a/sources/Application/Model/Project.h +++ b/sources/Application/Model/Project.h @@ -20,7 +20,7 @@ #define PROJECT_NUMBER "1" #define PROJECT_RELEASE "6" -#define BUILD_COUNT "0-bacon1" +#define BUILD_COUNT "0-bacon2" #define MAX_TAP 3 diff --git a/sources/Application/Views/PhraseView.cpp b/sources/Application/Views/PhraseView.cpp index c95bfb46..f370306a 100644 --- a/sources/Application/Views/PhraseView.cpp +++ b/sources/Application/Views/PhraseView.cpp @@ -505,6 +505,72 @@ void PhraseView::extendSelection() { isDirty_ = true; } } + +/****************************************************** + interpolateSelection: + expands the lowest value of selection to the highest + ******************************************************/ +void PhraseView::interpolateSelection() { + if (!clipboard_.active_) { + return; + } + + GUIRect rect = getSelectionRect(); + // Only interpolate if we're in note (0) or param (3, 5) columns + int col = rect.Left(); + if (col != rect.Right() || (col != 0 && col != 3 && col != 5)) { + return; + } + + int startRow = rect.Top(); + int endRow = rect.Bottom(); + // Need at least 2 rows to interpolate + if (endRow - startRow < 1) { + return; + } + + // Select the appropriate data array based on column + if (col == 0) { + // Note column + uchar *noteData = phrase_->note_ + (16 * viewData_->currentPhrase_); + + uchar startNote = noteData[startRow]; + uchar endNote = noteData[endRow]; + + if (startNote == 0xFF || endNote == 0xFF) { + View::SetNotification("No note info"); + return; + } + + int numSteps = endRow - startRow; + int noteDiff = (int)endNote - (int)startNote; + + for (int step = 0; step <= numSteps; step++) { + int row = startRow + step; + int value = startNote + (2 * noteDiff * step + numSteps) / (2 * numSteps); + noteData[row] = (uchar)value; + } + } else { + // Parameter columns (3 or 5) + ushort *paramData = (col == 3) ? + phrase_->param1_ + (16 * viewData_->currentPhrase_) : + phrase_->param2_ + (16 * viewData_->currentPhrase_); + + ushort startParam = paramData[startRow]; + ushort endParam = paramData[endRow]; + + int numSteps = endRow - startRow; + int paramDiff = (int)endParam - (int)startParam; + + for (int step = 0; step <= numSteps; step++) { + int row = startRow + step; + int value = startParam + (2 * paramDiff * step + numSteps) / (2 * numSteps); + paramData[row] = (ushort)value; + } + } + isDirty_ = true; +} + /****************************************************** copySelection: copies data in the current selection to the @@ -992,6 +1058,8 @@ void PhraseView::processSelectionButtonMask(unsigned short mask) { if (mask & EPBM_B) { if (mask & EPBM_L) { extendSelection(); + } else if (mask & EPBM_R) { + interpolateSelection(); } else { copySelection(); } @@ -1210,7 +1278,7 @@ void PhraseView::DrawView() { DrawString(pos._x, pos._y, buffer, props); setTextProps(props, 2, j, true); pos._y++; - if (j == row_ && (col_ == 2 || col_ == 3)) { + if (j == row_ && col_ == 2) { printHelpLegend(command, props); } } @@ -1257,7 +1325,7 @@ void PhraseView::DrawView() { DrawString(pos._x, pos._y, buffer, props); setTextProps(props, 4, j, true); pos._y++; - if (j == row_ && (col_ == 4 || col_ == 5)) { + if (j == row_ && col_ == 4) { printHelpLegend(command, props); } } diff --git a/sources/Application/Views/PhraseView.h b/sources/Application/Views/PhraseView.h index 7693164d..1e266254 100644 --- a/sources/Application/Views/PhraseView.h +++ b/sources/Application/Views/PhraseView.h @@ -33,6 +33,7 @@ class PhraseView : public View { GUIRect getSelectionRect(); void fillClipboardData(); + void interpolateSelection(); void copySelection(); void cutSelection(); void pasteClipboard(); diff --git a/sources/Application/Views/TableView.cpp b/sources/Application/Views/TableView.cpp index f16355d8..1fe50cad 100644 --- a/sources/Application/Views/TableView.cpp +++ b/sources/Application/Views/TableView.cpp @@ -119,6 +119,57 @@ void TableView::extendSelection() { } } +/****************************************************** + interpolateSelection: + expands the lowest value of selection to the highest + ******************************************************/ +void TableView::interpolateSelection() { + if (!clipboard_.active_) { + return; + } + + GUIRect rect = getSelectionRect(); + + // Only interpolate if we're in param columns (1, 3, 5) + int col = rect.Left(); + if (col != rect.Right() || (col != 1 && col != 3 && col != 5)) { + return; + } + + int startRow = rect.Top(); + int endRow = rect.Bottom(); + + // Need at least 2 rows to interpolate + if (endRow - startRow < 1) { + return; + } + + Table &table = TableHolder::GetInstance()->GetTable(viewData_->currentTable_); + + ushort *paramData; + if (col == 1) { + paramData = table.param1_; + } else if (col == 3) { + paramData = table.param2_; + } else { + paramData = table.param3_; + } + + ushort startParam = paramData[startRow]; + ushort endParam = paramData[endRow]; + + int numSteps = endRow - startRow; + int paramDiff = (int)endParam - (int)startParam; + + for (int step = 0; step <= numSteps; step++) { + int row = startRow + step; + int value = startParam + (2 * paramDiff * step + numSteps) / (2 * numSteps); + paramData[row] = (ushort)value; + } + + isDirty_ = true; +} + void TableView::copySelection() { // Keep up with row,col of selection coz @@ -619,6 +670,8 @@ void TableView::processSelectionButtonMask(unsigned short mask) { if (mask & EPBM_B) { if (mask & EPBM_L) { extendSelection(); + } else if (mask & EPBM_R) { + interpolateSelection(); } else { copySelection(); } @@ -750,7 +803,7 @@ void TableView::DrawView() { DrawString(pos._x, pos._y, buffer, props); setTextProps(props, 0, j, true); pos._y++; - if (j == row_ && (col_ == 0 || col_ == 1)) { + if (j == row_ && col_ == 0) { printHelpLegend(command, props); } } @@ -788,7 +841,7 @@ void TableView::DrawView() { DrawString(pos._x, pos._y, buffer, props); setTextProps(props, 2, j, true); pos._y++; - if (j == row_ && (col_ == 2 || col_ == 3)) { + if (j == row_ && col_ == 2) { printHelpLegend(command, props); } } @@ -826,7 +879,7 @@ void TableView::DrawView() { DrawString(pos._x, pos._y, buffer, props); setTextProps(props, 4, j, true); pos._y++; - if (j == row_ && (col_ == 4 || col_ == 5)) { + if (j == row_ && col_ == 5) { printHelpLegend(command, props); } } diff --git a/sources/Application/Views/TableView.h b/sources/Application/Views/TableView.h index 38a68a53..db11ca99 100644 --- a/sources/Application/Views/TableView.h +++ b/sources/Application/Views/TableView.h @@ -21,6 +21,7 @@ class TableView : public View { void cutPosition(); void pasteLast(); + void interpolateSelection(); void copySelection(); void cutSelection(); void pasteClipboard(); From b0ecd0325f8c59423376a096f026b00d9439f512 Mon Sep 17 00:00:00 2001 From: djdiskmachine Date: Sat, 27 Dec 2025 16:48:53 +0100 Subject: [PATCH 27/38] Fix Save As Save as now discards unsaved changes to current project Unsaved changes only written to project under new name Adds filesystem function Delete(Path&) Adds optional argument to PersistencyService::Save(const char* name) Save temp file Copy temp file to new location Delete temp file Bump CHANGELOG https://github.com/djdiskmachine/LittleGPTracker/issues/212 --- CHANGELOG | 1 + .../Persistency/PersistencyService.cpp | 10 +++++----- .../Application/Persistency/PersistencyService.h | 4 ++-- sources/Application/Views/ProjectView.cpp | 15 +++++++++------ sources/System/FileSystem/FileSystem.cpp | 16 ++++++++++++++++ sources/System/FileSystem/FileSystem.h | 1 + 6 files changed, 34 insertions(+), 13 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9a7b7e80..e7a087c0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,7 @@ Fixes: Add 64 bit soundfont support (#211) Skip randomly generated project name if a directory with that name already exists (#175) + Save Song As" saves to current as well as new project (#212) 1.5.0-bacon3 Contributions: diff --git a/sources/Application/Persistency/PersistencyService.cpp b/sources/Application/Persistency/PersistencyService.cpp index ebcaaed6..5b6ee1af 100644 --- a/sources/Application/Persistency/PersistencyService.cpp +++ b/sources/Application/Persistency/PersistencyService.cpp @@ -7,12 +7,12 @@ PersistencyService::PersistencyService():Service(MAKE_FOURCC('S','V','P','S')) { } ; -void PersistencyService::Save() { +void PersistencyService::Save(const char *name) { - Path filename("project:lgptsav.dat") ; + Path filename(name); - TiXmlDocument doc(filename.GetPath()) ; - TiXmlElement first("LITTLEGPTRACKER") ; + TiXmlDocument doc(filename.GetPath()); + TiXmlElement first("LITTLEGPTRACKER") ; TiXmlNode *node=doc.InsertEndChild(first) ; // Loop on all registered service @@ -25,7 +25,7 @@ void PersistencyService::Save() { } ; doc.SaveFile() ; -} ; +}; bool PersistencyService::Load() { diff --git a/sources/Application/Persistency/PersistencyService.h b/sources/Application/Persistency/PersistencyService.h index 27171df1..410f9cae 100644 --- a/sources/Application/Persistency/PersistencyService.h +++ b/sources/Application/Persistency/PersistencyService.h @@ -8,8 +8,8 @@ class PersistencyService: public Service,public T_Singleton { public: PersistencyService() ; - void Save() ; - bool Load() ; + void Save(const char *name = "project:lgptsav.dat"); + bool Load() ; } ; class PersistencyDocument: public TiXmlDocument { diff --git a/sources/Application/Views/ProjectView.cpp b/sources/Application/Views/ProjectView.cpp index 2afe9516..da126609 100644 --- a/sources/Application/Views/ProjectView.cpp +++ b/sources/Application/Views/ProjectView.cpp @@ -38,8 +38,8 @@ static void SaveAsProjectCallback(View &v,ModalView &dialog) { Path path_dstprjdir = Path(str_dstprjdir); Path path_dstsmpdir = Path(str_dstsmpdir); - Path path_srclgptdatsav = path_srcprjdir.GetPath() + "lgptsav.dat"; - Path path_dstlgptdatsav = path_dstprjdir.GetPath() + "/lgptsav.dat"; + Path path_srclgptdatsav = path_srcprjdir.GetPath() + "lgptsav_tmp.dat"; + Path path_dstlgptdatsav = path_dstprjdir.GetPath() + "/lgptsav.dat"; if (path_dstprjdir.Exists()) { Trace::Log("ProjectView", "Dst Dir '%s' Exist == true", @@ -55,10 +55,13 @@ static void SaveAsProjectCallback(View &v,ModalView &dialog) { return; }; - FSS.Copy(path_srclgptdatsav,path_dstlgptdatsav); + if (FSS.Copy(path_srclgptdatsav, path_dstlgptdatsav) > -1) { + FSS.Delete(path_srclgptdatsav); + } - I_Dir *idir_srcsmpdir=FileSystem::GetInstance()->Open(path_srcsmpdir.GetPath().c_str()); - if (idir_srcsmpdir) { + I_Dir *idir_srcsmpdir = + FileSystem::GetInstance()->Open(path_srcsmpdir.GetPath().c_str()); + if (idir_srcsmpdir) { idir_srcsmpdir->GetContent("*"); idir_srcsmpdir->Sort(); IteratorPtrit(idir_srcsmpdir->GetIterator()); @@ -270,7 +273,7 @@ void ProjectView::Update(Observable &,I_ObservableData *data) { } case ACTION_SAVE_AS: { PersistencyService *service = PersistencyService::GetInstance(); - service->Save(); + service->Save("project:lgptsav_tmp.dat"); NewProjectDialog *mb = new NewProjectDialog(*this); DoModal(mb, SaveAsProjectCallback); break; diff --git a/sources/System/FileSystem/FileSystem.cpp b/sources/System/FileSystem/FileSystem.cpp index 168c793f..78884dcc 100644 --- a/sources/System/FileSystem/FileSystem.cpp +++ b/sources/System/FileSystem/FileSystem.cpp @@ -215,4 +215,20 @@ int FileSystemService::Copy(const Path &src,const Path &dst) isrc->Close(); idst->Close(); return nbwrite; +} + +int FileSystemService::Delete(const Path &path) { + int result = -1; + std::string pathString = path.GetPath(); + FileSystem * fs = FileSystem::GetInstance(); + + if (fs->GetFileType(pathString.c_str()) != FT_UNKNOWN) { + fs->Delete(pathString.c_str()); + result += 1; + Trace::Log("FileSystemService"," Delete %s ", pathString.c_str()); + } else { + Trace::Log("FS Delete","path does not exist: %s", pathString.c_str()); + } + + return result; } \ No newline at end of file diff --git a/sources/System/FileSystem/FileSystem.h b/sources/System/FileSystem/FileSystem.h index a915ffc8..4f36388d 100644 --- a/sources/System/FileSystem/FileSystem.h +++ b/sources/System/FileSystem/FileSystem.h @@ -111,6 +111,7 @@ class FileSystem: public T_Factory { class FileSystemService { public: int Copy(const Path &src,const Path &dst); + int Delete(const Path &path); }; #endif From fc258482f61c0f000ab30ade01eaf779c6040bc5 Mon Sep 17 00:00:00 2001 From: djdiskmachine Date: Sat, 27 Dec 2025 16:54:01 +0100 Subject: [PATCH 28/38] ProjectView render item Possible to render from ProjectView Notify users when entering and exiting recording Remove old config-based recording and references in documentation. Add view item Pass render mode to MixerService on ProjectView::Update --- CHANGELOG | 2 + docs/LittlePiggyTrackerConf.md | 13 -- docs/wiki/What-is-LittlePiggyTracker.md | 17 +-- docs/wiki/config_xml.md | 10 -- docs/wiki/ubuntu_install.md | 1 - sources/Application/Mixer/MixerService.cpp | 156 +++++++++------------ sources/Application/Mixer/MixerService.h | 27 ++-- sources/Application/Model/Project.cpp | 9 ++ sources/Application/Model/Project.h | 9 +- sources/Application/Model/ProjectDatas.h | 8 +- sources/Application/Views/ProjectView.cpp | 75 +++++++--- sources/Application/Views/ProjectView.h | 10 +- sources/Application/Views/SongView.cpp | 11 ++ sources/Application/Views/ViewData.cpp | 2 + sources/Application/Views/ViewData.h | 6 + 15 files changed, 191 insertions(+), 165 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e7a087c0..085828a3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,6 @@ 1.6.0-bacon2 + ProjectView Render item + When in project view, it's now possible to initiate rendering Interpolate values in tables and phrases R + B on single-column selection will fill values from lowest to highest diff --git a/docs/LittlePiggyTrackerConf.md b/docs/LittlePiggyTrackerConf.md index 6f6acfd1..cb6bd4aa 100644 --- a/docs/LittlePiggyTrackerConf.md +++ b/docs/LittlePiggyTrackerConf.md @@ -13,7 +13,6 @@ 06. [Key and Button Mapping](#key-and-button-mapping) 07. [Auto Repeat](#auto-repeat) 08. [Path](#path) -09. [Rendering](#rendering) 10. [Volume](#volume) 11. [Audio Configuration](#audio-configuration) 12. [MIDI Configuration](#midi-configuration) @@ -246,18 +245,6 @@ You can tweak two different path: ``` -## Rendering - -Additionally to playing the song, LittleGPTracker can be used to render the audio to file. To control file rendering, the variable `RENDER` can be set to either `FILE`,`FILESPLIT`,`FILERT`,`FILESPLITRT`. Note that there's a small issue with the speed when using `FILE`/`FILESPLIT` so the xxRT seem like the best choice at the moment -The xxRT options render in real time -The xSPLITx options render separate files for the channels (stems) - -```xml - - - -``` - ## Volume For \[**GP2X**/**Dingoo**\] only diff --git a/docs/wiki/What-is-LittlePiggyTracker.md b/docs/wiki/What-is-LittlePiggyTracker.md index 52c6fd3c..ff297ffa 100644 --- a/docs/wiki/What-is-LittlePiggyTracker.md +++ b/docs/wiki/What-is-LittlePiggyTracker.md @@ -591,20 +591,11 @@ RTRG 0101: does not do anything because after looping one tick, you move forward # Rendering Some people exploit the analog gap between their device's headphone output and whatever they are recording with. Alternately, you can start piggy in rendering mode so it will output 16bit, 44100Hz .WAV files. -Please note that RENDER mode is not intended to be functional on the GP2X Builds. -The following values can set for RENDER in the config.xml: +The following values can set for RENDER in the project view -- Standard mode: audio is played; no render. -- FILE: File rendering: Full speed (no audio) rendering of the stereo mixdown. -- FILESPLIT: File split rendering: Full speed (no audio) rendering of each channel separately. -- FILERT: Real Time file rendering: Renders the mixdown to file WHILE playing audio. This allow to render live mode tweaks directly. -- FILESPLITRT: Real Time file split: same except all channels are rendered separately. - -Here is an example of the proper XML syntax: (See [The config.xml setup guide](../LittlePiggyTrackerConf.md)) - -```xml - -``` +- Off: audio is played; no render. +- Stereo: Real Time file rendering: Renders the mixdown to file WHILE playing audio. This allow to render live mode tweaks directly. +- Stems: Real Time file split: same except all channels are rendered separately. Remember, any of the config.xml parameters can be specified to lgpt on the command line in this fashion: diff --git a/docs/wiki/config_xml.md b/docs/wiki/config_xml.md index 3687abba..b910ed38 100644 --- a/docs/wiki/config_xml.md +++ b/docs/wiki/config_xml.md @@ -199,16 +199,6 @@ You can tweak two different path: ``` -## Rendering - -Additionally to playing the song, LittleGPTracker can be used to render the audio to file. To control file rendering, the variable RENDER can be set to either FILE,FILESPLIT,FILERT,FILESPLITRT. Note that there's a small issue with the speed when using FILE/FILESPLIT so the xxRT seem like the best choice at the moment - -```xml - - - -``` - ## Volume This setting is for GP2X and Dingoo only. It is used to set the volume of the hardware at startup. In decimal (base 10). diff --git a/docs/wiki/ubuntu_install.md b/docs/wiki/ubuntu_install.md index fef0874f..c78ac58c 100644 --- a/docs/wiki/ubuntu_install.md +++ b/docs/wiki/ubuntu_install.md @@ -58,4 +58,3 @@ Please remember: ##### Use Piggy as your Midi Sequencer -##### Script piggy to run in render mode from a simple xterm command diff --git a/sources/Application/Mixer/MixerService.cpp b/sources/Application/Mixer/MixerService.cpp index abd6c722..daba8f7e 100644 --- a/sources/Application/Mixer/MixerService.cpp +++ b/sources/Application/Mixer/MixerService.cpp @@ -1,52 +1,34 @@ #include "MixerService.h" +#include "Application/Audio/DummyAudioOut.h" +#include "Application/Model/Config.h" +#include "Application/Model/Mixer.h" +#include "Application/Model/Project.h" #include "Services/Audio/Audio.h" #include "Services/Audio/AudioDriver.h" #include "Services/Midi/MidiService.h" #include "System/Console/Trace.h" -#include "Application/Model/Config.h" -#include "Application/Audio/DummyAudioOut.h" -#include "Application/Model/Mixer.h" -MixerService::MixerService(): - out_(0), - sync_(0) -{ - mode_=MSM_AUDIO ; - const char *render=Config::GetInstance()->GetValue("RENDER") ; - if (render) { - if (!strcmp(render,"FILERT")) { - mode_=MSM_FILERT ; - } ; - if (!strcmp(render,"FILE")) { - mode_=MSM_FILE ; - } ; - if (!strcmp(render,"FILESPLIT")) { - mode_=MSM_FILESPLIT ; - } ; - if (!strcmp(render,"FILESPLITRT")) { - mode_=MSM_FILESPLITRT ; - } ; - } ; -} ; +MixerService::MixerService() : out_(0), sync_(0), isRendering_(false) { + mode_ = MSRM_PLAYBACK; +}; -MixerService::~MixerService() { -} ; +MixerService::~MixerService() {}; /* * initializes the mixer service, config changes depending if we're in sequencer or render mode */ bool MixerService::Init() { - // create the output depending on rendering mode - out_ = 0; + // create the output depending on rendering mode + out_ = 0; switch (mode_) { - case MSM_FILE: - case MSM_FILESPLIT: - out_ = new DummyAudioOut(); - break; - default: - Audio *audio = Audio::GetInstance(); - out_ = audio->GetFirst(); - break; + case MSRM_STEREO: + case MSRM_STEMS: + out_ = new DummyAudioOut(); + break; + default: + Audio *audio = Audio::GetInstance(); + out_ = audio->GetFirst(); + break; } for (int i=0;iInsert(master_); } - switch(mode_) { - case MSM_AUDIO: - break ; - case MSM_FILERT: - case MSM_FILE: - out_->SetFileRenderer("project:mixdown.wav"); - break; - case MSM_FILESPLITRT: - case MSM_FILESPLIT: - for (int i=0;iAddObserver(*MidiService::GetInstance()); + initRendering(mode_); + out_->AddObserver(*MidiService::GetInstance()); } sync_=SDL_CreateMutex(); @@ -90,6 +57,23 @@ bool MixerService::Init() { return (result); }; +void MixerService::initRendering(MixerServiceRenderMode mode) { + switch(mode) { + case MSRM_PLAYBACK: + break; + case MSRM_STEREO: + out_->SetFileRenderer("project:mixdown.wav"); + break; + case MSRM_STEMS: + for (int i = 0; i < SONG_CHANNEL_COUNT; i++) { + char buffer[1024]; + sprintf(buffer, "project:channel%d.wav", i); + bus_[i].SetFileRenderer(buffer); + } + break; + } +} + void MixerService::Close() { if (out_) { out_->RemoveObserver(*MidiService::GetInstance()); @@ -98,21 +82,13 @@ void MixerService::Close() { master_.Empty() ; switch(mode_) { - case MSM_FILE: - case MSM_FILESPLIT: - SAFE_DELETE(out_) ; - break; - default: - break ; - } - switch(mode_) { - case MSM_FILESPLITRT: - case MSM_FILESPLIT: - break; - default: - break ; - } - } + case MSRM_STEMS: + case MSRM_STEREO: + break; + default: + break; + } + } for (int i=0;iStart() ; - if (out_) { - out_->AddObserver(*this) ; - out_->Start() ; + MidiService::GetInstance()->Start(); + if (out_) { + out_->AddObserver(*this); + out_->Start(); } return true ; } ; @@ -181,20 +163,22 @@ int MixerService::GetPlayedBufferPercentage() { } void MixerService::toggleRendering(bool enable) { - switch(mode_) { - case MSM_AUDIO: - break ; - case MSM_FILERT: - case MSM_FILE: - out_->EnableRendering(enable) ; - break ; - case MSM_FILESPLITRT: - case MSM_FILESPLIT: - for (int i=0;iEnableRendering(enable); + break; + case MSRM_STEMS: + initRendering(MSRM_STEMS); + for (int i = 0; i < SONG_CHANNEL_COUNT; i++) { + bus_[i].EnableRendering(enable); + }; + break; + } } void MixerService::OnPlayerStart() { diff --git a/sources/Application/Mixer/MixerService.h b/sources/Application/Mixer/MixerService.h index 8a7f6a5f..55de2f4a 100644 --- a/sources/Application/Mixer/MixerService.h +++ b/sources/Application/Mixer/MixerService.h @@ -13,13 +13,11 @@ #include "Services/Audio/AudioOut.h" #include "MixBus.h" -enum MixerServiceMode { - MSM_AUDIO, - MSM_FILE, - MSM_FILESPLIT, - MSM_FILERT, - MSM_FILESPLITRT -} ; +enum MixerServiceRenderMode { + MSRM_PLAYBACK, + MSRM_STEREO, + MSRM_STEMS, +}; #define MAX_BUS_COUNT 10 @@ -51,6 +49,8 @@ class MixerService: void SetPregain(int); void SetSoftclip(int, int); void SetMasterVolume(int); + void SetRenderMode(int); + bool IsRendering(); int GetPlayedBufferPercentage() ; virtual void Execute(FourCC id,float value) ; @@ -63,11 +63,12 @@ class MixerService: protected: void toggleRendering(bool enable) ; private: - AudioOut *out_ ; - MixBus master_ ; - MixBus bus_[MAX_BUS_COUNT] ; - MixerServiceMode mode_ ; - SDL_mutex *sync_ ; - + void initRendering(MixerServiceRenderMode); + AudioOut *out_; + MixBus master_; + MixBus bus_[MAX_BUS_COUNT]; + MixerServiceRenderMode mode_; + SDL_mutex *sync_; + bool isRendering_; } ; #endif diff --git a/sources/Application/Model/Project.cpp b/sources/Application/Model/Project.cpp index 784a21fb..56bcead3 100644 --- a/sources/Application/Model/Project.cpp +++ b/sources/Application/Model/Project.cpp @@ -41,6 +41,9 @@ tempoNudge_(0) new Variable("scale", VAR_SCALE, scaleNames, scaleCount, 0); this->Insert(scale); scale->SetInt(0); + Variable *renderMode = + new Variable("renderMode", VAR_RENDER, renderModes, MAX_RENDER_MODE, 0); + this->Insert(renderMode); // Reload the midi device list @@ -110,6 +113,12 @@ int Project::GetPregain() { return v->GetInt(); } +int Project::GetRenderMode() { + Variable *v = FindVariable(VAR_RENDER); + NAssert(v); + return v->GetInt(); +} + void Project::NudgeTempo(int value) { if((GetTempo() + tempoNudge_) > 0) tempoNudge_ += value; diff --git a/sources/Application/Model/Project.h b/sources/Application/Model/Project.h index 5b8f5c1a..09ee605b 100644 --- a/sources/Application/Model/Project.h +++ b/sources/Application/Model/Project.h @@ -17,6 +17,7 @@ #define VAR_SOFTCLIP_GAIN MAKE_FOURCC('S', 'F', 'G', 'N') #define VAR_PREGAIN MAKE_FOURCC('P', 'R', 'G', 'N') #define VAR_SCALE MAKE_FOURCC('S', 'C', 'A', 'L') +#define VAR_RENDER MAKE_FOURCC('R', 'N', 'D', 'R') #define PROJECT_NUMBER "1" #define PROJECT_RELEASE "6" @@ -43,9 +44,10 @@ class Project: public Persistent,public VariableContainer,I_Observer { int GetSoftclip(); int GetSoftclipGain(); int GetPregain(); - + int GetRenderMode(); void Trigger(); + static const unsigned int MAX_RENDER_MODE = 3; // I_Observer virtual void Update(Observable &o, I_ObservableData *d); @@ -56,7 +58,8 @@ class Project: public Persistent,public VariableContainer,I_Observer { void LoadFirstGen(const char *root); protected: - void buildMidiDeviceList() ; + void buildMidiDeviceList(); + private: InstrumentBank *instrumentBank_ ; char **midiDeviceList_ ; @@ -64,6 +67,6 @@ class Project: public Persistent,public VariableContainer,I_Observer { int tempoNudge_ ; unsigned long lastTap_[MAX_TAP] ; unsigned int tempoTapCount_; -} ; +}; #endif diff --git a/sources/Application/Model/ProjectDatas.h b/sources/Application/Model/ProjectDatas.h index e4eaff0f..0f70f880 100644 --- a/sources/Application/Model/ProjectDatas.h +++ b/sources/Application/Model/ProjectDatas.h @@ -1,2 +1,6 @@ -char *softclipStates[] = {"Bypass", "Subtle", "Medium", "Heavy", "Insane"}; -char *softclipGainStates[] = {"[unity]", "[boost]"}; +#ifndef _PROJECTDATAS_H_ +#define _PROJECTDATAS_H_ +static const char *softclipStates[] = {"Bypass", "Subtle", "Medium", "Heavy", "Insane"}; +static const char *softclipGainStates[] = {"[unity]", "[boost]"}; +static const char *renderModes[] = {"Off", "Stereo", "Stems"}; +#endif \ No newline at end of file diff --git a/sources/Application/Views/ProjectView.cpp b/sources/Application/Views/ProjectView.cpp index da126609..0674049a 100644 --- a/sources/Application/Views/ProjectView.cpp +++ b/sources/Application/Views/ProjectView.cpp @@ -1,4 +1,6 @@ #include "ProjectView.h" +#include "Application/Mixer/MixerService.h" +#include "Application/Model/ProjectDatas.h" #include "Application/Model/Scale.h" #include "Application/Persistency/PersistencyService.h" #include "Application/Views/ModalDialogs/MessageBox.h" @@ -81,13 +83,15 @@ static void SaveAsProjectCallback(View &v,ModalView &dialog) { } static void LoadCallback(View &v,ModalView &dialog) { - if (dialog.GetReturnCode()==MBL_YES) { + MixerService::GetInstance()->SetRenderMode(0); + if (dialog.GetReturnCode()==MBL_YES) { ((ProjectView &)v).OnLoadProject() ; } } ; static void QuitCallback(View &v,ModalView &dialog) { - if (dialog.GetReturnCode()==MBL_YES) { + MixerService::GetInstance()->SetRenderMode(0); + if (dialog.GetReturnCode()==MBL_YES) { ((ProjectView &)v).OnQuit() ; } } ; @@ -98,8 +102,8 @@ static void PurgeCallback(View &v,ModalView &dialog) { ProjectView::ProjectView(GUIWindow &w,ViewData *data):FieldView(w,data) { - lastClock_=0 ; - lastTick_=0 ; + lastClock_ = 0; + lastTick_ = 0; project_=data->project_ ; @@ -183,6 +187,13 @@ ProjectView::ProjectView(GUIWindow &w,ViewData *data):FieldView(w,data) { MidiService::GetInstance()->Size(), 1, 1); T_SimpleList::Insert(field); + position._y += 2; + v = project_->FindVariable(VAR_RENDER); + NAssert(v); + field = new UIIntVarField(position, *v, "Render: %s", 0, + project_->MAX_RENDER_MODE - 1, 1, 2); + T_SimpleList::Insert(field); + position._y += 2; a1 = new UIActionField("Exit", ACTION_QUIT, position); a1->AddObserver(*this); @@ -195,23 +206,34 @@ ProjectView::~ProjectView() { void ProjectView::ProcessButtonMask(unsigned short mask,bool pressed) { - if (!pressed) return ; + if (!pressed) + return; - FieldView::ProcessButtonMask(mask) ; + FieldView::ProcessButtonMask(mask); - if (mask&EPBM_R) { - if (mask&EPBM_DOWN) { + if (mask & EPBM_R) { + if (mask&EPBM_DOWN) { ViewType vt=VT_SONG; ViewEvent ve(VET_SWITCH_VIEW,&vt) ; SetChanged(); - NotifyObservers(&ve) ; - } - } else { - if (mask&EPBM_START) { - Player *player=Player::GetInstance() ; + NotifyObservers(&ve); + } + } else { + if (mask&EPBM_START) { + Player *player = Player::GetInstance(); + + int renderMode = viewData_->renderMode_; + if (renderMode > 0 && !player->IsRunning()) { + viewData_->isRendering_ = true; + View::SetNotification("Rendering started!"); + } else if (viewData_->isRendering_ && player->IsRunning()) { + viewData_->isRendering_ = false; + View::SetNotification("Rendering done!"); + } + player->OnStartButton(PM_SONG,viewData_->songX_,false,viewData_->songX_) ; } - } ; + }; } ; void ProjectView::DrawView() { @@ -230,8 +252,22 @@ void ProjectView::DrawView() { SetColor(CD_NORMAL); DrawString(pos._x,pos._y,projectString,props) ; - FieldView::Redraw() ; - drawMap() ; + FieldView::Redraw(); + drawMap(); + + int currentMode = project_->GetRenderMode(); + if ((viewData_->renderMode_ != currentMode) && !MixerService::GetInstance()->IsRendering()) { + // Mode changed + if (currentMode > 0 && viewData_->renderMode_ == 0) { + View::SetNotification("Rendering on, press start"); + } else if (currentMode == 0 && viewData_->renderMode_ > 0) { + View::SetNotification("Rendering off"); + } + viewData_->renderMode_ = currentMode; + MixerService::GetInstance()->SetRenderMode(currentMode); + } + + View::EnableNotification(); } ; void ProjectView::Update(Observable &,I_ObservableData *data) { @@ -243,11 +279,11 @@ void ProjectView::Update(Observable &,I_ObservableData *data) { # ifdef _64BIT int fourcc=*((int*)data); #else - int fourcc=(unsigned int)data ; + int fourcc = (unsigned int)data; #endif - UIField *focus=GetFocus() ; - if (fourcc!=ACTION_TEMPO_CHANGED) { + UIField *focus = GetFocus(); + if (fourcc!= ACTION_TEMPO_CHANGED) { focus->ClearFocus() ; focus->Draw(w_) ; w_.Flush() ; @@ -267,6 +303,7 @@ void ProjectView::Update(Observable &,I_ObservableData *data) { break ; } case ACTION_SAVE: { + MixerService::GetInstance()->SetRenderMode(0); PersistencyService *service = PersistencyService::GetInstance(); service->Save(); break; diff --git a/sources/Application/Views/ProjectView.h b/sources/Application/Views/ProjectView.h index 1f9474cf..352a28e4 100644 --- a/sources/Application/Views/ProjectView.h +++ b/sources/Application/Views/ProjectView.h @@ -27,10 +27,10 @@ class ProjectView: public FieldView,public I_Observer { protected: private: - Project *project_ ; -// Debug - unsigned long lastTick_ ; - unsigned long lastClock_ ; - UIField *tempoField_ ; + Project *project_; + // Debug + unsigned long lastTick_; + unsigned long lastClock_; + UIField *tempoField_; } ; #endif diff --git a/sources/Application/Views/SongView.cpp b/sources/Application/Views/SongView.cpp index e184195a..39c8a59d 100644 --- a/sources/Application/Views/SongView.cpp +++ b/sources/Application/Views/SongView.cpp @@ -1,5 +1,7 @@ #include "SongView.h" #include "Application/Commands/ApplicationCommandDispatcher.h" +#include "Application/Mixer/MixerService.h" +#include "Application/Model/ProjectDatas.h" #include "Application/Player/Player.h" #include "Application/Utils/char.h" #include "System/Console/Trace.h" @@ -485,6 +487,14 @@ void SongView::onStart() { from = r.Left(); to = r.Right(); } + int renderMode = viewData_->renderMode_; + if (renderMode > 0 && !player->IsRunning()) { + viewData_->isRendering_ = true; + View::SetNotification("Rendering started!"); + } else if (viewData_->isRendering_ && player->IsRunning()) { + viewData_->isRendering_ = false; + View::SetNotification("Rendering done!"); + } player->OnSongStartButton(from, to, false, false); }; @@ -511,6 +521,7 @@ void SongView::onStop() { from = r.Left(); to = r.Right(); } + player->OnSongStartButton(from, to, true, false); }; diff --git a/sources/Application/Views/ViewData.cpp b/sources/Application/Views/ViewData.cpp index 11376496..f4dca9ff 100644 --- a/sources/Application/Views/ViewData.cpp +++ b/sources/Application/Views/ViewData.cpp @@ -17,6 +17,8 @@ ViewData::ViewData(Project *project) { currentGroove_=0 ; mixerCol_=0 ; mixerRow_=0 ; + renderMode_ = 0; + isRendering_ = false; } ; ViewData::~ViewData() { diff --git a/sources/Application/Views/ViewData.h b/sources/Application/Views/ViewData.h index 08da6f19..26be7b9d 100644 --- a/sources/Application/Views/ViewData.h +++ b/sources/Application/Views/ViewData.h @@ -74,6 +74,12 @@ class ViewData { int mixerCol_ ; // int mixerRow_ ; + + // Render Settings + + int renderMode_ ; // Current render mode (0=audio, 1=mixdown, 2=split) + bool isRendering_ ; // True when actively rendering (playing with mode > 0) + // Player Settings PlayMode playMode_ ; From 4fa3aa9238e72a711b04a493821d23e40f9d9ef5 Mon Sep 17 00:00:00 2001 From: djdiskmachine Date: Sat, 27 Dec 2025 17:02:16 +0100 Subject: [PATCH 29/38] QWERTY keyboard on new project Pressing A + up on character selection in new project enters qwerty keyboard mode. --- CHANGELOG | 10 + docs/wiki/What-is-LittlePiggyTracker.md | 20 +- docs/wiki/tips_and_tricks.md | 17 + projects/lgpt.vcxproj | 1 + projects/lgptest.dev | 11 +- sources/Application/Model/Project.h | 15 +- sources/Application/Utils/KeyboardLayout.h | 100 +++++ .../Views/ModalDialogs/NewProjectDialog.cpp | 375 ++++++++++++------ .../Views/ModalDialogs/NewProjectDialog.h | 8 +- 9 files changed, 431 insertions(+), 126 deletions(-) create mode 100644 sources/Application/Utils/KeyboardLayout.h diff --git a/CHANGELOG b/CHANGELOG index 085828a3..8fd20f48 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,13 @@ +1.6.0-bacon4 + QWERTY keyboard name entry for new projects + * Press A on the project name field to enter QWERTY keyboard mode + * Navigate the on-screen keyboard with D-PAD/arrows + * Press A to input the selected character + * Press B to backspace + * Press L/R to move the text cursor left/right + * Press START or select OK to exit keyboard mode + * All keyboard navigation logic extracted to reusable KeyboardLayout.h utility + 1.6.0-bacon2 ProjectView Render item When in project view, it's now possible to initiate rendering diff --git a/docs/wiki/What-is-LittlePiggyTracker.md b/docs/wiki/What-is-LittlePiggyTracker.md index ff297ffa..ae2b04a5 100644 --- a/docs/wiki/What-is-LittlePiggyTracker.md +++ b/docs/wiki/What-is-LittlePiggyTracker.md @@ -51,8 +51,24 @@ After that you can copy additional wavs to the lgptRoot/lgptProject/samples dire ## New project -When creating a new project, use the Random button to generate a random name. Generate a new name with Random or edit it manually selecting characters with A and pressing up/down -Attempting to create a project with the same name in the same location produces a notification that this operation is denied +When creating a new project, you have several options for naming: + +**Random Name Generation:** +- Select the "Random" button and press A to generate a random name + +**QWERTY Keyboard Entry:** +- Move to the name field and press A to enter QWERTY keyboard mode +- An on-screen keyboard will appear with these controls: + - **D-PAD/Arrows:** Navigate the keyboard + - **A:** Input the selected character + - **B:** Backspace (delete character) + - **L/R:** Move the text cursor left/right within your project name + - **START or OK key:** Exit keyboard mode and return to the dialog +- The keyboard includes: + - Numbers (0-9) + - Uppercase and lowercase letters (A-Z, a-z) + - Special characters (@ | - _ < > ? ,) + - Space bar, backspace, and OK (done) buttons on the bottom row ## Multiple Projects diff --git a/docs/wiki/tips_and_tricks.md b/docs/wiki/tips_and_tricks.md index 470e2a87..15d84b16 100644 --- a/docs/wiki/tips_and_tricks.md +++ b/docs/wiki/tips_and_tricks.md @@ -1,3 +1,20 @@ +# Project Naming with QWERTY Keyboard + +Since version 1.6.0, you can use an on-screen QWERTY keyboard when creating new projects: + +**Quick Tips:** +- Press A on the project name to enter keyboard mode +- The keyboard cursor will jump to the character under your text cursor unless it's a space +- Use L/R shoulder buttons to move through your project name +- Erase with B and exit with Start + +**Keyboard Layout:** +The on-screen keyboard is organized like this: +- Numbers +- Uppercase (A-Q + extra characters) +- Lowercase (a-q + extra characters) +- Special [Space] [Erase] [Done] + # Delays and Echoes ## Simulating LSDj's D command diff --git a/projects/lgpt.vcxproj b/projects/lgpt.vcxproj index e6f588df..24ee5329 100644 --- a/projects/lgpt.vcxproj +++ b/projects/lgpt.vcxproj @@ -440,6 +440,7 @@ + diff --git a/projects/lgptest.dev b/projects/lgptest.dev index e877c121..e3e0ef5b 100644 --- a/projects/lgptest.dev +++ b/projects/lgptest.dev @@ -2937,7 +2937,6 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= - [Unit288] FileName=..\sources\Application\utils\RandomNames.h CompileCpp=1 @@ -2948,3 +2947,13 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= +[Unit289] +FileName=..\sources\Application\utils\KeyboardLayout.h +CompileCpp=1 +Folder=Application/Utils +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + diff --git a/sources/Application/Model/Project.h b/sources/Application/Model/Project.h index 09ee605b..f2336228 100644 --- a/sources/Application/Model/Project.h +++ b/sources/Application/Model/Project.h @@ -21,7 +21,7 @@ #define PROJECT_NUMBER "1" #define PROJECT_RELEASE "6" -#define BUILD_COUNT "0-bacon2" +#define BUILD_COUNT "0-bacon4" #define MAX_TAP 3 @@ -61,12 +61,11 @@ class Project: public Persistent,public VariableContainer,I_Observer { void buildMidiDeviceList(); private: - InstrumentBank *instrumentBank_ ; - char **midiDeviceList_ ; - int midiDeviceListSize_ ; - int tempoNudge_ ; - unsigned long lastTap_[MAX_TAP] ; - unsigned int tempoTapCount_; + InstrumentBank *instrumentBank_; + char **midiDeviceList_; + int midiDeviceListSize_; + int tempoNudge_; + unsigned long lastTap_[MAX_TAP]; + unsigned int tempoTapCount_; }; - #endif diff --git a/sources/Application/Utils/KeyboardLayout.h b/sources/Application/Utils/KeyboardLayout.h new file mode 100644 index 00000000..c260c1cc --- /dev/null +++ b/sources/Application/Utils/KeyboardLayout.h @@ -0,0 +1,100 @@ +#ifndef _KEYBOARD_LAYOUT_H_ +#define _KEYBOARD_LAYOUT_H_ + +#include + +// Keyboard layout configuration +#define SPACE_ROW 7 +#define KEYBOARD_ROWS (SPACE_ROW + 1) + +#define SPCE_START 0 +#define SPCE_END 3 +#define BACK_START 4 +#define BACK_END 6 +#define DONE_START 8 +#define DONE_END 10 + +static const char* keyboardLayout[] = { + "1234567890", + "QWERTYUIOP", + "ASDFGHJKL@", + "ZXCVBNM,?>", + "qwertyuiop", + "asdfghjkl|", + "zxcvbnm-_<", + "[_] <- OK" +}; + +// Helper functions for special row section detection +inline bool isInSpaceSection(int col) { return col < SPCE_END; } +inline bool isInBackSection(int col) { return col >= BACK_START && col < BACK_END; } +inline bool isInDoneSection(int col) { return col >= DONE_START; } + +// Get the character at a specific keyboard position +inline char getKeyAtPosition(int row, int col) { + if (row < 0 || row >= KEYBOARD_ROWS) return '\0'; + const char* rowStr = keyboardLayout[row]; + + // Handle special row with SPC, BACK, and DONE + if (row == SPACE_ROW) { + if (col >= 0 && col < SPCE_END) return ' '; // [_] (space) + if (col >= BACK_START && col < BACK_END) return '\b'; // <- (backspace) + if (col >= DONE_START && col < DONE_END) return '\r'; // OK (carriage return) + return '\0'; + } + + int len = strlen(rowStr); + if (col < 0 || col >= len) return '\0'; + return rowStr[col]; +} + +// Find a character's position in the keyboard layout +inline void findCharacterInKeyboard(char ch, int &outRow, int &outCol) { + if (ch == ' ') return; // Skip space character + + // Search for character in keyboard layout (excluding special row) + for (int row = 0; row < SPACE_ROW; row++) { + const char* rowStr = keyboardLayout[row]; + int len = strlen(rowStr); + for (int col = 0; col < len; col++) { + if (rowStr[col] == ch) { + outRow = row; + outCol = col; + return; + } + } + } + // Character not found, don't change position +} + +// Clamp keyboard column to valid range for current row +inline void clampKeyboardColumn(int row, int& col) { + if (row == SPACE_ROW) { + if (col < SPCE_END) col = SPCE_START; + else if (col <= BACK_END) col = BACK_START; + else col = DONE_START; + } else { + int maxCol = strlen(keyboardLayout[row]) - 1; + if (col > maxCol) col = 0; + } +} + +// Cycle keyboard column left (-1) or right (+1) within current row +inline void cycleKeyboardColumn(int row, int direction, int& col) { + if (row == SPACE_ROW) { + if (direction < 0) { // LEFT + if (isInSpaceSection(col)) col = DONE_START; + else if (isInBackSection(col)) col = SPCE_START; + else col = BACK_START; + } else { // RIGHT + if (isInBackSection(col)) col = DONE_START; + else if (isInDoneSection(col)) col = SPCE_START; + else col = BACK_START; + } + } else { + int maxCol = strlen(keyboardLayout[row]) - 1; + col = (col + direction + maxCol + 1) % (maxCol + 1); + } +} + +#endif diff --git a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp index 132a63ca..48366734 100644 --- a/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp +++ b/sources/Application/Views/ModalDialogs/NewProjectDialog.cpp @@ -1,5 +1,6 @@ #include "NewProjectDialog.h" +#include "Application/Utils/KeyboardLayout.h" #include "Application/Utils/RandomNames.h" static char *buttonText[BUTTONS_LENGTH] = {(char *)"Random", (char *)"Ok", @@ -12,39 +13,87 @@ NewProjectDialog::NewProjectDialog(View &view, Path currentPath) NewProjectDialog::~NewProjectDialog() {} +// Move text cursor left (-1) or right (+1) and update keyboard position +void NewProjectDialog::moveCursor(int direction) { + int newPos = currentChar_ + direction; + if (newPos >= 0 && newPos < MAX_NAME_LENGTH) { + currentChar_ = newPos; + findCharacterInKeyboard(name_[currentChar_], keyboardRow_, keyboardCol_); + } +} + void NewProjectDialog::DrawView() { - SetWindow(DIALOG_WIDTH,5) ; + SetWindow(DIALOG_WIDTH, keyboardMode_ ? 15 : 5); - GUITextProperties props ; + GUITextProperties props; - SetColor(CD_NORMAL) ; + SetColor(CD_NORMAL); // Draw string int x = (DIALOG_WIDTH - MAX_NAME_LENGTH) / 3; char buffer[2]; - buffer[1]=0 ; - for (int i=0;i 0) { + currentChar_--; + name_[currentChar_] = ' '; + } + } else if (ch == '\r') { + // END key: exit keyboard mode (same as START) + keyboardMode_ = false; + isDirty_ = true; + // EndModal(0); + return; + } else if (ch != '\0') { + name_[currentChar_] = ch; + lastChar_ = ch; + if (currentChar_ < MAX_NAME_LENGTH - 1) { + currentChar_++; + findCharacterInKeyboard(name_[currentChar_], keyboardRow_, + keyboardCol_); + } + } + isDirty_ = true; + return; + } else if (mask == EPBM_B) { + // Backspace: delete character and move cursor left + if (currentChar_ > 0) { + currentChar_--; + name_[currentChar_] = ' '; + isDirty_ = true; + } + return; + } else if (mask == EPBM_L) { + // Move cursor left + moveCursor(-1); + isDirty_ = true; + return; + } else if (mask == EPBM_R) { + // Move cursor right + moveCursor(1); + isDirty_ = true; + return; + } else if (mask == EPBM_UP) { + keyboardRow_ = (keyboardRow_ - 1 + KEYBOARD_ROWS) % KEYBOARD_ROWS; + clampKeyboardColumn(keyboardRow_, keyboardCol_); + isDirty_ = true; + return; + } else if (mask == EPBM_DOWN) { + keyboardRow_ = (keyboardRow_ + 1) % KEYBOARD_ROWS; + clampKeyboardColumn(keyboardRow_, keyboardCol_); + isDirty_ = true; + return; + } else if (mask == EPBM_LEFT) { + cycleKeyboardColumn(keyboardRow_, -1, keyboardCol_); + isDirty_ = true; + return; + } else if (mask == EPBM_RIGHT) { + cycleKeyboardColumn(keyboardRow_, 1, keyboardCol_); + isDirty_ = true; + return; + } else if (mask == EPBM_START) { + keyboardMode_ = false; + isDirty_ = true; + return; + } + return; + } else if (mask & EPBM_A) { + if (mask == EPBM_A) { + std::string randomName = ""; + switch (selected_) { + case 0: + // Toggle keyboard mode + keyboardMode_ = !keyboardMode_; + // When entering keyboard mode, jump to current character + if (keyboardMode_) { + findCharacterInKeyboard(name_[currentChar_], keyboardRow_, + keyboardCol_); + } + isDirty_ = true; + break; + case 1: + do { + randomName = getRandomName(); + std::fill(name_ + randomName.length(), + name_ + sizeof(name_) / sizeof(name_[0]), ' '); + strncpy(name_, randomName.c_str(), randomName.length()); + lastChar_ = currentChar_ = randomName.length() - 1; + } while (currentPath_.Descend(GetName()).Exists()); + isDirty_ = true; + break; + case 2: + if (currentPath_.Descend(GetName()).Exists()) { + std::string res("Name " + std::string(name_) + " busy"); + View::SetNotification(res.c_str(), -6); + } else { + EndModal(1); + } + break; + case 3: + EndModal(0); + break; + } + } + if (mask & EPBM_UP) { + name_[currentChar_]+=1; lastChar_=name_[currentChar_] ; isDirty_=true ; - } - if (mask&EPBM_DOWN) { + } + if (mask&EPBM_DOWN) { name_[currentChar_]-=1; lastChar_=name_[currentChar_] ; isDirty_=true ; } - } else { - - // R Modifier - - if (mask & EPBM_R) { - } else { - // No modifier - if (mask == EPBM_UP) { - selected_ = (selected_ == 0) ? 1 : 0; - isDirty_ = true; - } - if (mask == EPBM_DOWN) { - selected_ = (selected_ == 0) ? 1 : 0; - isDirty_ = true; - } - - if (mask == EPBM_LEFT) { - switch (selected_) { - case 0: - if (currentChar_ > 0) - currentChar_--; - break; - case 1: - case 2: - case 3: - if (selected_ > 0) - selected_--; - break; - } - isDirty_ = true; - } - if (mask == EPBM_RIGHT) { - switch (selected_) { - case 0: - if (currentChar_ < MAX_NAME_LENGTH - 1) - currentChar_++; - else - selected_++; - break; - case 1: - case 2: - case 3: - if (selected_ < BUTTONS_LENGTH) - selected_++; - break; - } - isDirty_ = true; - } - } - } + } else { + + // A modifier + if (mask & EPBM_A) { + if (mask == EPBM_A) { + std::string randomName = getRandomName(); + switch (selected_) { + case 0: + if (name_[currentChar_] == ' ') { + name_[currentChar_] = lastChar_; + } + isDirty_ = true; + break; + case 1: + std::fill(name_ + randomName.length(), + name_ + sizeof(name_) / sizeof(name_[0]), ' '); + strncpy(name_, randomName.c_str(), randomName.length()); + lastChar_ = currentChar_ = randomName.length() - 1; + isDirty_ = true; + break; + case 2: + EndModal(1); + break; + case 3: + EndModal(0); + break; + } + } + } else { + + // R Modifier + + if (mask & EPBM_R) { + } else { + // No modifier + if (mask == EPBM_UP) { + selected_ = (selected_ == 0) ? 1 : 0; + isDirty_ = true; + } + if (mask == EPBM_DOWN) { + selected_ = (selected_ == 0) ? 1 : 0; + isDirty_ = true; + } + + if (mask == EPBM_LEFT) { + switch (selected_) { + case 0: + if (currentChar_ > 0) + currentChar_--; + break; + case 1: + case 2: + case 3: + if (selected_ > 0) + selected_--; + break; + } + isDirty_ = true; + } + if (mask == EPBM_RIGHT) { + switch (selected_) { + case 0: + if (currentChar_ < MAX_NAME_LENGTH - 1) + currentChar_++; + else + selected_++; + break; + case 1: + case 2: + case 3: + if (selected_ < BUTTONS_LENGTH) + selected_++; + break; + } + isDirty_ = true; + } + } + } } }; - std::string NewProjectDialog::GetName() { for (int i = MAX_NAME_LENGTH; i >= 0; i--) { if (name_[i]==' ') { diff --git a/sources/Application/Views/ModalDialogs/NewProjectDialog.h b/sources/Application/Views/ModalDialogs/NewProjectDialog.h index 457f8692..917e2953 100644 --- a/sources/Application/Views/ModalDialogs/NewProjectDialog.h +++ b/sources/Application/Views/ModalDialogs/NewProjectDialog.h @@ -1,6 +1,7 @@ #ifndef _NEW_PROJECT_DIALOG_H_ #define _NEW_PROJECT_DIALOG_H_ +#include "Application/Utils/KeyboardLayout.h" #include "Application/Views/BaseClasses/ModalView.h" #include @@ -25,6 +26,9 @@ class NewProjectDialog:public ModalView { int lastChar_; char name_[MAX_NAME_LENGTH + 1]; int currentChar_; -} ; - + bool keyboardMode_; + int keyboardRow_; + int keyboardCol_ ; + void moveCursor(int direction); +}; #endif From e0c34ff454d5bd3b3117972f7a614cb2efb8a700 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Fri, 17 Apr 2026 05:36:21 +0000 Subject: [PATCH 30/38] Package libav deps with GARLIC Extract files from Docker Update Package and Launch scripts --- .github/workflows/build.yml | 2 ++ projects/resources/GARLIC/LittleGPTracker.sh | 8 +++++++- projects/resources/packaging/lgpt_package.sh | 3 +++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 24765019..a8ab46c7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -329,6 +329,8 @@ jobs: apt update && apt install -y python3 python3-pillow cd projects make PLATFORM=GARLIC + # copy libav deps to the .zip + mkdir lib && find /usr/lib -name "*libav*so*" -type f -exec cp {} lib/ \; ' sudo chmod -R 777 ./workspace/projects sudo chown -R root:root ./workspace/projects diff --git a/projects/resources/GARLIC/LittleGPTracker.sh b/projects/resources/GARLIC/LittleGPTracker.sh index 51487a14..56d5d95e 100644 --- a/projects/resources/GARLIC/LittleGPTracker.sh +++ b/projects/resources/GARLIC/LittleGPTracker.sh @@ -1,6 +1,12 @@ #!/bin/sh +# Check if libav dependency is installed +# Install it if not +if [ ! -f /usr/lib/libavutil.so ]; then + cp lib/*so* /usr/lib/ &> lgpt.log +fi + progdir=$(dirname "$0")/lgpt cd $progdir HOME=$progdir -LD_PRELOAD=./j2k.so ./lgpt-rg35xx.elf &> log.txt +LD_PRELOAD=./j2k.so ./lgpt-rg35xx.elf &> lgpt.log sync diff --git a/projects/resources/packaging/lgpt_package.sh b/projects/resources/packaging/lgpt_package.sh index f154c116..3be915da 100755 --- a/projects/resources/packaging/lgpt_package.sh +++ b/projects/resources/packaging/lgpt_package.sh @@ -19,6 +19,9 @@ collect_resources() { #1PLATFORM #2lgpt.*-exe CONTENTS="./resources/$1/*" CONTENTS+=" ./custom_font.xml" CONTENTS+=" $BINARY" + if [ -d lib ]; then + CONTENTS+=" lib/" # Used for libav and other dependencies + fi if [ "$1" == "PSP" ] || [ "$1" == "GARLIC" ] || [ "$1" == "RG35XXPLUS" ] || From 1140f87e620d6f7acd1d0ed2a962015133f6f9e6 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Fri, 17 Apr 2026 12:28:32 +0000 Subject: [PATCH 31/38] Fix deps path --- .github/workflows/build.yml | 2 ++ projects/resources/packaging/lgpt_package.sh | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a8ab46c7..bad732dc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -330,7 +330,9 @@ jobs: cd projects make PLATFORM=GARLIC # copy libav deps to the .zip + echo copy files from usr/lib to lib mkdir lib && find /usr/lib -name "*libav*so*" -type f -exec cp {} lib/ \; + ls -la lib ' sudo chmod -R 777 ./workspace/projects sudo chown -R root:root ./workspace/projects diff --git a/projects/resources/packaging/lgpt_package.sh b/projects/resources/packaging/lgpt_package.sh index 3be915da..79a078c5 100755 --- a/projects/resources/packaging/lgpt_package.sh +++ b/projects/resources/packaging/lgpt_package.sh @@ -19,9 +19,6 @@ collect_resources() { #1PLATFORM #2lgpt.*-exe CONTENTS="./resources/$1/*" CONTENTS+=" ./custom_font.xml" CONTENTS+=" $BINARY" - if [ -d lib ]; then - CONTENTS+=" lib/" # Used for libav and other dependencies - fi if [ "$1" == "PSP" ] || [ "$1" == "GARLIC" ] || [ "$1" == "RG35XXPLUS" ] || @@ -38,6 +35,7 @@ collect_resources() { #1PLATFORM #2lgpt.*-exe CONTENTS="../../../README.md ../../../CHANGELOG ../../../LICENSE" CONTENTS+=" $(find . -name "samplelib" -type d)" CONTENTS+=" $(find . -name "lgpt_*" -type d)" + [ -d ../../lib ] && CONTENTS+=" ../../lib" zip -9 -r ../../$PACKAGE $CONTENTS CONTENTS="../../../docs/wiki/What-is-LittlePiggyTracker.md" CONTENTS+=" ../../../docs/wiki/config_xml.md" From cbfa1f7a829e32a726f5c689978f146b65172523 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Fri, 17 Apr 2026 13:44:16 +0000 Subject: [PATCH 32/38] Fix check job --- .github/workflows/check.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 69b79899..5115a154 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -266,9 +266,13 @@ jobs: wget -qO ./debian-archive-keyring.deb "$BASE$LATEST" dpkg -i ./debian-archive-keyring.deb - apt update && apt install -y python3 python3-pillow + apt update && apt install -y python3 python3-pillow cd projects make PLATFORM=GARLIC + # copy libav deps to the .zip + echo copy files from usr/lib to lib + mkdir lib && find /usr/lib -name "*libav*so*" -type f -exec cp {} lib/ \; + ls -la lib ' sudo chmod -R 777 ./workspace/projects sudo chown -R root:root ./workspace/projects From cfdad49d7ca7f6f4344efe0f2bca3d54b5950198 Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Fri, 17 Apr 2026 15:51:23 +0000 Subject: [PATCH 33/38] Grab .so files from the right place --- .github/workflows/build.yml | 2 +- .github/workflows/check.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bad732dc..9885e48a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -331,7 +331,7 @@ jobs: make PLATFORM=GARLIC # copy libav deps to the .zip echo copy files from usr/lib to lib - mkdir lib && find /usr/lib -name "*libav*so*" -type f -exec cp {} lib/ \; + mkdir lib && find /opt/miyoo/ -name "*libav*so*" -type f -exec cp {} lib/ \; ls -la lib ' sudo chmod -R 777 ./workspace/projects diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 5115a154..df1d85de 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -271,7 +271,7 @@ jobs: make PLATFORM=GARLIC # copy libav deps to the .zip echo copy files from usr/lib to lib - mkdir lib && find /usr/lib -name "*libav*so*" -type f -exec cp {} lib/ \; + mkdir lib && find /opt/miyoo/ -name "*libav*so*" -type f -exec cp {} lib/ \; ls -la lib ' sudo chmod -R 777 ./workspace/projects From 4ca754a3b5feb062ff25990e8c11012b739a99df Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Fri, 17 Apr 2026 15:59:29 +0000 Subject: [PATCH 34/38] Copy symlinks as well --- .github/workflows/build.yml | 2 +- .github/workflows/check.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9885e48a..5997209c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -331,7 +331,7 @@ jobs: make PLATFORM=GARLIC # copy libav deps to the .zip echo copy files from usr/lib to lib - mkdir lib && find /opt/miyoo/ -name "*libav*so*" -type f -exec cp {} lib/ \; + mkdir lib && find /opt/miyoo -name "*libav*so*" -exec cp -P {} lib/ \; ls -la lib ' sudo chmod -R 777 ./workspace/projects diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index df1d85de..af47032a 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -271,7 +271,7 @@ jobs: make PLATFORM=GARLIC # copy libav deps to the .zip echo copy files from usr/lib to lib - mkdir lib && find /opt/miyoo/ -name "*libav*so*" -type f -exec cp {} lib/ \; + mkdir lib && find /opt/miyoo -name "*libav*so*" -exec cp -P {} lib/ \; ls -la lib ' sudo chmod -R 777 ./workspace/projects From 1f93efb21fe17b8fdfdd92c8e78654f6f8dad9aa Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:20:35 +0000 Subject: [PATCH 35/38] Don't copyu --- projects/resources/GARLIC/LittleGPTracker.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/projects/resources/GARLIC/LittleGPTracker.sh b/projects/resources/GARLIC/LittleGPTracker.sh index 56d5d95e..46ca36d3 100644 --- a/projects/resources/GARLIC/LittleGPTracker.sh +++ b/projects/resources/GARLIC/LittleGPTracker.sh @@ -8,5 +8,6 @@ fi progdir=$(dirname "$0")/lgpt cd $progdir HOME=$progdir +export LD_LIBRARY_PATH=$progdir/lib:$LD_LIBRARY_PATH LD_PRELOAD=./j2k.so ./lgpt-rg35xx.elf &> lgpt.log sync From 05b7a12c3730c48f6a2b7d77a6fd0ffbe022ec2c Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:21:15 +0000 Subject: [PATCH 36/38] LD_PRELOAD instead of copy --- projects/resources/GARLIC/LittleGPTracker.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/projects/resources/GARLIC/LittleGPTracker.sh b/projects/resources/GARLIC/LittleGPTracker.sh index 46ca36d3..843321e4 100644 --- a/projects/resources/GARLIC/LittleGPTracker.sh +++ b/projects/resources/GARLIC/LittleGPTracker.sh @@ -1,10 +1,4 @@ #!/bin/sh -# Check if libav dependency is installed -# Install it if not -if [ ! -f /usr/lib/libavutil.so ]; then - cp lib/*so* /usr/lib/ &> lgpt.log -fi - progdir=$(dirname "$0")/lgpt cd $progdir HOME=$progdir From 6226a53a05c11090ab6c75dca06f63469df7ad6d Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Sat, 18 Apr 2026 10:39:00 +0000 Subject: [PATCH 37/38] Preserve symlinks without relative paths --- projects/Makefile | 2 +- projects/resources/GARLIC/LittleGPTracker.sh | 2 +- projects/resources/packaging/lgpt_package.sh | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/projects/Makefile b/projects/Makefile index 4bed97eb..7e0d3d5b 100644 --- a/projects/Makefile +++ b/projects/Makefile @@ -519,7 +519,7 @@ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) #--------------------------------------------------------------------------------- $(BUILD): - python3 ../sources/Resources/mkfont.py ../sources/Resources/$(FONT) ../sources/Resources/font.h +# python3 ../sources/Resources/mkfont.py ../sources/Resources/$(FONT) ../sources/Resources/font.h @[ -d $@ ] || mkdir -p $@ @make --no-print-directory -C $(BUILD) -f $(PWD)/Makefile diff --git a/projects/resources/GARLIC/LittleGPTracker.sh b/projects/resources/GARLIC/LittleGPTracker.sh index 843321e4..2fcd5602 100644 --- a/projects/resources/GARLIC/LittleGPTracker.sh +++ b/projects/resources/GARLIC/LittleGPTracker.sh @@ -3,5 +3,5 @@ progdir=$(dirname "$0")/lgpt cd $progdir HOME=$progdir export LD_LIBRARY_PATH=$progdir/lib:$LD_LIBRARY_PATH -LD_PRELOAD=./j2k.so ./lgpt-rg35xx.elf &> lgpt.log +LD_PRELOAD=./j2k.so ./lgpt-garlic.elf &> lgpt.log sync diff --git a/projects/resources/packaging/lgpt_package.sh b/projects/resources/packaging/lgpt_package.sh index 79a078c5..c6fd8a99 100755 --- a/projects/resources/packaging/lgpt_package.sh +++ b/projects/resources/packaging/lgpt_package.sh @@ -35,13 +35,14 @@ collect_resources() { #1PLATFORM #2lgpt.*-exe CONTENTS="../../../README.md ../../../CHANGELOG ../../../LICENSE" CONTENTS+=" $(find . -name "samplelib" -type d)" CONTENTS+=" $(find . -name "lgpt_*" -type d)" - [ -d ../../lib ] && CONTENTS+=" ../../lib" zip -9 -r ../../$PACKAGE $CONTENTS CONTENTS="../../../docs/wiki/What-is-LittlePiggyTracker.md" CONTENTS+=" ../../../docs/wiki/config_xml.md" CONTENTS+=" ../../../docs/wiki/tips_and_tricks.md" CONTENTS+=" ../$1/*.txt" - zip -9 ../../$PACKAGE -jq $CONTENTS && cd - + zip -9 ../../$PACKAGE -jq $CONTENTS + [ -d ../../lib ] && cd ../.. && zip -9 -r -y $PACKAGE lib && cd - + cd - } collect_resources PSP EBOOT.PBP From 12ddf016a095643a503ba44de3c61d980f10e2ff Mon Sep 17 00:00:00 2001 From: djdiskmachine <110535302+djdiskmachine@users.noreply.github.com> Date: Wed, 22 Apr 2026 17:53:26 +0000 Subject: [PATCH 38/38] Remove GARLIC ffmpeg support Update README and Makefile --- README.md | 3 ++- projects/Makefile.GARLIC | 10 ++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 1958d0c1..3b3a3899 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,8 @@ Recommended reading to get you started: | RASPI | YES | YES | YES | YES | Versatile platform | | CHIP | YES | YES | YES | YES | [See notes](projects/resources/CHIP/INSTALL_HOW_TO.txt) | | BITTBOY | MAYBE | NO | YES | YES | | -| GARLIC | MAYBE | NO | YES | YES | Port by [Simotek](http://simotek.net)| +| PORTMASTER | MAYBE | NO | YES | YES | | +| GARLIC | MAYBE | NO | YES | NO | Port by [Simotek](http://simotek.net)| | GARLICPLUS | MAYBE | NO | YES | YES | Port by [Simotek](http://simotek.net)| | RG35XXPLUS | MAYBE | NO | YES | NO | Port by [Simotek](http://simotek.net)| | MACOS | YES | YES | MAYBE | NO | Port by [clsource](https://genserver.social/clsource) | diff --git a/projects/Makefile.GARLIC b/projects/Makefile.GARLIC index 63fa2393..0ac24c9e 100644 --- a/projects/Makefile.GARLIC +++ b/projects/Makefile.GARLIC @@ -6,8 +6,6 @@ DEFINES := \ -DCPP_MEMORY \ -D_NDEBUG \ -DHAVE_STDINT_H \ - -DFFMPEG_ENABLED \ - -DFFMPEG_LEGACY_API \ -D_NO_JACK_ DEVKIT = /opt/miyoo/ @@ -26,12 +24,12 @@ SDL_LIBS := $(shell $(SYSROOT)/usr/bin/sdl-config --libs) # optimization OPT_FLAGS = -O3 -Ofast -fdata-sections -fdata-sections -fno-common -fno-PIC -flto -marm -mtune=cortex-a53 -mfpu=neon-vfpv4 -mfloat-abi=hard PREFIX := arm-linux-gnueabihf- -INCLUDES:= -Iinclude $(SDL_CFLAGS) $(FFMPEG_CFLAGS) -I$(PWD)/../sources +INCLUDES:= -Iinclude $(SDL_CFLAGS) -I$(PWD)/../sources CFLAGS := $(DEFINES) $(INCLUDES) $(OPT_FLAGS) -Wall CXXFLAGS:= $(CFLAGS) -std=gnu++03 -LIBS := $(SDL_LIBS) $(FFMPEG_LIBS) -lpthread -LIBDIRS := $(DEKVIT)/usr/lib -LIBDIRS += $(DEKVIT)/usr/include +LIBS := $(SDL_LIBS) -lpthread +LIBDIRS := $(DEVKIT)/usr/lib +LIBDIRS += $(DEVKIT)/usr/include OUTPUT := ../lgpt-garlic EXTENSION:= elf