jack c++ API

Programming applications for making music on Linux.

Moderators: MattKingUSA, khz

tatch
Established Member
Posts: 662
Joined: Fri Nov 16, 2012 3:18 pm

jack c++ API

Post by tatch »

is there no standard C++ API for JACK that people use?

i found this which is 2 years old as well as what appears to be an API by male. I thought a lot of LAU apps are written in C++, do people just use the C headers and drudge their own way to success?

( also how do I post to LAD? I tried posting a couple months ago but I never saw my message or any responses. Nabble has it though. )
Lyberta
Established Member
Posts: 681
Joined: Sat Nov 01, 2014 8:15 pm
Location: The Internet
Been thanked: 1 time

Re: jack c++ API

Post by Lyberta »

The problem is that C++ has no stable ABI so people still use C ABI to talk between programs. I plan to provide C++14 wrapper too.
User avatar
sadko4u
Established Member
Posts: 986
Joined: Mon Sep 28, 2015 9:03 pm
Has thanked: 2 times
Been thanked: 359 times

Re: jack c++ API

Post by sadko4u »

tatch wrote:is there no standard C++ API for JACK that people use?
Why do you need C++ API for such simple-interfaced things like JACK?
JACK's C interface is well designed, well documented and intuitively understandable.
LSP (Linux Studio Plugins) Developer and Maintainer.
Lyberta
Established Member
Posts: 681
Joined: Sat Nov 01, 2014 8:15 pm
Location: The Internet
Been thanked: 1 time

Re: jack c++ API

Post by Lyberta »

sadko4u wrote:Why do you need C++ API for such simple-interfaced things like JACK?
C and C++ are very different languages with very different idioms. C APIs can't provide RAII, exceptions and other things you normally expect from any decent C++ API. In my experience I've never used C API directly in my C++ code. I always make a wrapper.

By the way, I've looked at the source code of those libraries and they're written in C++03 which is very outdated now. People don't write code like this these days.
User avatar
sadko4u
Established Member
Posts: 986
Joined: Mon Sep 28, 2015 9:03 pm
Has thanked: 2 times
Been thanked: 359 times

Re: jack c++ API

Post by sadko4u »

FaTony wrote:
sadko4u wrote:Why do you need C++ API for such simple-interfaced things like JACK?
C and C++ are very different languages with very different idioms. C APIs can't provide RAII, exceptions and other things you normally expect from any decent C++ API.
Oh no, you really need for simple things like JACK API such piece of crap like RAII, exceptions and huge causeless metaprogramming?
FaTony wrote:In my experience I've never used C API directly in my C++ code. I always make a wrapper.
It's normal to wrap functions into object-oriented code. And it's normal that for different tasks different wrappers can be implemented. So I think, topic starter should better write his own wrapper.
LSP (Linux Studio Plugins) Developer and Maintainer.
Lyberta
Established Member
Posts: 681
Joined: Sat Nov 01, 2014 8:15 pm
Location: The Internet
Been thanked: 1 time

Re: jack c++ API

Post by Lyberta »

sadko4u wrote:Oh no, you really need for simple things like JACK API such piece of crap like RAII, exceptions and huge causeless metaprogramming?
Maybe you need to read tutorials from this century?
User avatar
sadko4u
Established Member
Posts: 986
Joined: Mon Sep 28, 2015 9:03 pm
Has thanked: 2 times
Been thanked: 359 times

Re: jack c++ API

Post by sadko4u »

FaTony wrote:Maybe you need to read tutorials from this century?
I follow the changes that are made in C++ since C++98 and can say that things have changed not particularly better.

There is still no normal RTTI and no reflection.
There is still no FINALLY statement because C++ language designers propagate RAII concept that isn't a magic pill in most cases. Yes, now it can be emulated with lambdas but without macros (which 'are hell', as said by Stroustroup) it will look out like a crap.
Exceptions and pointers can not be safely combined together without auto_ptr. You could avoid pointer metaprogramming by using finally but... you already know.
Break from nested loop? No, we still don't have this facility, we must use flag variables or goto (which 'is hell').
Oh yes! Now we got 'auto' keyword that allows us not to write the full 10-meter type name of the variable. But this does not fix that fact that C++ has a very complicated type system, and after changes made in C++11 that extend metaprogramming it will have even more complicated type system. I still can not pass std::vector<char *> to the function that requires std::vector<const char *> as argument. Instead of this I have to do a copy of the collection and pass it. And I still get many-many lines of the compiler's error output when I pass something non-natural to the STL's container template argument.
Operator overloading makes each expression non-obvious and context-specific, so without additional syntax highliting and code inspection you can not actually say what does expression 'c=a+b' mean.

