170 likes | 269 Views
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
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.