mirror of
https://github.com/sshlien/abcmidi.git
synced 2026-05-30 11:59:29 +00:00
Add missing C: (composer), R: (rhythm) and X: fields and return error (#21)
* Add configuration for CMake build system alongside autoconf - Add a modern CMake build system (`CMakeLists.txt`, `CMakePresets.json`) that coexists with the legacy autoconf/Makefile build - Shared source files (`midifile.c`, `parseabc.c`, `music_utils.c`, `parser2.c`) are compiled once via OBJECT libraries and linked into the 8 binaries - Three presets: `default` (Release), `debug`, `sanitize` (ASan + UBSan) - Generates `compile_commands.json` for clangd/LSP editor support - Install rules match the legacy Makefile (binaries, doc files, man pages) - Pinned to `-std=gnu89` because the codebase mixes K&R `()` and ANSI typed prototypes — in C23/gnu23 (GCC 15+ default), `()` means `(void)`, making these a hard error. Note: **the existing autoconf build is also broken with GCC 15** for the same reason ```sh cmake --preset debug cmake --build --preset debug cmake --install build/debug --prefix /usr/local Documentation - README.md: added Building section with both autoconf and CMake instructions - doc/readme.txt: added build instructions in the existing preamble - doc/CHANGES: added changelog entry Test plan - All 3 presets configure and build with GCC 15 - Smoke test: abc2midi samples/coleraine.abc produces valid MIDI through mftext - Sanitizer build (--preset sanitize) runs clean on sample files - Install layout verified: 8 binaries, 10 doc files, 8 man pages in correct paths - Build on macOS (untested, should work with AppleClang) * Implement basic testing infrastructure The CMake build includes a test suite covering all 8 programs: - **Smoke tests** verify each binary runs cleanly with `-ver`. - **Golden-file tests** run each program on a sample input and compare the (normalized) output to a checked-in reference. Binary MIDI outputs are piped through `mftext` to produce diffable text. Volatile lines (version banners, dates, temporary paths) are stripped before comparison. ```sh ctest --preset debug ctest --preset debug -L golden ctest --preset debug -L smoke ``` To regenerate the golden files after an intentional behavioural change, review the diff, then commit: ```sh cmake --build build/debug --target update-golden git diff tests/golden/ ``` * Factorize more the test CMake code * Add GitHub Action to run the CI and output a status badge * Add GitHub Action workflow dispatch to allow running from the UI * Now abc2midi exits 1 if an error occurs Before it was always returning 0, hiding failures complicated to track in complex build systems. * Output missing C:, R: and X: headers as MIDI text meta-events * Update changelog and comments --------- Co-authored-by: Seymour Shlien <fy733@ncf.ca>
This commit is contained in:
78
.github/workflows/test.yml
vendored
Normal file
78
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
# CI workflow for abcMIDI.
|
||||
#
|
||||
# Runs the CMake-based test suite (smoke + golden-file tests) on every push
|
||||
# and pull request against the long-lived branches, and can also be triggered
|
||||
# manually from the GitHub UI or via `gh workflow run test.yml`.
|
||||
#
|
||||
# Status badge: see the [![Tests]] link at the top of README.md.
|
||||
|
||||
name: Tests
|
||||
|
||||
on:
|
||||
# Run on pushes to the main development branches.
|
||||
push:
|
||||
branches: [master, future]
|
||||
# Run on PRs targeting those same branches.
|
||||
pull_request:
|
||||
branches: [master, future]
|
||||
# Allow manual runs on any branch from the Actions tab or `gh workflow run`.
|
||||
workflow_dispatch:
|
||||
|
||||
# Minimal permissions: the workflow only needs to read the repository contents.
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# One parallel job per tool. GitHub Actions only exposes a single badge
|
||||
# per workflow file, so this matrix produces one aggregate "Tests" badge
|
||||
# but still gives per-tool visibility in the Actions UI and lets a single
|
||||
# tool failure be diagnosed without scrolling through unrelated output.
|
||||
strategy:
|
||||
# Keep running the other tools even if one fails, so a single
|
||||
# regression does not hide unrelated breakage.
|
||||
fail-fast: false
|
||||
matrix:
|
||||
tool:
|
||||
- abc2midi
|
||||
- abc2abc
|
||||
- midi2abc
|
||||
- midistats
|
||||
- mftext
|
||||
- yaps
|
||||
- midicopy
|
||||
- abcmatch
|
||||
|
||||
# Job display name in the Actions UI (e.g. "Tests / abc2midi").
|
||||
name: ${{ matrix.tool }}
|
||||
|
||||
steps:
|
||||
# `persist-credentials: false` avoids leaving a GITHUB_TOKEN in the
|
||||
# local git config — defence in depth against a later step that might
|
||||
# inadvertently push or call the API on our behalf.
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
# Configure with the `default` preset (Release build, see CMakePresets.json).
|
||||
- name: Configure
|
||||
run: cmake --preset default
|
||||
|
||||
# Build every binary. Each matrix job builds the full set rather than
|
||||
# just `${{ matrix.tool }}` because several tools depend on others at
|
||||
# test time: the golden tests for abc2midi / midistats / midicopy pipe
|
||||
# their output through mftext, and midi2abc / midistats / midicopy are
|
||||
# exercised on a MIDI file produced on-the-fly by abc2midi. Building
|
||||
# everything keeps the test dispatch logic in tests/run_test.cmake
|
||||
# simple and matches what a developer runs locally.
|
||||
- name: Build
|
||||
run: cmake --build --preset default
|
||||
|
||||
# Run only the tests relevant to this matrix tool. The regex matches:
|
||||
# - the smoke test smoke_<tool>_ver
|
||||
# - every golden test <tool>_<sample>
|
||||
# (see tests/CMakeLists.txt for the naming convention).
|
||||
- name: Test ${{ matrix.tool }}
|
||||
run: ctest --preset default -R '^(smoke_${{ matrix.tool }}_ver|${{ matrix.tool }}_)'
|
||||
@@ -1,5 +1,7 @@
|
||||
### abcMIDI package
|
||||
|
||||
[](https://github.com/keryell/abcmidi/actions/workflows/test.yml)
|
||||
|
||||
abcMIDI is a package of programs written in C for handling [abc music notation](http://abcnotation.com/) files. The software was created by James Allwright in the early 1990 and presently maintained by Seymour Shlien. It initially included the following programs:
|
||||
|
||||
1. abc2midi for converting an abc file to a midi file,
|
||||
|
||||
18
doc/CHANGES
18
doc/CHANGES
@@ -15686,6 +15686,24 @@ emitted as simple section markers (e.g. "Part A"). The existing code at
|
||||
genmidi.c:3187 that was meant to write markers was unreachable dead code;
|
||||
it has been restructured. Changes in genmidi.c (PART case in writetrack,
|
||||
partmarkers global) and store.c (event_part, event_init for -PMAR flag).
|
||||
|
||||
abc2midi: now exits with status 1 if any errors occur. Previously
|
||||
abc2midi always exited 0 regardless of errors. An error_count global is
|
||||
incremented by event_error() and main() returns 1 when error_count > 0.
|
||||
Changes in store.c (error_count global, event_error, main return value).
|
||||
|
||||
March 31 2026 [RK]
|
||||
|
||||
abc2midi: output missing C: (composer), R: (rhythm) and X: (reference
|
||||
number) headers as MIDI text meta-events (0x01). Previously the C:
|
||||
field was stored as a COMPOSER feature but had no case handler in
|
||||
writetrack(), so composer information was lost. The R: field was only
|
||||
used internally for Hornpipe detection and never stored as a feature.
|
||||
The X: reference number was not stored at all. Changes: added case
|
||||
COMPOSER in genmidi.c writetrack; added textfeature(TEXT, "R:...")
|
||||
in event_field 'R' case in store.c; added textfeature(TEXT, "X:...")
|
||||
in event_refno() in store.c.
|
||||
|
||||
Man page updated in doc/abc2midi.1.
|
||||
|
||||
2026 April 01
|
||||
|
||||
@@ -3168,6 +3168,13 @@ long writetrack(int xtrack)
|
||||
strlen(atext[pitch[j]]));
|
||||
};
|
||||
break;
|
||||
case COMPOSER: /* [RK] 2026-03-31 */
|
||||
if (texton) {
|
||||
char cbuf[300];
|
||||
snprintf(cbuf, sizeof(cbuf), "C:%s", atext[pitch[j]]);
|
||||
mf_write_meta_event(0L, text_event, cbuf, strlen(cbuf));
|
||||
}
|
||||
break;
|
||||
case TITLE:
|
||||
/* Write name of song as sequence name in track 0 and as track 1 name. */
|
||||
/* karaokestarttrack routine handles this instead if tune is a Karaoke tune. */
|
||||
|
||||
18
store.c
18
store.c
@@ -296,6 +296,7 @@ int retuning = 0; /* [SS] 2012-04-01 */
|
||||
int bend = 8192; /* [SS] 2012-04-01 */
|
||||
int comma53 = 0; /* [SS] 2014-01-12 */
|
||||
int silent = 0; /* [SS] 2014-10-16 */
|
||||
int error_count = 0; /* number of errors reported by event_error() [RK] 2026-03-30 */
|
||||
int no_more_free_channels; /* [SS] 2015-03-23 */
|
||||
void init_p48toc53 (); /* [SS] 2014-01-12 */
|
||||
void convert_to_comma53 (char acc, int *midipitch, int* midibend);
|
||||
@@ -1536,6 +1537,7 @@ void event_fatal_error(char *s)
|
||||
void event_error(char *s)
|
||||
/* generic error handler */
|
||||
{
|
||||
error_count++; /* [RK] 2026-03-30 */
|
||||
#ifdef NOFTELL
|
||||
extern int nullpass;
|
||||
|
||||
@@ -2683,7 +2685,8 @@ void event_field(char k, char *f)
|
||||
break;
|
||||
case 'R':
|
||||
{
|
||||
char* p;
|
||||
char* p;
|
||||
char buff[258];
|
||||
p = f;
|
||||
/* strncpy(rhythmdesignator,f,32); [SS] 2011-08-19 */
|
||||
snprintf(rhythmdesignator,sizeof(rhythmdesignator),"%s",f); /* [SEG] 2020-06-04 */
|
||||
@@ -2695,6 +2698,11 @@ void event_field(char k, char *f)
|
||||
ratio_a = 2; /* [SS] 2016-01-02 */
|
||||
ratio_b = 4;
|
||||
};
|
||||
/* Also store as text feature for MIDI output [RK] 2026-03-31 */
|
||||
if (strlen(f) < 256) {
|
||||
sprintf(buff, "R:%s", f);
|
||||
textfeature(TEXT, buff);
|
||||
}
|
||||
};
|
||||
break;
|
||||
default:
|
||||
@@ -6230,6 +6238,12 @@ void event_refno(int n)
|
||||
/* sprintf(outname, "%s%d.mid", outbase, n); */
|
||||
};
|
||||
startfile();
|
||||
/* Store reference number as text feature for MIDI output [RK] 2026-03-31 */
|
||||
{
|
||||
char xbuf[40];
|
||||
sprintf(xbuf, "X:%d", n);
|
||||
textfeature(TEXT, xbuf);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6278,6 +6292,6 @@ int main(int argc, char *argv[])
|
||||
parsefile(filename);
|
||||
free_abbreviations();
|
||||
};
|
||||
return(0);
|
||||
return(error_count > 0 ? 1 : 0); /* [RK] 2026-03-30 */
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user