## 6 Multithreading Support  
The Csound API includes an interface for multithreading, which is implemented via pthreads [28] on POSIX systems, or other native threading libraries in non-POSIX platforms. To allow opcodes an object-oriented access to this C interface, CPOF provides the Thread pure virtual class. This is subclassed and instantiated to encapsulate a separate thread whose entry point is given by a run() method. The base class provides join() and get_thread() methods for joining a thread and getting its handle. The example in Listing 10 illustrates the use of the Thread class. This implements a message printer on separate thread, picking up a string from the input and outputting it to the terminal. We derive a class that includes the run() method. To prevent data races, the class provides its own spin locks. A message is passed to it via the set_messsage() method. ```
classPrintThread:publiccsnd::Thread{ std::atomic_boolsplock; std::atomic_boolon; std::stringmessage; voidlock(){ booltmp=false; while(!splock.compare_exchange_weak(tmp, true) tmp=false; }
```
voidunlock() {  splock=false;  }  
uintptr_tr run() {  std::string old;  while(on) {  lock();  if(old.compare(message)) {  csound->message(message.c_str());  old=message;  }  unlock();  }  return 0;  }  
public:  PrintThread(csnd::Csound *csound)  : Thread(csound), splock(false), on(true), message(\"\") {};  
-PrintThread(){  on=false;  join();  }  
void set_message(const char *m) {  lock();  message = m;  unlock();  }  
The opcode class then is composed with it, as demonstrated in Listing 11. It will instantiate the object by calling its constructor and then pass messages to it from the performance method. ``` structTPrint:csnd::Plugin<0,l>{ static constexprcharconst*otypes=\"\"; static constexprcharconst*itypes=\"S\"; PrintThreadthread;  intinit(){  csound->plugin_deinit(this);  csnd::constr(&thread,csound);  returnOK; }  intdeinit(){  csnd::destr(&thread);return OK;  }  int kperf() {  thread.set_message(inargs.str_data(0).data);  return OK;  } };

## 7 Results

As we have noted, CPOF supports a fully object-oriented approach to the development of new Csound opcodes, which is the main result of this work. In this section, we first oppose two versions of the same unit generator, the first using the original C API and the second based on CPOF This demonstrates the advantages of applying the framework in the implementation of the opcode. To complement this, drawing from examples in the Csound codebase, we highlight two particular aspects of object-oriented programming that are enabled by CPOF: code re-use and the application of standard algorithms. Concluding this section, the overall contribution of this work to Csound and audio programming in general is discussed. ### CPOF versus C API

As a way of comparing the CPOF approach with the original C API, we will focus on re-implementing an existing opcode using the framework. We have chose tone, a simple first-order lowpass filter, which provides a simple code that is easy to follow, but also demonstrates the compactness of the C++ approach. In Listing 12, we present the original code, taken from the Csound sources and adapted as a plugin. While the original code is actually an internal opcode, for the sake of making an exact comparison, we present it here in a modified version as an externally-loaded plugin. The only changes made to the original code are to do with opcode registration. ```
typedefstruct{  OPDSh;  MYFLT*ar,*asig,*khp,*istor;  doublec1,c2,yt1,prvhp; }TONE; inttonset(CSOUND*csound,TONE*p) {  doubleb;  p->prvhp=(double)*p->khp;  b=2.0-cos((double)(p->prvhp*TWOPI/csound->GetSr()));  p->c2=b-sqrt(b*b-1.0);  p->cl=1.0-p->c2;  if(LIKELY(!