For these and many other facts I decided to use C++ for my project only as 'C with classes'. Instead of catching std::bad_alloc (that nobody catches in 95% of project, even in STL code there is no out-of-memory control) in many places I prefer to turn-off exception handling and check pointer for non-NULL value because when the code falls on an unhandled exception, we can not get stack trace of the exception to find the actual place where it was thrown, so dereferencing of NULL pointer is better. I do not use STL because it generates huge amount of machine code for each new template instance and because C++ does non-wanted inlining of generated code where you don't want this. That's why I avoid templates where it's possible. And actually in 99% of cases you really do not need templates.

So if I can use C API, I use it directly without any wrappers. If I need this API on some instance in more than one place, I write a simple wrapping class without RAII, exceptions and other together-conflicting factilities of C++.
LSP (Linux Studio Plugins) Developer and Maintainer.
Lyberta
Established Member
Posts: 681
Joined: Sat Nov 01, 2014 8:15 pm
Location: The Internet
Been thanked: 1 time

Re: jack c++ API

Post by Lyberta »

sadko4u wrote:There is still no normal RTTI and no reflection.
Define "normal RTTI". I have no problems with current RTTI.
sadko4u wrote:There is still no FINALLY statement because C++ language designers propagate RAII concept that isn't a magic pill in most cases.
There is zero need for "finally" precisely because of RAII. If your classes don't follow RAII then you are doing it wrong.
sadko4u wrote:Exceptions and pointers can not be safely combined together without auto_ptr. You could avoid pointer metaprogramming by using finally but... you already know.
Combined? What? auto_ptr was deprecated in C++11. Now we have unique_ptr and shared_ptr. What do you mean by "pointer metaprogramming"? Again, there's no need for "finally" because smart pointers follow RAII and raw pointers are presumed non-owning. If you have owning raw pointers, you're doing it wrong.
sadko4u wrote:Break from nested loop? No, we still don't have this facility, we must use flag variables or goto (which 'is hell').
C doesn't have it too. Name the language that has this.
sadko4u wrote:I still can not pass std::vector<char *> to the function that requires std::vector<const char *> as argument.
char* is a C legacy. You need to pass std::vector<std::string>.
sadko4u wrote:Operator overloading makes each expression non-obvious and context-specific, so without additional syntax highliting and code inspection you can not actually say what does expression 'c=a+b' mean.
Every tool can be abused. If you find a library that makes the code ambiguous, find a better library.
sadko4u wrote:For these and many other facts I decided to use C++ for my project only as 'C with classes'. Instead of catching std::bad_alloc (that nobody catches in 95% of project, even in STL code there is no out-of-memory control) in many places I prefer to turn-off exception handling and check pointer for non-NULL value because when the code falls on an unhandled exception, we can not get stack trace of the exception to find the actual place where it was thrown, so dereferencing of NULL pointer is better. I do not use STL because it generates huge amount of machine code for each new template instance and because C++ does non-wanted inlining of generated code where you don't want this. That's why I avoid templates where it's possible. And actually in 99% of cases you really do not need templates.

So if I can use C API, I use it directly without any wrappers. If I need this API on some instance in more than one place, I write a simple wrapping class without RAII, exceptions and other together-conflicting factilities of C++.
Just as I expected. You just couldn't learn proper C++. Maybe all you read was Russian books? I've read a couple of them and they were total shit.

Guess what, all my classes follow RAII, I never use error codes and always use exceptions, and about ~70% of all my code is templates. I've even written a digital audio processing library that is 99% templates. The only non-template part is reading and writing WAV files. Why? Because templates allow you to work with any type. In my library almost all class templates take sample type and allocator so all my classes templates work with any bit depth and allocator. Want 16, 24, 32 bit int? Supported out of the box. Want 64 bit int and 128 bit float? Write a 100 line class and the whole library suddenly supports it.

