view ringtools/imy/firstpass.c @ 909:1e9fe07f8f09

doc/Voice-memo-utils: new article
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 29 Dec 2022 21:03:11 +0000
parents 0d6814238109
children
line wrap: on
line source

/*
 * This module implements the first pass of fc-imy2pwt processing:
 * reading and parsing the iMelody input file at the level of lines,
 * storing the melody for subsequent processing and catching the
 * optional BEAT: line, if present.
 */

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "sizelimits.h"

extern char *imy_filename;
extern char melody_str_buf[MELODY_BUF_SIZE];
extern unsigned beats_per_min;

static char *melody_write_ptr, *melody_write_endp;
static int lineno;

static void
copy_melody_str(line)
	char *line;
{
	char *cp, *np;

	cp = line;
	while (isspace(*cp))
		cp++;
	if (!*cp) {
		fprintf(stderr, "%s line %d: empty melody line\n",
			imy_filename, lineno);
		exit(1);
	}
	for (np = cp; *cp && !isspace(*cp); cp++)
		;
	if (*cp)
		*cp++ = '\0';
	while (isspace(*cp))
		cp++;
	if (*cp) {
		fprintf(stderr, "%s line %d: single melody string expected\n",
			imy_filename, lineno);
		exit(1);
	}
	if (strlen(np) > (melody_write_endp - melody_write_ptr)) {
		fprintf(stderr, "%s line %d: melody buffer size exceeded\n",
			imy_filename, lineno);
		exit(1);
	}
	strcpy(melody_write_ptr, np);
	melody_write_ptr += strlen(np);
}

static void
process_beat_line(line)
	char *line;
{
	if (!isdigit(*line)) {
		fprintf(stderr, "%s line %d: number expected on BEAT: line\n",
			imy_filename, lineno);
		exit(1);
	}
	beats_per_min = atoi(line);
	if (beats_per_min < 25 || beats_per_min > 900) {
		fprintf(stderr, "%s line %d: bpm number is out of range\n",
			imy_filename, lineno);
		exit(1);
	}
}

read_imy_firstpass()
{
	FILE *inf;
	char linebuf[LINE_BUF_SIZE];
	int prev_line_is_melody;

	inf = fopen(imy_filename, "r");
	if (!inf) {
		perror(imy_filename);
		exit(1);
	}
	melody_write_ptr = melody_str_buf;
	melody_write_endp = melody_str_buf + MELODY_BUF_SIZE - 1;
	for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) {
		if (!index(linebuf, '\n')) {
			fprintf(stderr,
				"%s line %d: too long or unterminated\n",
				imy_filename, lineno);
			exit(1);
		}
		if (linebuf[0] == ' ' || linebuf[0] == '\t') {
			if (lineno == 1) {
				fprintf(stderr,
					"%s line 1: invalid continuation\n",
					imy_filename);
				exit(1);
			}
			if (prev_line_is_melody)
				copy_melody_str(linebuf);
			continue;
		}
		if (!strncasecmp(linebuf, "MELODY:", 7)) {
			copy_melody_str(linebuf + 7);
			prev_line_is_melody = 1;
		} else if (!strncasecmp(linebuf, "BEAT:", 5)) {
			process_beat_line(linebuf + 5);
			prev_line_is_melody = 0;
		} else if (!strncasecmp(linebuf, "END:IMELODY", 11))
			break;
		else
			prev_line_is_melody = 0;
	}
	fclose(inf);
	if (!melody_str_buf[0]) {
		fprintf(stderr, "error: no melody found in %s\n", imy_filename);
		exit(1);
	}
}