If you use the EastWest Symphonic Choirs or Hollywood Choirs, you may already know that WordBuilder can become unstable when faced with too many or too extreme tempo changes. It can begin to mispronounce syllables or even cause the notes and syllables to get out of synch. If your goal is to create an audio recording of WordBuilder singing a piece with substantial tempo changes, I have written a program that can help keep WordBuilder from becoming unstable.
I used this program to create my video of The Shepherds’ Farewell by Hector Berlioz. In my rendition of this piece, the tempo is almost constantly speeding up or slowing down, so the MIDI file exported from the original project had over 450 tempo changes. When WordBuilder tried to sing the original project with the lyrics, the notes and syllables got out of synch before the end of the first verse.
Description of the program
My program takes a MIDI file with any number of tempo changes and converts it into a MIDI file with a fixed tempo in which the notes are no longer related to measures and beats but start and end at the same elapsed times (to the nearest millisecond) as they did before. After the conversion, WordBuilder should be able to sing the lyrics without becoming unstable because it no longer encounters any tempo changes.
Since Cubase and Dorico use 480 ticks per quarter note, at a fixed tempo of 125 quarter notes per minute, each tick lasts one millisecond, each quarter note lasts 480 milliseconds, one measure in 5/4 time lasts 2.4 seconds and 25 measures last one minute.
How to use the program
MIDI files are stored in a compact binary form which makes them more difficult to modify than text files. To simplify the implementation of my program called adjtime, I use the utilities midicsv and csvmidi to convert MIDI files to and from text files in the comma-separated value (CSV) format.
To use adjtime, start by exporting a MIDI file named src.mid from the source program. It is assumed that src.mid specifies a time signature and an initial tempo at the beginning of the file. Now execute the following sequence of commands:
midicsv src.mid src.txt
adjtime < src.txt > dst.txt
csvmidi dst.txt dst.mid
Finally, import dst.mid into the destination program, which is assumed to use 480 ticks per quarter note.
C source code for the program
I am only providing the source code for my program because I’m not sure the Dorico team would want me to post a link to an executable program which might be capable of doing something malicious.
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct tempo {
struct tempo *link;
long tempo;
long ticks;
long time;
} tempo_t;
char Buffer[BUFSIZ];
int Div;
tempo_t Head = { &Head, 0, LONG_MAX, LONG_MAX };
tempo_t *Node = &Head;
char *Ptr;
void error(char *str)
{
fputs(str, stderr);
fputc('\n', stderr);
exit(EXIT_FAILURE);
}
long gettime(long ticks)
{
if (ticks == 0)
return 0;
while (ticks > Node->link->ticks)
Node = Node->link;
return (double) (ticks - Node->ticks) / Div * Node->tempo + Node->time + 0.5;
}
int main(void)
{
char *ptr;
long ticks;
long time;
int track;
while (gets(Buffer) != NULL) {
track = atoi(Buffer);
ptr = strchr(Buffer, ',') + 1;
ticks = atol(ptr);
time = gettime(ticks);
Ptr = strchr(ptr, ',') + 1;
if (strstr(Ptr, "Header") != NULL) {
ptr = strrchr(Buffer, ',') + 1;
Div = atoi(ptr);
strcpy(ptr, " 480");
}
else if (strstr(Ptr, "Time_signature") != NULL) {
if (ticks != 0)
continue;
ptr = strchr(Ptr, ',') + 1;
strcpy(ptr, " 5, 2, 24, 8");
}
else if (strstr(Ptr, "Tempo") != NULL) {
ptr = strchr(Ptr, ',') + 1;
Node = Node->link = malloc(sizeof(tempo_t));
if (Node == NULL)
error("insufficient memory");
Node->link = &Head;
Node->tempo = atol(ptr);
Node->ticks = ticks;
Node->time = time;
if (ticks != 0)
continue;
strcpy(ptr, " 480000");
}
else if (strstr(Ptr, "End_track") != NULL)
Node = &Head;
printf("%d, %ld,%s\n", track, (time + 500L) / 1000L, Ptr);
}
return EXIT_SUCCESS;
}
For Windows users, the webpage for midicsv and csvmidi contains a link to a zip file containing executable programs for these utilities. For Mac users, this webpage contains a link to a gzip-compressed tar file containing the C source code and a makefile for these utilities.