I learned to program (kinda) back in high school. I was assigned a really open-ended AP world history final project where we just had to something history related (and educational) in a medium of our choice. I told one of my friends I wanted to make a game for the project and he was immediately in. I downloaded whatever version of GameMaker by YoYo Games was available at the time (in 2010) and went at it.

We made this rather silly game based on the Protestant Reformation where you play as Martin Luther, nailing theses to the wall, and converting people to lutheranism. I learned the basic visual programming and scripting stuff available in GameMaker just by messing around and seeing what happened. The game was a bit with the class (most people did poster boards or presentations) and I remember the teacher being pumped we put so much effort into it (hand painted sprites and all).

I later ended up going to school for computer science and definitely learned more about programming there but mostly when I was trying to create something outside of normal school projects. The programming languages I use in my work I learned from personal projects. There’s a lot to be said about having an idea for something you really want to bring to fruition and putting the effort necessary toward it to make it happen!

3 Likes

From my personal experience, I would highly recommend starting with Max. It has really thorough tutorials and documentation, and everything works. You cover all the basics of programming, but in an easy to understand/visual way. Pure Data does not have good documentation, and it’s tougher to get external packages to add on. SuperCollider has a solid set of basic tutorials, but after that you basically just jump into the deep end. Coming from zero programming experience, there is no way I could have done SuperCollider, without having learned Max. C will take you forever to make a beep and you’ll have almost certainly given up by then.

1 Like

Most of my supercollider knowledge came from Eli, 24 videos in this playlist:

4 Likes
$ cat > main.c <<EOF
> #include <stdio.h>
>
> int main(void) {
>   printf("\a");
>   return 0;
> }
> EOF
$ gcc main.c
$ ./a.out
7 Likes

While I can’t determine myself if that snippet does in fact make a beep, I think my point still stands. A beginner would, in my mind, give up trying long before they could write a concise piece of code like that to make a beep. Further, could you now make that a major scale of beeps?

1 Like

as an exercise, here is a full C program that generates a major scale of sine waves in 32-bit, 48k, raw mono audio format. (suitable for import into audacity or whatever.) it has enough comments that i think each step should be pretty clear.

the point that i’m making, and that (if i may say so) i think @csboling was making in a, heh, bit salty way, is that C is the bedrock (either directly or conceptually) of most modern languages; each of its components is simple and not really that intimidating; but building things up from small blocks takes some effort of course.

you could easily refine this into just intonation, or add a lowpass to the frequency parameter (it’s clicky right now), or whatever. and it is perfectly portable and runs on most any modern or not-so-modern computer . (i just typed it up on windows 10 and built with gcc on the windows “linux subsystem.”)

this is an exercise that one might encounter in the intro chapters of a text like “the audio programming book” by boulanger & lazzarini, or “elements of computer music” by moore.

my point being that one shouldn’t necessarily be scared of starting at a low level of abstraction, it’s not really different from the SuperCollider level or the MSP level except in terms of presentation and the layers of abstraction available to you. this idea dovetails nicely with @ht73’s point, that one of the benefits of PD/Max/&c is giving you a nice environment of mid/high-level wrappers, if you are interested in a hands-on exploration of numerical details.

on the other hand, of course there’s no reason to specify things at the sample level unless it particularly appeals to you. anyways:

save as beeps.c
compile: gcc beeps.c -o beeps -lm
run: ./beeps
produces beeps.raw, import to your sound editor

// include some standard C libs
#include <math.h>
#include <stdint.h>
#include <stdio.h>

float midicps(float midi)
{
    // midi note 45 == 110 hz at A == 440hz
    // the difference between note 45 and the arg is the number of semitones
    // each semitone corresponds to a ratio of 2 ** (-1/12)
    return 110 * powf(2, (midi - 45) / 12);
}

// state variable to represent the phase of a sine oscillator
float phase = 0;
// sample rate
float sr = 48000.f;
// amount by which to increment phase per sample
// we will redefine this dynamically
float inc = 0.f;

// function to set the oscillator frequency
void set_midi_note(float midi)
{
    inc = 2 * M_PI * midicps(midi) / sr;
}

// the scale degrees of an ionian (major) scale
float scale[] = {
    0, 2, 4, 5, 7, 9, 11, 12
};

