170 likes | 285 Vues
This document presents a comprehensive overview of leveraging the latest C++ features in music applications, highlighting the ongoing standardization effort that aims to utilize modern programming capabilities for reactive and efficient music software. An example of a second-order resonator is provided, showcasing the implementation of advanced techniques such as parallelism and locality in data handling. Performance improvements through compiler optimizations are discussed, demonstrating the substantial benefits that arise from adopting a modern C++ approach to sound programming.
E N D
Music Programming Using New Features of Standard C++ Adrian Freed Amar Chaudhary Center for New Music and Audio Technologies University of California, Berkeley
Outline • Standardization effort for C++ • Motivation: to exploit new standard in music applications • Work through an example that aggressively uses new features • Compiler results • Conclusion
Standardization effort for C++ • NOT a codification of existing practice • Introduced many new features (outlined in printed paper) • Directly address efficiency issues relevant to reactive music software
Motivation • Open Sound Library (OSL) • Exploit high performance of modern computers • Parallelism • Data and code locality • Multi-level register/primary/secondary/main memory hierarchy • Exploit expressivity from new language features
Example: Second-order Resonator double damped_sine(double frequency, double amplitude,double rate,Time &t){ return amplitude * exp(-rate*t) * sin(2.0*PI*frequency*t); } Test for(Time t;t<10.0;++t)cout<< damped_sine(440.0, 1.0, 0.1,t)<<endl;
Regular 44.1kHz Sampling class Time {double time;const double sampling_interval; public:Time(double srate=44100.0): time(0.0),sampling_interval(1.0/srate) {}operator double() { return time; }friend double operator *(double f, Time &t){ return f * t.time; }Time& operator ++() { time += sampling_interval; return *this; } };
Example: Second-order Resonator • Simple • Easy to Debug • Easy to relate to basic mathematical description Too slow
Time as Discrete Sequences class Time {int sample_count; const double sampling_interval; public:Time(double srate=44100.0):sample_count(0), sampling_interval(1.0/srate) {}operator double(){ return sample_count*sampling_interval; }friend double operator *(double f, Time &t) { return f * t.sample_count*t.sampling_interval;}Time& operator ++() { ++sample_count; return *this; } };
Optimizing Exponentials • Operator Strength Reduction using identity:
Optimizing Exponentials class expstate { double value, factor; public:double exp(double k, int i) { return (i==0) ? (factor = ::exp(k), value=1.0) : (value *= factor);} };
Identity applies to Sinusoids Euler’s identity: class sinstate { complex<double> value, factor; public:double sin(double k, int i) { return (i==0) ?(factor = ::exp(complex<double>(0.0,k)), value=1.0) : imag(value *= factor);} };
Putting it all together class Time { private: const double sampling_interval; mutable double time, *prevs; mutable int index; public: Time (double srate=44100.0, int depth=MAXDEPTH): sampling_interval(1.0/srate), prevs(new double[depth]),index(0), time(0.0) { for (int i = 0; i < depth; ++i) {prevs[i] = 1.0;} }
Putting it all together operator double() const { return time; } const Time& operator ++() const { index=0; time += sampling_interval; return *this; } struct defmul{ const Time& t; const double f; defmul(const Time& at, const double af): t(at), f(af) {} operator double() { return f * t; } }; friend defmul operator *(const double f, const Time &t) { return defmul(t, f) ;} friend defmul operator *(const Time &t, const double f) { return defmul(t, f); }
Putting it all together double exp(const double f) const { double t = prevs[index]; exp_aux(prevs+(index++),-sampling_interval * f); return t; } friend double exp(const defmul &dm) { return ((const Time &) dm.t).exp(dm.f); } friend void exp_aux ( double * p, const double f) { *p *= ::exp(f); } };
Compiler Optimizations • Inlining • Code hoisting • Loop unrolling • Constant folding • Compile time arithmetic for intrinsics
Compiler Results • Kuck and Associates Inc. (http://www.kai.com) • Microsoft Visual C++ 6.0 (not 4.2) • Careful adjustment of optimization options • inline composition closure (i.e., defmul) • exponentiationonly computed once
Conclusion • Did not involve change the original function. • Users define their needs in an expressive high-level form. • Provide a large family of optimization classes. • Code for optimization classes is available at compile time. • Optimizations themselves are expressed in a high-level form.