If you ask for structure, a look at the task macros may be helpful. They allow to write down independent sequential actions (tasks) in an easy-to-read fashion, in contrast to state machines with large syntactic overhead. In fact the task macros construct a state machine, so the woodoo is only the representation in source code, not any unusual principle behind them.
First you write down the signal tasks. like this:
void signal1() {
beginTask();
taskWaitFor(signalType==1); //wait for global trigger
tone(...);
taskDelay(duration1); //equivalent to delay(), but not blocking other tasks
noTone(...);
if (stopFlag) taskRestart(); //if you really want to abort the currently played signal
taskDelay(duration2);
...
if (stopFlag) {
signalType=0; //no signal active
stopFlag=false; //stop request handled
}
endTask();
}
If you really want to terminate a signal prematurely, in favour of a different signal, you can break out of the sequence at any time, using taskRestart() to restart at beginTask(). But in the case of such signals I'd think that every signal should be finished regularly, not aborted. For that purpose I added the stopFlag handling to the above pattern.
Then create the signal dispatcher:
void dispatch(int type) {
if (signalType != 0 && signalType != type)
stopFlag=true; //abort the currently played signal
else
signalType = type; //start signal playback, 0 for none
}
This piece of code can become part of loop(), no need to wrap it into a function.
Of course it is possible to terminate a signal regularly, by simply setting signalType=0, but this would not give any feedback about the currently (still?) played signal. As is, the signalType is reset only when the current signal has been played completely. Perhaps nicer synchronization can be implemented?
Run the tasks:
#include <ALib0.h> //the task macros and more
int signalType;
bool stopFlag;
void loop() {
//give every task a chance to proceed
signal1();
signal2();
...
//add whatever remains to do, e.g. which signal to play
int signalToPlay = 0;
if (condition1) signalToPlay = 1;
...
dispatch(signalToPlay); //or inline the above code
...
}