You are here:

C++/set of values

Advertisement


Question
Yes, I am asking on how to detect the highest and lowest frequency values from a set of values.

What is new_aubio_pitchdetection? What does it do?  Can it be used to return a _set_ of frequencies for differing samples sets from which you wish to determine the minimum and maximum values? Yes.


Can you give me a pseudo code of this.

'then you set min = max = first value. Then for every subsequent value if the value is less than min you set min to the value and if the value is greater than max you set max to the value.'

Sorry for the confusion.

Thanks a lot. I appreciate your help..  

Answer
Thanks for clarifying what you are after. Now I can help <g>!

However I think if you had sat down and thought it through you would have been able to have done the basics for yourself - it really is not rocket science - honest!

It follows directly from what I stated before:

   FrquencyValueType  frequency = DetectPitch( initialSampleSet );
   FrquencyValueType  minFrequency = frequency;
   FrquencyValueType  maxFrequency = frequency;
   For each remaining set of sample date:
       frequency = DetectPitch( currentSampleSet );
       if frequency < minFrequency then minFrequency = frequency;
       if frequency > maxFrequency then maxFrequency = frequency;
   End For each

Where DetectPitch is either new_aubio_pitchdetection or some function that wraps it up together with any boiler plate code required to set up each call.

A variation could be to loop over all the sample sets and use a flag to indicate the need to set the initial values for minFrequency and maxFrequency:

   FrquencyValueType  frequency;
   FrquencyValueType  minFrequency;
   FrquencyValueType  maxFrequency;
   Boolean isFirstTime = True;
   For each set of sample date:
       frequency = DetectPitch( currentSampleSet );
       if isFirstTime OR frequency < minFrequency then minFrequency = frequency;
       if isFirstTime OR frequency > maxFrequency then maxFrequency = frequency;
       isFirstTime = False;
   End For each

Of course this implies that all the frequency information is local to some function with a loop, which it may not be, they may be local to the DetectPitch function - or some other function without a loop that calls it. The obvious solutions to these problems would be to make them static - either globally or local to DetectPitch. However all forms of static data have problems with concurrency (multithreading) and non-function-local static data (i.e. global data) causes problems with overall code structure, testability and maintainability. Hence we should try to avoid static data if possible.

OK so let's lay out the options:

1) Use global static data for minFrequency and maxFrequency values and isFirstTime, and move the if statements into the function responsible for setting the minimum and maximum values:

   // Outside of any function
   FrquencyValueType  minFrequency;
   FrquencyValueType  maxFrequency;
   Boolean isFirstTime = True;

   // Within function of interest:
   FrquencyValueType  frequency = ... // call to new_aubio_pitchdetection or to DetectPitch if other function
   if isFirstTime OR frequency < minFrequency then minFrequency = frequency;
   if isFirstTime OR frequency > maxFrequency then maxFrequency = frequency;
   isFirstTime = False;

   // do other processing that relies on the minFrequency and maxFrequency values

This allows us to retain minFrequency and maxFrequency values across calls. It also allows any other part of the program to access the values of minFrequency and maxFrequency and isFirstTime - and _modify_ them if they so desire. This obviously can lead to hard to fix and maintain code as you have to know all parts of the program as any part may fiddle with global data. They are also not thread safe - and therefore require proper synchronisation support in such situations.

[ note:
   we could use thread local storage for thread specific data but such a storage class is
   not currently part of the C++ standard (but will almost certainly be part of the next
   revision of the ISO C++ standard), so if available non-standard techniques have to be used
]

Furthermore there is only one set of such values which could be limiting in some circumstances - e.g. a multi channel set of samples processed one at a time but interleaved for each channel, as could happen in an event based system:

   Process sample chunk 0, channel 0
   Process sample chunk 0, channel 1
       .
       .
       .
   Process sample chunk 0, channel n

   Process sample chunk 1, channel 0
   Process sample chunk 1, channel 1
       .
       .
       .
   Process sample chunk 1, channel n
       .
       .
       .
   Process sample chunk m, channel 0
   Process sample chunk m, channel 1
       .
       .
       .
   Process sample chunk m, channel n

In this situation the minFrequency and maxFrequency values will refer to the minFrequency and maxFrequency values across all channels and not just the current channel - which may or may not be acceptable.

2) Use local static data. Within the definition of DetectPitch place local static definitions of the min, max together with the if statements in the function:

   // Within function of interest:
   FrquencyValueType  frequency = ... // call to new_aubio_pitchdetection or to DetectPitch if other function
   static FrquencyValueType  minFrequency = frequency;
   static FrquencyValueType  maxFrequency = frequency;
   if frequency < minFrequency then minFrequency = frequency;
   if frequency > maxFrequency then maxFrequency = frequency;

   // do other processing that relies on the minFrequency and maxFrequency values