// function to update the oscillator value on each sample
float update_osc()
{
    phase = phase + inc;
    // wrap the phase. this isn't really necessary here, 
    // but could be if we let the oscillator run for an arbitrary time.
    while (phase > 2 * M_PI)
    {
        phase -= (2 * M_PI);
    }
    return sinf(phase);
}

int main()
{
    // duration of each note (0.2s)
    int notesamps = 4800 * 2;
    // current value of oscillator
    int32_t val;
    // open a raw sound file
    FILE *file = fopen("beeps.raw", "wb"); // binary write mode

    // root midi note (middle C)
    float root = 60;

    // number of scale degrees
    int num_degrees = sizeof(scale) / sizeof(float);

    // for each scale degree...
    for (int degree = 0; degree < num_degrees; ++degree)
    {
        // update the pitch...
        set_midi_note(root + scale[degree]);
        // and spit out some samples
        for (int samp = 0; samp < notesamps; ++samp)
        {
            // scale the sine output from [-1, 1] to a 32-bit signed integer range
            val = update_osc() * 0x7fffffff;
            // push the value to the file; it is a single 4-byte variable
            fwrite(&val, 4, 1, file);
        }
    }
    fclose(file);
}

on-topic, this kinda thing closely approximates how i learned to program, except in those days you could spit the bytes out to a PCM soundcard directly. i dunno maybe you still can.

11 Likes

the thread seems to be in violent agreement that (1) starting from zero might be intimidating and (2) that while worthwhile, a deep understanding can be gained in stages with various kinds of conveniences?

5 Likes

sure, i’m not disagreeing with anything. except… the general notion that “C is hard” or inaccessible or something.

parsing 75 lines of heavily-commented C that makes sine waves, should be a basic step, a shibboleth, not a super distant aspirational goal. you really should be able to compile + run that thing right now on *nix or in a few minutes on *doze. (it’s not as terse as possible because i am not doing code golf, here.)

and hey, bonus, it’s a pretty small step from that program to (some of my favorite music ever made):

that doesn’t mean you gotta make everything out of per-sample loops, that would be a waste of time for the great majority of creative applications. doing a couple exercises at the low level is good for getting at the high level too. the silly boilerplate stuff is about file pointers, memory sizes, &c… but the topic is “learning to program,” not learning about sinusoids or temperament, so those details are actually kinda important. (“hacking”. we’re not in the ][e days so you can’t just smash registers, you will just crash and it will be boring. but you can still do arbitrarily bad things to a bit of memory in C and hear those sounds.)

4 Likes

The biggest benefit of learning in MSP or PD, to me, is that it’s real time. Learning computer music in a real time environment allows for quick experimentation and the ability to break and fix small pieces while hearing the output. I found it invaluable for understanding signal paths and the effect of my ideas, where working with a compiled language adds abstraction in time due to the write>compile>run delay in hearing the results of what you’re doing.

I’ll also echo @zebra’s point that C doesn’t have to be scary, but it definitely gets complicated fast in ways that have nothing to do with your goals for the code (i.e. memory management). And that the middle layer of audio specific units that you get from SuperCollider/MSP/PD can be a great stepping stone for learning since it lets you focus on the sound more directly.

But for me the biggest difference is compiled vs real time.

5 Likes

I’m still sticking with my original argument that for this kind of person:

C would be intimidating to start with, and in that sense would be hard and inaccessible, and that they could probably encourage themselves to get into programming more easily by sending a bang out of a button in Max than by starting with C. Also I like this point:

You get positive feedback much more easily and quickly.

I think @alanza has really summed this up best:

3 Likes

Programming didn’t really stick for me until I started using it to make music and sound. That gave programming a purpose.

It also helped that I was determined to make music entirely on Linux, for whatever reason. There wasn’t much commercial music software available at the time, so (thankfully) Linux forced me to write my own tools. Also, Linux has such a dev friendly environment. The Unix approach to development is so simple and straight forward.

Oh! And this is critical… Csound. I was learning Csound because it was a sophisticated synthesis engine that could run on Linux. One of the best things about Csound is that it is text based synthesizer. It was trivial to write programs to generate Csound code. A little went a long way too! These programs weren’t just toys either. While simple, they were actually very practical. At the time, I was learning a little bit of Python and Perl.