I personally hate C because of it's raw pointers, arrays and strings and because it doesn't have templates and RAII. Whenever I see the code which says "but then you need to call this function to clean this up", I'm like "O rly? Gotta find a better API". But I'm pretty sure C will die in about 50 years and we'll have a much better languages.
User avatar
sadko4u
Established Member
Posts: 986
Joined: Mon Sep 28, 2015 9:03 pm
Has thanked: 2 times
Been thanked: 359 times

Re: jack c++ API

Post by sadko4u »

FaTony wrote:Define "normal RTTI". I have no problems with current RTTI.
Normal RTTI means reflection. It means that I can take the pointer to the object and get ALL information about structure of it's type and, also, can dynamically find and call methods of this object by name and argument types. C++'s RTTI is a fake.
FaTony wrote:There is zero need for "finally" precisely because of RAII. If your classes don't follow RAII then you are doing it wrong.
RAII is not a magic pillow. C++ provides many duplicate facilities (pointers and references, macroses and templates, classes and structures). Programming with RAII input/output and interaction between processes is like shooting into leg. Finally allows to do code smarter and more predictive than using huge amount of wrapping classes instead of one that internally uses 'finally' statements. С++ adepts get cranky on RAII and write huge amount of templated code there where they just could insert 'finally'. If C++ is so 'flexible' and 'powerful', why it does not provide such 'duplicate to RAII facility' like 'finally'? Also RAII is poor ideology because... C++'s destructors can not throw exceptions (no, they can but it's very dangerous)! So to properly free/destruct resource I still should call special destroying routine before issuing the destructor or write tons of code that allow to pass error from destrutor to the environment. So in this case all usage of RAII goes to epic fail because I spend a lot of time by writing code that I shouldn't write if I used 'finally'.
FaTony wrote:Combined? What? auto_ptr was deprecated in C++11. Now we have unique_ptr and shared_ptr. What do you mean by "pointer metaprogramming"?
So this thing I directly mean. Now instead of auto_ptr we should use two type of template wrappers: unique_ptr and shared_ptr. And they have additional overhead of data and restrictions (still relative to RAII!).
FaTony wrote:C doesn't have it too. Name the language that has this.
For C it's normal because it does not have constructors/destructors, templates and other 'special' memory and resource management. C is designed so that it allows simply translate it's code into assembly code in mind and vice verse. Stroustroup called 'goto' statement 'evil' but didn't provide something for replacement.
Languages that allow 'break out the nested loop': Java, JavaScript, C#, D and even PERL.
FaTony wrote:char* is a C legacy. You need to pass std::vector<std::string>.
Even more. I can't pass std::vector<std::string> to the function that requires std::vector<const std::string>. Replacing char * to std::string does not solve the problem.
FaTony wrote:Every tool can be abused. If you find a library that makes the code ambiguous, find a better library.
You're wrong because C++ adepts say 'only this way is right' by providing such crap libraries like STL and Boost. I saw how one C++ adept tried to perform multithreaded IO on sockets with new libraries provided by C++ 11 standard. I couldn't read his code without many facepalms because there were a lot of hacks that could be avoided by just writing raw C-style code.
FaTony wrote:Just as I expected. You just couldn't learn proper C++. Maybe all you read was Russian books?
I've read Stroustroup's third edition book many years ago and wanted to be employeed as C++ developer. But, fortunately, PERL and JAVA was offered to me instead. Also I'm highly experienced in writing low-level assembly code. So I have a good base to perform comparison.
FaTony wrote: Guess what, all my classes follow RAII, I never use error codes and always use exceptions, and about ~70% of all my code is templates. I've even written a digital audio processing library that is 99% templates.
The only non-template part is reading and writing WAV files. Why? Because templates allow you to work with any type. In my library almost all class templates take sample type and allocator so all my classes templates work with any bit depth and allocator. Want 16, 24, 32 bit int? Supported out of the box. Want 64 bit int and 128 bit float? Write a 100 line class and the whole library suddenly supports it.
This?

Code: Select all

                        stream.Read(chunkid.data(), chunkid.size());
			stream >> chunksize;
			if (chunkid == FormatChunkID)
			{
				// Format chunk.
				stream >> format;
				stream >> numchannels;
				stream >> samplerate;
				std::uint32_t byterate;
				stream >> byterate;
				stream >> blockalign;
				stream >> bitdepth;
				if (chunksize == 16)
				{
					continue;
				}
				std::uint16_t extensionsize;
				stream >> extensionsize;
				// Skip extension bytes for now.
				stream.SeekReadPosition(extensionsize, std::ios_base::cur);
			}