Note that static local data is only initialised the first time code execution passes through the local static definition statement, which neatly handles the is first time case for us.

Static data exist from the time they are created until the end of the program execution - unlike stack based automatic local variables which are destroyed on function call return (or earlier if they go out of scope before function call return). Hence once created (on the first call) the minFrequency and maxFrequency values will have the values they had at the end of the previous call for (the start of) each subsequent call.

However unlike global static data they can only be seen within the scope of the function in which they are defined which removes the problems with maintainability associated with global data - you know these values will only be modified and used within calls to the function they are defined in.

On the other hand the multi-threading and single set of data problems associated with global static data are still true for local static data. [note: In this case I do not think that (non-standard) thread local storage would help]

3) One way around the one-set-data problem would of course be to use more than one set of data - e.g. an array of data. However the other problems would not be fixed and only one way of providing multiple data can be provided - which again could limit flexibility.

4) One way around this, at the function level if not the global level, is to pass in the minFrequency and maxFrequency values with each call in a modifiable way (in fact they would be input and output parameters):

   TheProcessingFunction    // could be DetectPitch or some other function
   ( SampleDataSetType samples      By Nonmodifiable Reference
   , FrquencyValueType minFrequency By Modifiable Reference
   , FrquencyValueType maxFrequency By Modifiable Reference
   )
   Begin Function
       FrquencyValueType  frequency = ...
       if frequency < minFrequency then minFrequency = frequency;
       if frequency > maxFrequency then maxFrequency = frequency;

       // ...
  End Function

In this scenario the caller keeps separate values for each channel's minFrequency and maxFrequency values - possibly in global data, possibly not. Its up to the user of the function how they store the collections of minFrequency and maxFrequency values. (note: the isFirstTime flag may also need to be passed in and out)

In C++ we pass data in by modifiable reference using a non-const reference to the argument as the parameter type (e.g. FrquencyValueType & minFrequency) or as a pointer to non-const data - which is the C way.

However the values required to be held and passed around are separate and this can become cumbersome if more values need to be handled in these ways.

5) To get around this to some extent we could group the passed data into a user defined type to keep it together:

   Type FrequencyInformation          // e.g. a C style struct
       FrquencyValueType minFrequency;
       FrquencyValueType maxFrequency;
       Boolean          isInitialised;
   End Type

   TheProcessingFunction    // could be DetectPitch or some other function
   ( SampleDataSetType samples By Nonmodifiable Reference
   , FrequencyInformation fi By Modifiable Reference
   )
   Begin Function
       FrquencyValueType  frequency = ...
       if fi.isInitialised OR frequency < fi.minFrequency then fi.minFrequency = frequency;
       if fi.isInitialised OR frequency > fi.maxFrequency then fi.maxFrequency = frequency;
       isFirstTime = False;

       // ...
   End Function

6) We could turn things around a bit and separate (encapsulate) the data and logic for handling the minimum and maximum values. This would be a good use of a C++ class.

   Class FrequencyStats          // !!! Still pseudo code !!!!
       Private:
         FrquencyValueType minFrequency;
         FrquencyValueType maxFrequency;
         Boolean          isInitialised;
         
       Public:
         FrequencyStats()        // Default constructor - assumes FrquencyValueType objects
         : minFrequency(0)       // can be initialised using 0.
         , maxFrequency(0)
         , isInitialised(False)  // Must start with isInitialised set to False
         Begin Function
         End Function
         
         Update( FrquencyValueType frequency )
         Begin Function
         if isInitialised OR frequency < minFrequency then minFrequency = frequency;
         if isInitialised OR frequency > maxFrequency then maxFrequency = frequency;
         isFirstTime = False;
         End Function
      
         Minimum() Constant : FrquencyValueType
         Begin Function
         Return minFrequency;
         End Function

         Maximum() Constant : FrquencyValueType
         Begin Function
         Return maxFrequency;
         End Function
   End Class

Now each set of frequency statistical data is responsible for updating the values when it receives an Update message. Ok so that is object oriented talk - what this means for C++ is that a member function Update is called. It is now responsible for all the logic.

We can create FrequencyStats objects in many ways (but always initialised to the default values defined by the only provided (default) constructor - more could be added if required): as local automatic or static objects, as global object or dynamically using new. For example reworking one of the original examples using a FrequencyStats object would look like:

   FrquencyValueType  frequency;
   FrequencyStats     frequencyStatistics;  // default initialised using default constructor
   For each set of sample date:
       frequency = DetectPitch( currentSampleSet );
       frequencyStatistics.Update( frequency );
   End For each