Finally, learning Vim was a huge help. It’s a great text editor. But more importantly, it unified the physical experience of coding into a single interface. Instead of learning a new IDE for every language I wanted to learn, I just did it all in Vim.

7 Likes

I first got a taste of programming in college using R for Bio-stats. I was pretty late to the game in 2008. But my curiosity in programming stems from that semester using R. My knowledge base was essentially nothing, but I went through periods of personal breakthroughs and growth, and periods little to no gains. I still use R today, but more regularly use VBA and SQL for work, both of which I learned on my own and went through a similar growth process.

To expand entirely too much on my well-meaning shitpost:

You can make a beep with a computer with simple programs in lots and lots of ways! Some of them are certainly more interesting than others. This “hello world” variant should work in basically any language you can use to write a console program on the desktop. Printing the BEL character (escape code '\a') to the terminal exactly like this is probably one of the first ways I ever deliberately made a program make sound, I think a friend and I even had some goofy C or C++ program that would beep repeatedly this way with some pseudo-musical timing by just using spin-wait delays.

If one’s goal is to build specific effects or tools for audio processing, there are lots of awesome environments where this is going to be a lot less work than other ways you can go about it. Many of these will let you learn programming while also getting to do real-time audio stuff, visual programming, etc. out of the box, and that is very satisfying and can be very productive. But I think that if one’s goal is to learn to program, C can be a great place to start. It has relatively few syntax elements, it allows very direct manipulation of memory and files, it challenges and teaches valuable techniques through its constraints. It is also scurrying around somewhere underneath the feet of basically any other programming environment you come across. Writing software you will some day be well-served, especially if you want to involve real-time signal processing, by having a working knowledge of C. There is a learning curve as far as understanding the language building blocks but that’s true in every language or environment.

My immediate reaction to the sentiment that audio programming in C is too complicated for beginners to learn to make something musical before getting frustrated was “what’s the simplest C program I can write that makes a sound?” and I think that this would be a super fun way to structure a C tutorial – every program somehow makes sound, either by playing it directly, by creating a file, or other means. You can also use a lot of great libraries for abstracting away a lot of the complicated bits that you don’t want to deal with, nowadays there are even pretty good package managers for writing C/C++ programs. Here is an example I set up which uses Conan to install the cross-platform PortAudio library, then build the paex_sine.c example file to play a 5 second (loud! turn your volume down) sine wave. This should work on any platform as long as you have a C compiler and Python installed. That is easier said than done on some platforms but still I think fairly comparable to setup procedures for most programming languages. This also hides a fair number of details that it is also important for beginners to understand that don’t directly relate to the programming part – invoking the compiler, including and linking, etc. – but I think these can also be learned incrementally side-by-side with the actual programming part.

There is something really special about programming C or assembler that is hard to separate from how I think about software. Especially on a platform like a microcontroller with no operating system where nothing is write protected and writing to some addresses can do something tangible, there is a feeling of glimpsing what the machine actually is, encountering at once its elegance and power and fragility and capability for self-destruction, making lights blink and steppers step and BEEPS! I would most likely not have learned “how to program” in any practical sense, or at least would have had a much different path there, had it not been for my early experiences programming C. I value that a lot and having some of those engrossing experiences is something I wish for all programmers, beginners or otherwise.

That said, I frequently prefer to actually try and do music things inside environments where the hard work of building the tool, or at least the workshop, has been underway for a while – there is a framework in place where I can focus on “application logic”. Thankfully there are tons of platforms now where this is possible, and many of them can be easily extended in C, enjoying immediate interaction with the data without having to lay the groundwork first. On the other hand, living in a software environment you built yourself in some way is wonderful, the feeling of knowing roughly where to find things, or of understanding at a glance the complicated chain of events that would result in the bug you’re looking at, and feeling like you know where the secret tunnels go.


My first encounter with the concept of a computer program as something that could be written was stumbling across AppleScript on what I’m almost certain was called a Macintosh SE II, but Google seems unconvinced that such a model existed. Perhaps it was an SE/30? I had no clue what I was looking at, or what a “syntax error” was, which was all I could get it to say for a long time. I was looking for video games. I guess I came back to it enough times that I eventually figured out there was a record button, which would convert whatever else you were doing on the computer into text! From that I figured out some basics about available commands, and I managed to program it to, like, open a folder and slide the window around the outer edge of the screen. This would have all been copy-pasting and editing stuff the macro recorder spat out, I don’t think I had any concept of flow control until several years (and programming languages?) later. My parents seemed confused, but supportive.