Or this?

Code: Select all

template <typename T, typename Allocator>
void Pan<T, Allocator>::Render(MultichannelAudioBuffer<T, Allocator>& buffer)
{
	if (buffer.GetNumberOfChannels() == 1)
	{
		buffer.ChannelPushBack(buffer[0].GetAudioBuffer());
	}
	else if (buffer.GetNumberOfChannels() != 2)
	{
		throw std::invalid_argument{"Pan::Render: Invalid number of channels."};
	}
	buffer[0] += leftgain;
	buffer[1] += rightgain;
}
Or this?

Code: Select all

template <typename T, typename Allocator>
AmplifierMIDIControl<T, Allocator>::AmplifierMIDIControl(
	Amplifier<T, Allocator>& amp, MIDI::InputChannel& channel,
	Gain<CalcType> maxgain)
	: amp{amp}, channel{channel}, maxgain{std::move(maxgain)}
{
	cchook = channel.HookControlChange([&](const auto& event){
		this->OnControlChange(event); });
	this->SetGain();
}
Sorry, but for audio processing it's a holy crap. Because:
1. You have a lot of code overhead for processing one sample. For simple devices it's not noticeable. For devices that do complex processing it's a very huge performance penalty. Yes, it looks funny but doesn't solve the more foreground task: it should be fast as possible.
2. For audio processing on very popular x86 architecture float and double are enough to do many things. You do not need to support many sample formats.
3. The behaviour of fixed-point is very different to floating point, especially relative to overflows/undeflows. So you will be forced to completely rewrite your code for microcontrollers also for performance purposes.
Whenever I see the code which says "but then you need to call this function to clean this up", I'm like "O rly?
And this is is reasonalbe. All your RAII is powerless when the cleaning function takes a lot of time for execution or returns error code. When you use auto-destruction wrappers, you can not properly handle the behaviour of your code relative to long cleaning. Also you can not throw exceptions from destructors, surprise!
LSP (Linux Studio Plugins) Developer and Maintainer.
Lyberta
Established Member
Posts: 681
Joined: Sat Nov 01, 2014 8:15 pm
Location: The Internet
Been thanked: 1 time

Re: jack c++ API

Post by Lyberta »

sadko4u wrote:Normal RTTI means reflection. It means that I can take the pointer to the object and get ALL information about structure of it's type and, also, can dynamically find and call methods of this object by name and argument types. C++'s RTTI is a fake.
This would mean having lots of runtime overhead to store reflection info. But if you really want it, why not to make a proposal to ISO committee.
sadko4u wrote:RAII is not a magic pillow. C++ provides many duplicate facilities (pointers and references, macroses and templates, classes and structures).
Because of the C compatibility. Yeah, I would love to get rid of pointers and macros.
sadko4u wrote:Programming with RAII input/output and interaction between processes is like shooting into leg. Finally allows to do code smarter and more predictive than using huge amount of wrapping classes instead of one that internally uses 'finally' statements. С++ adepts get cranky on RAII and write huge amount of templated code there where they just could insert 'finally'. If C++ is so 'flexible' and 'powerful', why it does not provide such 'duplicate to RAII facility' like 'finally'?
You can spent 5 minutes of your time and have a "finally" class template.
sadko4u wrote:Also RAII is poor ideology because... C++'s destructors can not throw exceptions (no, they can but it's very dangerous)! So to properly free/destruct resource I still should call special destroying routine before issuing the destructor or write tons of code that allow to pass error from destrutor to the environment. So in this case all usage of RAII goes to epic fail because I spend a lot of time by writing code that I shouldn't write if I used 'finally'.
If cleanup function fails, you can't do anything except logging an error and terminating the application which you can do using destructor.
sadko4u wrote:So this thing I directly mean. Now instead of auto_ptr we should use two type of template wrappers: unique_ptr and shared_ptr. And they have additional overhead of data and restrictions (still relative to RAII!).
unique_ptr has zero overhead. shared_ptr has reference count because it's supposed to be shared. You use shared_ptr only if you really need it.
sadko4u wrote:Even more. I can't pass std::vector<std::string> to the function that requires std::vector<const std::string>. Replacing char * to std::string does not solve the problem.
I have never seen a library where template parameter is const. Library that uses std::vector<const std::string> is brain dead.
sadko4u wrote:You're wrong because C++ adepts say 'only this way is right' by providing such crap libraries like STL and Boost.
STL and Boost are crap? Look at the header of it's site:
"...one of the most highly regarded and expertly designed C++ library projects in the world." — Herb Sutter and Andrei Alexandrescu, C++ Coding Standards
Herb Sutter is the head of ISO C++ standardization committee. If you would compare his opinion and another from some random guy on the Internet, I would certainly choose the first one.
Another point: STL was written in 1994 and became a basis of the part of the C++ standard library. There are zero occurrences of the word "STL" in the standard. To me, STL is Stephan T Lavavej.
sadko4u wrote:This?