Or, if we do not require the frequency value for anything else:

   FrequencyStats     frequencyStatistics;  // default initialised using default constructor
   For each set of sample date:
       frequency = DetectPitch( currentSampleSet );
       frequencyStatistics.Update( DetectPitch(currentSampleSet) );
   End For each

Which I think you will admit is quite a bit neater than the original.

When needed the minimum and maximum values can be obtained by calling the Minimum and Maximum methods:

   FrquencyValueType max = frequencyStatistics.Maximum();

Note however that the data parts of FrequencyStats objects are private to the object - meaning only class members (or friends) can access them. Hence while we can easily access the current minimum and maximum values for a FrequencyStats object we cannot easily change it other than by assigning the object the state of some other FrequencyStats objects:

   FrequencyStats fs1;
   
   // ...
   
   FrequencyStats fs2;
   
   fs2 = fs1;
   
Note we can also create a copy of another FrequencyStats object:

   FrequencyStats fs3(fs2);

Although I am showing pseudo code rather than C++, these are C++ features for class objects. Unless we actively make an effort the compiler will, if it can, always provide our class types with copy construction and assignment operations which perform an instance-data-member-wise copy of the source object to the target object, which is almost certainly OK for value classes like FrequencyStats as all data members have value semantics and can be so copied and assigned to.

In the case of having to update such values one call at a time say in an event handler we can use what ever strategy seems appropriate - e.g. storing a reference to a collection of FrequencyStats objects using some registration facility for such data (or even - dare I mention it - static data). Each event can then associate any frequency information with the correct related FrequencyStats object:

   FrequencyStatsCollection Ref allFrequencyStats = GetUserData() As FrequencyStatsCollection;
   
   FrequencyStatsCollectionKey fsKey = event.GetChannelId(); // Or channel name or whatever...
   
   FrequencyStats fs = allFrequencyStats[fsKey];  // get FrequencyStats for this channel
   
   fs.Update( DetectPitch( event.GetSampleData() ); // update FrequencyStats for this channel

The above of course is a very rough and made up outline of the sort of thing that would be done.

As to the multithreading problem, well if FrequencyStats objects were held in thread local storage or similar then again the problem goes away. However if such data has to be shared across threads then synchronisation will again be required.

Remember that nearly all the examples are pseudo code, not any real programming language.

Even though I know there is a lot here I hope this has been of some help and if nothing else has given you food for thought. Again I could have been more focused if you provided a bit more information on exactly how your code / calls were laid out. However getting the balance of information in a question right is of course in itself tricky. Hopefully I have at least touched on what you are doing and if you require further details then please ask further questions.  

C++

All Answers


Answers by Expert:


Ask Experts

Volunteer


Ralph McArdell

Expertise

I am a software developer with more than 15 years C++ experience and over 25 years experience developing a wide variety of applications for Windows NT/2000/XP, UNIX, Linux and other platforms. I can help with basic to advanced C++, C (although I do not write just-C much if at all these days so maybe ask in the C section about purely C matters), software development and many platform specific and system development problems.

Experience

My career started in the mid 1980s working as a batch process operator for the now defunct Inner London Education Authority, working on Prime mini computers. I then moved into the role of Programmer / Analyst, also on the Primes, then into technical support and finally into the micro computing section, using a variety of 16 and 8 bit machines. Following the demise of the ILEA I worked for a small company, now gone, called Hodos. I worked on a part task train simulator using C and the Intel DVI (Digital Video Interactive) - the hardware based predecessor to Indeo. Other projects included a CGI based train simulator (different goals to the first), and various other projects in C and Visual Basic (er, version 1 that is). When Hodos went into receivership I went freelance and finally managed to start working in C++. I initially had contracts working on train simulators (surprise) and multimedia - I worked on many of the Dorling Kindersley CD-ROM titles and wrote the screensaver games for the Wallace and Gromit Cracking Animator CD. My more recent contracts have been more traditionally IT based, working predominately in C++ on MS Windows NT, 2000. XP, Linux and UN*X. These projects have had wide ranging additional skill sets including system analysis and design, databases and SQL in various guises, C#, client server and remoting, cross porting applications between platforms and various client development processes. I have an interest in the development of the C++ core language and libraries and try to keep up with at least some of the papers on the ISO C++ Standard Committee site at http://www.open-std.org/jtc1/sc22/wg21/.

Education/Credentials

©2016 About.com. All rights reserved.