After that I feel like K-12 was only occasionally punctuated by intervals in which I was not farting around trying to teach myself to program something. Misadventures included: endless if-else trees of Visual Basic dialog boxes composing a short and deeply uninteresting choose-your-own-adventure text game, being given and reading the first chapter of a half dozen or so different books on C++ before getting bored, a stream of harebrained toy programs, failing to understand some web tutorials on SDL and OpenGL in service of some nebulous fantasies about making video games, really bad Geocities-cliche type websites making prominent use of <embed src="ff3_kefka.mid"> and bearing no regard for the idea of a “closing tag”.

In retrospect I think I was a pretty awful and unfocused learner and absorbed way less from these experiences than I could have, not for a lack of trying on other people’s part. When I was introduced to microcontroller programming in high school something clicked, I started to understand why C was designed this way, which I don’t think had really been conveyed in the course of my earlier attempts to learn C++. After that I started to get more serious about it, went to college, yada yada.

5 Likes

tbh I feel like the thing that intimidates me more about DSP at the C level is the additional understanding of sound rather than code. It’s not a huge mental leap to write code per sample and the syntax isn’t rlly that bad, but I’m too used to the mathematical stuff that even shitty max/msp objects have baked in (i.e. filtering, interpolation, unit conversions).

feel like there’s a lot more resources for learning code compared to audio/digital sound - though maybe this is a good place to ask abt that.

The STK has a lot of these low level building blocks, plus some exotic things like banded waveguides.
https://ccrma.stanford.edu/software/stk/

3 Likes

i agree - the point i was trying to make is that “DSP at the C level” is just “DSP.”

the question was “how did you learn to program.” for me and a lot of people, that was with C, and it continues to be useful. i still think that in an objective sense that is the “best” way to learn programming, which is not the same as learning computer science or audio DSP - C is ubiquitous, simple, performant, close to the machine; it forces you to learn about abstraction and architecture; there are an endless number of high-quality resources, libraries, and examples; and unlike Max/MSP it is free.

but really the “best” way to learn something is to do it, and in this context the language is probably not as important as just having a project and executing it from start to finish.

since my livelihood involves coding, i also continue to do exercises on codesignal.com whenever i can and in as many different languages as i can, to stay flexible. i highly recommend doing this; it is very helpful for me to be able to read and modify code in ruby, haskell, dart, kotlin, swift or whatever. similarly, rosettacode.org is a cool resource.

now you can use gen~ or WebAudio to very easily process a block of audio samples. which will not teach you much about programming. whatever, many/most people don’t actually want/need to be general programmers.

learning DSP and math is definitely harder. it’s been discussed quite a bit on various threads and there are a lot of book recommendations. my personal favorite is probably the steiglitz primer which is admirably short, clear and to-the-point.

13 Likes

Thanks for these tips.

I’m in an odd place right now with regard to programming. Started coding at the age of 9, and did it professionally from '98 to '06, but have since drifted further and further away from coding as a primary pastime.

So, now I’m looking at starting over. In some ways it feels like starting from scratch. It’s pretty exciting, but also in many ways just as overwhelming as the first time through.

Has anybody else come back to coding after a long hiatus? I was a pretty solid coder back in the day, but I’m so rusty now that I’m lacking all confidence.

1 Like

BTW, i’m also a fan of the pragmatic programmer.

for me, the biggest challenges in the craft of programming are not gaining fluency in syntax or algorithms. those are the fun parts, which can be easily pursued as a hobby or game. the hard parts are things like managing project scope, defining requirements, establishing unit tests, refactoring, and all the “other stuff” that you can’t learn from a language reference.

8 Likes

While we are talking about great sites to “practice” programming doing https://adventofcode.com every year is incredibly fun for me, and serves as a nice refresher for more algorithmic knowledge.

1 Like

I hear ya. DSP code at the C level is mostly a bunch of arithmetic operations and trig operations. You can’t look at C code and grok it the same way you can with other data structures and algorithms IMO. You need to really know the mathematical notation.

2 Likes