Code: Select all

snip
Or this?

Code: Select all

snip
Or this?

Code: Select all

snip
Sorry, but for audio processing it's a holy crap. Because:
1. You have a lot of code overhead for processing one sample.
Where have you found an overhead?
sadko4u wrote:2. For audio processing on very popular x86 architecture float and double are enough to do many things. You do not need to support many sample formats.
I convert to float for processing. And unlike your design, I give user the choice of their preferred bit depth.
sadko4u wrote:3. The behaviour of fixed-point is very different to floating point, especially relative to overflows/undeflows. So you will be forced to completely rewrite your code for microcontrollers also for performance purposes.
There is no fixed point types in ISO C++ and I'm not interested in platform specific hacks.
sadko4u wrote:And this is is reasonalbe. All your RAII is powerless when the cleaning function takes a lot of time for execution or returns error code. When you use auto-destruction wrappers, you can not properly handle the behaviour of your code relative to long cleaning. Also you can not throw exceptions from destructors, surprise!
Again, if cleanup fails, you can't fix it. If cleanup takes much time you too can't do anything to make it faster.
User avatar
sadko4u
Established Member
Posts: 986
Joined: Mon Sep 28, 2015 9:03 pm
Has thanked: 2 times
Been thanked: 359 times

Re: jack c++ API

Post by sadko4u »

FaTony wrote:You can spent 5 minutes of your time and have a "finally" class template.
I've already solved this by using macros (which are 'evil') and lambas. Syntax changed but still comfortable for use, without need of huge typing:

Code: Select all

    template<typename T>
        class _ddb_finalizer
        {
            private:
                T _f;

            public:
                inline _ddb_finalizer( const T f ): _f(f) { };
                inline ~_ddb_finalizer() { _f(); };
        };

    template<typename T>
        _ddb_finalizer<T> _ddb_finalizer_inst( const T x )
        {
            return _ddb_finalizer<T>(x);
        };

    #define __FINALLY_IMPL(line, code) auto _ddb_finalizer_var##line = _ddb_finalizer_inst( [&]() { code; } );
    #define __FINALLY_PROXY(line, code) __FINALLY_IMPL(line, code)
    #define FINALLY(code) __FINALLY_PROXY(__LINE__, code)
    
    #include <stdio.h>
    
    int main()
    {
       printf("init\n");
       int *p = new int[100];
       FINALLY
       (
           printf("cleanup\n");
           if (p != NULL)
           	delete [] p;
       );
       printf("some code\n");
    }
But without defines the code would look out like a crap.
FaTony wrote:If cleanup function fails, you can't do anything except logging an error and terminating the application which you can do using destructor.
Terminating application? You're serious? I should terminate application on probabale I/O error with sockets or filesystem? No, instead of this I can launch some process for fixing the problem or retry some amount of I/O operations. But this all requires some time, so the problem object/resource should be passed to another cleaning/fixing thread.
FaTony wrote: unique_ptr has zero overhead.
Really? And what about tuples? /usr/include/c++/4.8/bits/unique_ptr.h:

