Hi, I have a C++ audio project that I done last year. Now I would create a new C++ audio project, that at its first stage will start as an improvement of the past project. The project is a Score-Based Music System, with offline computation and batch processing. For this reason, I am considering the fact to take out the old project and create a mock-up on it because the old project grew without any clear direction related to best practice of design and coding. My idea is to take a piece of code of the old project, delineate all the vulnerabilities that I saw, evaluate the improvements and try to create a mock-up upon it to perform the same piece of code but well-designed. In the following, I would provide you my candidate snippet of code, with some comments, plus the list of relevant issues that I see and a proposal of modification. Then, I will ask to provide a feedback on it, in particular if you see any drawback on my proposal or any particular issue or something that I am clearly missing. Lastly, please consider that it is a mock-up, I am a fan of KISS principle, and that once this analysis will be done I will try to apply the proposal to another snippet of code taken from the old project, to see if it works correctly.
~~~
durGrain = 20000.; // time to be considered
for(auto d=0; d<durGrain; )
{
	const double tIncr = d / static_cast<double>(durGrain); // internal increment

	double before_start = 150.; // base value
	double before_var = -70. * util::halfsine(tIncr); // util is a namespace I use for Utilities and wrapper for mathematical functions
	double dur_start = 80;
	double dur_var = 46.66 * util::sine(tIncr);
	double before = before_start + before_var; // base + variation
	double dur = dur_start + dur_var;

	double freq_start = freq_main; // base "reference" value, declared as static const value outside this snippet
	double freq_var = 0.
	double freq = freq_start + freq_var; // base + variation

	double amp_start = amp_2f; // reference value, declared as static const value outside this snippet
	double amp_var = 0.;
	double amp = amp_start + amp_var; // base  + variation

	itemsSF = myGrain.Calculate_items(before, dur); // myGrain is my synthesizer, here it calculates the number of samples that will be processed

	myGrain.Set_same_freq(freq); // same value are set
	myGrain.Set_same_amp(amp); 
	const double* toBeWritten = myGrain.Compute(); // main Process function, that returns a pointer to double there samples are computed and stored

	successSF = myWriter.Write(toBeWritten, itemsSF); // myWriter is the class that will take the samples and will write them in an external Wave file

	d += before + dur; // temporal increment
}
~
To make this code flexible and modular, I will introduce:
1. A Scorer class, that will read and load parameters from an external score text file, following a syntax like <VariableName> = <Value>;, like "amp = 2f;". Inside it, also a Parser and Tokenizer have to be considered. 
2. A ConfigHandler class, that will be responsible for the mediator pattern.
3. An AudioProcessor interface, that will hold a Process method.
4. An AudioBuffer class, that will hold a vector of double. A simple pool buffering technique will be used.
5. TimeProcessor class, that will hold the main loop over different processing functions and the possibility to resize AudioBuffer if needed.
6. Classes DynamicParameter and StaticParameter, to handle different parameters that can change or not during the loop, plus an ExpressionParameter, to handle cases in which an explicit temporal dependency has to be considered (see before_var, as an example), following a Strategy Pattern. Moreover, a function like evaluateExpression has to be implemented. 
~
Open topics: 
A. I know that they are a lot of topics for just fixing few lines of code, but I do not see anything that I can remove without any clear impact on flexibility and modularity.
B. ConfigHandler implements a mediator pattern, because actually I will keep a fixed pipeline, just a synthesizer that provides samples to a writer. For this reason, I think there is no need for a Chain-of-responsibility pattern, even if inside the score I would provide even the parameter durGrain, that will be needed by TimeProcessor. 
C. I like this unified idea that main classes are Processor, like TimeProcessor and AudioProcessor. This idea underlines the processing-related part.
D. No Pipeline class will be implemented, I will take a fixed and manually-handled pipeline for the mock-up. This will be handled in TimeProcessor main loop.
E. evaluteExpression will be a basic custom implementation, I will not use in the first moment a third-party library. 
F. I do not like to violate the SRP, especially in consideration of TimeProcessor. Indeed, AudioProcessor interface has a very limited scope (only virtual Process() method), while TimeProcessor risks to have a complex, even if small due to the size of the mock-up, interface.
G. AudioBuffer can be resized depending on the some temporal parameter, like in this case "before + dur". I would introduce a dedicated BufferProcessor, however I am stuck while considering that there may be the possibility that these temporal parameters are adjested internally by some AudioProcessor, for example if the AudioProcessor has to allocate a specific time window depending on a zero-crossing algorithm. For this reason, I am considering to specialize AudioProcessor such that only the ResizingAudioProcessor can resize the buffer and removing this responsability to TimeProcessor.