[–] 2 points 7 months ago

I’ll try to add “hw:” in front of the device handles.

Generally that'd be required if you're using the hw:<card>[,device] device addressing, yes. You probably want to treat all device names, addresses, and handles as "opaque", though, meaning you don't care what the actual string looks like, and select your intended device through some other criteria.

That's where default comes from, in a way. It leaves the device choice to the user. I understood that you intend to access some other audio device, typically non-default. In that case it's ideal if you have any uniquely identifiable device information associated with the class of device you want to use, enumerate all "sound cards" to find those matching your criteria, and "hand down" the associated PCM handle to where you need it, without needing to know what it actually looks like.

Another way is to get a list of all "sound cards" of the system, and offer a legible selection of names/descriptions to the user in your application's options to explicitly select the correct device, and have an internal mapping of that selection to it's ASCII identifiers of PCM handles. Again, no need to know what the identifier looks like, you only need to match the user's selection to it's internal ID. This offloads the potentially difficult decision what device to use to your user, though, who may be even more lost being asked that question.

  • source
  • parent
  • context
  • [–] [S] 1 point 7 months ago* (last edited 7 months ago) (3 children)

    On function snd_pcm_open():

    name ASCII identifier of the PCM handle

    What does this mean exactly? What can I pass to it besides of "default"?

    Originally I tried the function snd_device_name_hint, but it only worked for MIDI devices so far. For PCM, it lists all kinds of things.

    Update: I'll try to add "hw:" in front of the device handles.

  • source
  • parent
  • context
  • [–] 2 points 7 months ago (4 children)

    The way is to use the appropriate ALSA library functions as mentioned in the associated docs, and see referenced examples for an outline how the flow is authoritatively supposed to look like, right from the tap.

    Please elaborate "weird results for some reason" with minimal examples, as in "this is what I get running this code, and that is what I expected". More often than not, the process of writing up your problems for external review leads to understanding, or at least to a couple good ideas what you might be doing wrong, or expecting to work differently.

    The ALSA API is dense, and very C. It's super-easy to make wrong assumptions about how things should work there. Great training for slogging through API docs, though. :)

  • source
  • [–] 3 points 7 months ago*

    Here's a little secret: All data types don't actually exist. When your code is compiled down to machine code your computer just operates on collections of bits. Types are a tool we use to make code more understandable to humans. int and unsigned int tell us information about how numerical values are interpreted. bool tells you that only two values are going to be used and that the value will somehow relate to true/false. char tells us that the value is probably some sort of text. But again, everything is just stored as bits under the hood.

    You can go even further and define new types, even though they might still just be numbers under the hood - you could for instance define a new type, e.g. Age, which is still just an integer, but it tells you the reader more information about what it is and what it might be used for. You might define a new type just for error codes, so at a glance you can see that this function doesn't return an int, it returns an OsError, even if the errors are actually still just integer values.

    C does however play somewhat loosely by these rules, and to try and 'make your life easier' will often 'coerce' types between eachother to make everything work. For instance, integer types can be coerced to booleans - 0 is false, everything else is true (even negative values). Later on you'll find that arrays can 'decay' to pointers, and other fun surprises. Personally, I think this implicit coercion between types is one of C's biggest mistakes. If types exist to help humans reason about code, what does it mean if the compiler needs to silently change types behind the scenes to make things work? It means the humans were sloppy and the compiler can only guess at what they actually wanted to do (and this is the best case scenario! What happens if the compiler coerces types in places humans didn't expect? Bugs!).

    There exist a spectrum of different behaviours in this regard, some languages are what we call 'weakly typed' (like Javascript, or to a lesser extent C) and other languages which are 'strongly typed'. Weakly typed languages will try to implicitly convert types together to make things work: In Javascript if you try and add an integer to text "Hello!" + 52 the compiler will try to implicitly convert types until something makes sense, for instance in this case the compiler would say 'oh, they probably want to add the text "52" onto the end' and will produce "Hello!52". Sometimes this is handy, sometimes it introduces bugs. A strongly typed language will instead simply refuse to compile until you make the types line up.

  • source
  • [–] 3 points 7 months ago*

    C++ actually does this 'optimisation' for std::vector<bool>. I say 'optimisation' because it effectively trades time for space, which is usually the opposite of what you want - space is cheap, time usually isn't. Sometimes it's a good tradeoff though - it's common in embedded development where you might only have a few kB of RAM.

  • source
  • parent
  • context
  • [–] 1 point 7 months ago* (last edited 7 months ago)

    Good point. Yeah, my "probably" is doing a lot of heavy-lifting there. Thx, I've added a short sentence.) In reality we don't really know the length of a bool nor an int type in C. Likely a bool is 1 Byte and an int is 4 Bytes. But that depends on the architecture and compiler. The bool it guaranteed to hold 0 and 1, so it must be at least 1 bit. But with how addressing works, it ends up being 8 bits (1 Byte) anyway. If we want to be more efficient than that, I believe we have to code something with bit fields. It's a bit out of scope for a beginner, unless they do microcontroller stuff.

  • source
  • parent
  • context
  • [–] 2 points 7 months ago* (1 child)

    The way I make sense of it, is we sometimes return failure (i.e. from main). So 0 is no failure (aka success) and we can use the same thinking. The correct, expressive way to write it is probably use "EXIT_SUCCESS" and skip the ones and zeros. Pretty sure this comes from Unix. And with a lot of the other functions in cstdlib it's the same way as using integers as booleans. For example a "malloc()" will either return your memory or a null pointer and the 0 is the special failure case.

    But IMO the programming language shows its age and the context it was used in. More modern programming language design tends to be more strict with the types. Differentiate between interfacing with Unix stuff and other kinds of values. And we got more powerful concepts to deal with errors. So we don't always have to abuse the zero to say we ended up in some special case.

  • source
  • parent
  • context
  • [–] 3 points 7 months ago

    Okay, now... variableA = 1 (true) and variableB = 42 (true). Suppose we want to compare the values of them to see if they're the same or different. A simple check of if variableA == variableB will return False, because while they're both set to 'true', they're set to different values of 'true'. It could get problematic and become a way to introduce really weird bugs.

  • source
  • parent
  • context
  • [–] 8 points 7 months ago (2 children)

    First, if you do it with an int, you’re probably using up 32bits per value.

    One project I worked with stored boolean values as bits in an 8-bit int, and then used binary math to read and write individual bits from that int, with each bit representing a distinct and independent boolean variable.

    Really weird, complicated, and sounds kind of dumb ... but it worked, and it was extremely memory-efficient.

  • source
  • parent
  • context
  • [–] 2 points 7 months ago

    If u accidentally us the wrong type of variable it outputs en error when compiling. That's one of the main pros of statically typed languages and why the most reliable scripts are written in them to my knollidge. I'm sure there a languages out there where u can us boolean as a int or float but non i know. Not that i would consider my self a programmer but i asked the myself the same questions when i started.

  • source
  • [–] 18 points 7 months ago* (last edited 7 months ago) (12 children)

    I think there are several reasons. First, if you do it with an int, you're probably using up 32bits per value. You'd need 1 but waste the other 31, they needlessly take up storage. (Edit: Though your bool will most likely take 8 bit anyways due to other things.) And then sometimes it's nice to be expressive. So no one needs to remember if 1 is True or 0, or if True is greater than False, whether 2 or -1 map to True or False. And you end up in situations where either 2 equals 1, or True isn't always equal True. Or you do weird things to handle values other than 0 and 1 in the operations. All of that can be avoided and the code gets more readable with specific types.

    There's nothing wrong with using ints, though. You just have to make sure the maths stays consistent.

  • source
  • [–] 12 points 7 months ago* (1 child)

    code is read more often that it is written. booleans are actually just integers under the hood but explicitly using booleans communicates your intent. you're saying to the next guy that "if this is something other than 1 or 0 something has gone wrong".

    when it comes to C specifically, the bool type was a pretty late addition because as you say, an integer can do the job. but it's very good for organisation, and it also allows the compiler to make some assumptions about how the variable can be accessed. if you know something can only be in two states, you can shove a whole bunch of them into the same byte of memory.

  • source
  • [–] 2 points 7 months ago (1 child)

    Sometimes you need to store a value that is either true or false and refer to it later or maybe update it. Maybe you have some complicated logic for when a loop needs to end that you can't really represent in the while condition. You can make the while check your bool variable and then set it to false when you are ready to end. Perhaps you have a function that returns a bool value and you setup your logic so there is a default return value but you do some calculations and sometimes you want to return the other value. it lets you have a single return statement in the function which can be easier to read.

    You use boolean variables in the same way as other variables. The example you share is indeed contrived. In that situation you need no variables at all. That example is merely showing the syntax.

  • source
  • view more: ‹ prev next ›