Code: Select all

  /// 20.7.1.2 unique_ptr for single objects.
  template <typename _Tp, typename _Dp = default_delete<_Tp> >
    class unique_ptr
    {
      // ...

      typedef std::tuple<typename _Pointer::type, _Dp>  __tuple_type;
      __tuple_type                                      _M_t;

     // ...
FaTony wrote:shared_ptr has reference count because it's supposed to be shared. You use shared_ptr only if you really need it.
Oh really? Let's look into /usr/include/c++/4.8/bits/shared_ptr.h and included files:

Code: Select all

  template<>
    class _Mutex_base<_S_mutex>
    : public __gnu_cxx::__mutex
    {
    protected:
      // This policy is used when atomic builtins are not available.
      // The replacement atomic operations might not have the necessary
      // memory barriers.
      enum { _S_need_barriers = 1 };
    };
    
    //...
    template<_Lock_policy _Lp = __default_lock_policy>
    class _Sp_counted_base
    : public _Mutex_base<_Lp>
    {
    // ...
    private:
      //...
      _Atomic_word  _M_use_count;     // #shared
      _Atomic_word  _M_weak_count;    // #weak + (#shared != 0)
    };
    
  template<_Lock_policy _Lp>
    class __shared_count
    {
      // ...
      _Sp_counted_base<_Lp>*  _M_pi;
    };
    
  template<typename _Tp, _Lock_policy _Lp>
    class __shared_ptr
    {
    // ...
      _Tp*                 _M_ptr;         // Contained pointer.
      __shared_count<_Lp>  _M_refcount;    // Reference counter.
    };
    
    // from namespace __gnu_cxx:
    class __mutex
  {
  private:
#if __GTHREADS && defined __GTHREAD_MUTEX_INIT
    __gthread_mutex_t _M_mutex = __GTHREAD_MUTEX_INIT;
#else
    __gthread_mutex_t _M_mutex;
#endif
    //...
  };
You're trying to fool me? It has overhead of two counters and additionally of spinlock object. So each modification of shared_ptr causes atomic operations on shared data that are expensive.

FaTony wrote:I have never seen a library where template parameter is const. Library that uses std::vector<const std::string> is brain dead.
Really? So you pass std::vector<std::string> to the function in hope that it won't modify strings from passed vector? This is called 'not brain dead'?
FaTony wrote: STL and Boost are crap? Look at the header of it's site:
I can give another site that says contrary things. Don't try to citate somebody, give facts.
FaTony wrote:Another point: STL was written in 1994 and became a basis of the part of the C++ standard library. There are zero occurrences of the word "STL" in the standard.
As the counterpart I can add that there is currently no C++ provided without STL. From STL we get damn std::cout, std::cin and many other unusable stuff.
FaTony wrote: Where have you found an overhead?
Oh, sorry, I thought it was shit. But now I see it is a complete shit:

Code: Select all

        /// \brief Amplifies all samples by the given gain.
        /// \param[in] gain Gain to apply.
        /// \return Reference to this audio buffer.
        MultichannelAudioBuffer& operator+=(Gain<CalcType> gain);
        
        /// \brief Adds the given value to all samples.
        /// \param[in] value Value to add.
        /// \return Reference to this audio buffer.
        MultichannelAudioBuffer& operator+=(typename T::ValueType value);
        
template <typename T, typename Allocator>
MultichannelAudioBuffer<T, Allocator>& MultichannelAudioBuffer<T, Allocator>::
	operator+=(Gain<CalcType> gain)
{
	for (auto&& channel : channels)
	{
		channel += gain;
	}
	return *this;
}

template <typename T, typename Allocator> template <bool IsConst>
typename MultichannelAudioBuffer<T, Allocator>::
        template FrameReference<IsConst>& MultichannelAudioBuffer<T, Allocator>::
        FrameReference<IsConst>::operator+=(Gain<CalcType> gain)
{
        for (auto&& sample : buffer)
        {
                *sample += gain;
        }
        return *this;
}

template <typename T, typename CT>
Sample<T, CT>& Sample<T, CT>::operator+=(Gain<CalcType> gain)
{
	return *this *= gain.GetValue();
}

template <typename CalcType>
CalcType Gain<CalcType>::GetValue(void) const
{
	return value;
}
Tons of code that mostly do... nothing. Many-many-many abstractions to use finally float or double.
FaTony wrote:I convert to float for processing. And unlike your design, I give user the choice of their preferred bit depth.
Or you can simply provide two overloaded functions that do same things in bulk mode with specified size of float instead of building huge template structure.
FaTony wrote:There is no fixed point types in ISO C++ and I'm not interested in platform specific hacks.
Under fixed point I ment integer sample processing, that means that the fractional part is zero length. But I already know that you fool your users and use float and double as an intermediate format.
FaTony wrote:Again, if cleanup fails, you can't fix it.
I can fix it because it depends on the current state of the program what to do in this case.
FaTony wrote:If cleanup takes much time you too can't do anything to make it faster.
Or cleanup may be passed to special cleaning thread so the main thread won't block.
LSP (Linux Studio Plugins) Developer and Maintainer.
Lyberta
Established Member
Posts: 681
Joined: Sat Nov 01, 2014 8:15 pm
Location: The Internet
Been thanked: 1 time

Re: jack c++ API

Post by Lyberta »

sadko4u wrote:I've already solved this by using macros (which are 'evil') and lambas. Syntax changed but still comfortable for use, without need of huge typing:
You can propose your solution to the standard committee.
sadko4u wrote:Terminating application? You're serious? I should terminate application on probabale I/O error with sockets or filesystem? No, instead of this I can launch some process for fixing the problem or retry some amount of I/O operations. But this all requires some time, so the problem object/resource should be passed to another cleaning/fixing thread.
Are you doing I/O in destructors? The destructor should close whatever resource it holds. There shouldn't be any I/O.
sadko4u wrote:Really? And what about tuples? /usr/include/c++/4.8/bits/unique_ptr.h:

Code: Select all

snip
Tuples are compile time. It doesn't have overhead at runtime.
sadko4u wrote:Oh really? Let's look into /usr/include/c++/4.8/bits/shared_ptr.h and included files:

Code: Select all

snip
You're trying to fool me? It has overhead of two counters and additionally of spinlock object. So each modification of shared_ptr causes atomic operations on shared data that are expensive.
It is required for thread safety. Remember, multithreading is now in ISO C++ so people need to think about thread safety.
sadko4u wrote:Really? So you pass std::vector<std::string> to the function in hope that it won't modify strings from passed vector? This is called 'not brain dead'?
I pass reference to const. You can't modify const std::vector<std::string>.
sadko4u wrote:I can give another site that says contrary things. Don't try to citate somebody, give facts.
You can give anything but you wouldn't have anything more reputable than isocpp.org
sadko4u wrote:As the counterpart I can add that there is currently no C++ provided without STL. From STL we get damn std::cout, std::cin and many other unusable stuff.
Here's the STL. Afaik Visual C++, libstdc++ and libc++ come without it.
sadko4u wrote:Oh, sorry, I thought it was shit. But now I see it is a complete shit:

Code: Select all

snip
Tons of code that mostly do... nothing. Many-many-many abstractions to use finally float or double.
If you love your float* or double*, keep using them. I make abstractions that allow me to do many things with little code. To me, it's better to write

Code: Select all

buffer += 6_dB
Than to write 2 nested loops with casts to some float type and back.
sadko4u wrote:Or you can simply provide two overloaded functions that do same things in bulk mode with specified size of float instead of building huge template structure.
First, you forgot that there is also a long double. Second, you want me to copy paste the whole code of the library and have 3 copies of code that do the same thing with different types? Ever heard about scalability?
sadko4u wrote:Under fixed point I ment integer sample processing, that means that the fractional part is zero length. But I already know that you fool your users and use float and double as an intermediate format.
You are the only person that calls integers fixed point. I don't fool anyone because my library is fully documented.
sadko4u wrote:I can fix it because it depends on the current state of the program what to do in this case.
Provide a concrete example.
sadko4u wrote:Or cleanup may be passed to special cleaning thread so the main thread won't block.
Yes, you can do this, but the time will still be consumed, no matter what thread does it.

You know, I'd love to go into your code and say that it's a complete shit, but I have better things to do.
User avatar
sadko4u
Established Member
Posts: 986
Joined: Mon Sep 28, 2015 9:03 pm
Has thanked: 2 times
Been thanked: 359 times

Re: jack c++ API

Post by sadko4u »

FaTony wrote:You can propose your solution to the standard committee.
I think I'm not the first and not the last who asks commitee about 'finally' statement. And I think I'm not the first and not the last whom the commitee will answer 'f*ck you' because I already saw the similar answers.
FaTony wrote:Are you doing I/O in destructors? The destructor should close whatever resource it holds. There shouldn't be any I/O.
I'm not doing I/O in destructors. But I saw how many people DO it:
http://www.tomdalling.com/blog/software ... explained/
FaTony wrote: Tuples are compile time. It doesn't have overhead at runtime.

It is required for thread safety. Remember, multithreading is now in ISO C++ so people need to think about thread safety.
Alright, how I shall use spinlocks everywhere I want to share pointer between objects. Even I don't use them for multi-threading. Nice, optimal solution for time-critical applications!
uinque_ptr doesn't allow copying. Also I can't use arrays on shared_ptr and weak_ptr, instead of this I should use vectors and so on... So the code falls into deep metaprogramming instead of doing something more useful.
sadko4u wrote:I pass reference to const. You can't modify const std::vector<std::string>.
Oh damn, these magic with references. Now const vector returns const reference to non-const data. Super! Fine! Did the original design of C++ expect this?
FaTony wrote:Here's the STL. Afaik Visual C++, libstdc++ and libc++ come without it.
Really? https://msdn.microsoft.com/en-us/library/cscc687y.aspx Alright, let's imagine STL is not coming-out-of-the-box for some compiler. And what you can do with it without STL? All your lovely meta-programming code (and highly propagated by other C++ adepts) that uses STL collections won't compile. It's like you would use C without glibc.
FaTony wrote:If you love your float* or double*, keep using them. I make abstractions that allow me to do many things with little code.

Code: Select all

buffer += 6_dB
Or you can just write:

Code: Select all

adjust_gain(buffer, 6_dB, samples);
This will allow you to apply this function not only on special object of buffer type but on every chunk of memory that contains data for processing.
FaTony wrote:First, you forgot that there is also a long double. Second, you want me to copy paste the whole code of the library and have 3 copies of code that do the same thing with different types? Ever heard about scalability?
Did you ever heard about optimizations? Each function can be tuned at low-level to boost performance up to numerous times (especially, by applying vectorization). When you instantiate templates, you have nothing to do with the generated code.
FaTony wrote:You are the only person that calls integers fixed point.
Because integers are the special case of fixed-point values.
FaTony wrote:I don't fool anyone because my library is fully documented.
And how do you handle 16-bit samples while adjusting 3dB gain?
sadko4u wrote:I can fix it because it depends on the current state of the program what to do in this case.
Concrete example: you're writing remote file via FXP protocol, then you perform the close() on remote handle. The close() fails on socket error. Now you have to execute code that will check that file was completely written if connection to the remote side is available. If it would be RAII, the usual solution (see the article above) would be 'call remote side for closing file handle' in destructor. You offered to crash program for this case. Very nice!
FaTony wrote:Yes, you can do this, but the time will still be consumed, no matter what thread does it.
Right, but the main thread that serves something won't block instead of 'close-on-destruction' case.
FaTony wrote:You know, I'd love to go into your code and say that it's a complete shit, but I have better things to do.
I also don't have much time to explain where template programming could be good and where it's better not to use it.
LSP (Linux Studio Plugins) Developer and Maintainer.
tramp
Established Member
Posts: 2335
Joined: Mon Jul 01, 2013 8:13 am
Has thanked: 9 times
Been thanked: 454 times

Re: jack c++ API

Post by tramp »

Hi

Funny read here, a lot of pro and cons on both side, but, we all know, the world isn't black&white.
Best way to resolve things, is, do it your way.
However, one thing here brings me to response here, because I can't believe what I read, it's this stance:
FaTony wrote:You are the only person that calls integers fixed point.
Ups, Fixed Point Processing, is a very well known, and widely used dsp therm.
http://www.dspguide.com/ch28/4.htm

and this
sadko4u wrote:That's why I avoid templates where it's possible.
there are a couple of need usage for templates, no reason to avoid them, even, no reason to pray them.

Code: Select all

template <class T>
inline std::string to_string(const T& t) {
    std::stringstream ss;
    ss << t;
    return ss.str();
}
On the road again.
Lyberta
Established Member
Posts: 681
Joined: Sat Nov 01, 2014 8:15 pm
Location: The Internet
Been thanked: 1 time

Re: jack c++ API

Post by Lyberta »

tramp wrote:Best way to resolve things, is, do it your way.
Amen to that. I'm tired of this discussion already.
Post Reply