We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Live-coding a music synthesizer

00:00

Formal Metadata

Title
Live-coding a music synthesizer
Title of Series
Number of Parts
130
Author
License
CC Attribution - NonCommercial - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
This is going to be a fun live-coding session using NumPy and SoundDevice. The goal of this talk is to make the computer produce realistic-sounding instrument sounds, using nothing but math. All the code will be written live and we'll hear the audio that it produces. We’ll start with creating a simple sound using a sine wave. We’ll gradually make it sound more like a real instrument, learning a little bit about music theory on the way. We’ll add features one-by-one until by the end of the talk, we’ll hear our synthesizer play a piece of classical music.
Roundness (object)2 (number)Meeting/Interview
Software developerTurtle graphicsOpen sourceTouchscreenArtificial lifeTurtle graphicsSoftware developerBitTheoryMusical ensembleProjective planeMultiplication signTraffic reportingHarmonic analysisCodeRight angleMathematicsWritingProcess (computing)Open sourceSoftware repositoryJSON
Musical ensembleCodeCodeComputer programmingLibrary (computing)Real numberDifferent (Kate Ryan album)Computer animation
MaizeMeta elementRepository (publishing)Source codeRow (database)Formal languageReading (process)Computer programRevision controlPressureLibrary (computing)Web browserWeb pageRight angleMultiplication signFrequencySineSource codeJSONProgram flowchartDiagram
Module (mathematics)MathematicsSineBit rateSample (statistics)FrequencyVolume (thermodynamics)Musical ensembleShared memoryMathematics2 (number)Point (geometry)Image resolutionNumerical analysisFunctional (mathematics)Sign (mathematics)SineLibrary (computing)
SineMathematicsRange (statistics)PressureIcosahedronBitPressurePlotterMultiplication signNumerical analysisTask (computing)Point (geometry)Quantum stateComputer animation
SineMathematicsSatelliteVolumeCommodore VIC-20TuplePressureMatrix (mathematics)Musical ensembleFinite differenceDialectRight angleTask (computing)Volume (thermodynamics)Figurate numberLevel (video gaming)Bit2 (number)Potenz <Mathematik>Well-formed formulaSelf-organizationLogical constantNeuroinformatik
Musical ensembleUniform resource locatorPosition operatorMereologyString (computer science)FrequencySound effectPoint (geometry)Set theoryTracing (software)Numerical analysisLengthTheoryPolygon meshPopulation densityLoop (music)Different (Kate Ryan album)Thread (computing)OctaveSineLecture/Conference
VolumeSineMathematicsSatelliteRange (statistics)Web pageNumerical analysisProcess (computing)Loop (music)FrequencyPlotterIteration
SineVolumeRange (statistics)MathematicsPressurePower (physics)Plot (narrative)Right angleFrequencyFisher informationCodeDistortion (mathematics)Computer animationDiagram
Musical ensembleVolume (thermodynamics)LogicRight angle1 (number)Range (statistics)
Range (statistics)SineVolumeMathematicsGauge theoryPressureOpen setLengthInterior (topology)Musical ensemblePressure2 (number)Social classResultantRange (statistics)Right angleTask (computing)ExpressionSineCodeMathematicsPower (physics)LengthSign (mathematics)Volume (thermodynamics)Constructor (object-oriented programming)FrequencySampling (statistics)Computer animation
CodeSequenceVolumeMathematicsInterior (topology)TupleMusical ensembleSequencePressureElectronic mailing listSocial class2 (number)Multiplication signInterface (computing)LengthTask (computing)Inheritance (object-oriented programming)Source code
SequenceTupleVolumeMathematicsRange (statistics)Row (database)SequenceInheritance (object-oriented programming)Computer animation
CodeLattice (order)SequenceTupleScaling (geometry)Different (Kate Ryan album)Well-formed formulaMultiplication signPower (physics)Task (computing)Musical ensembleSource codeComputer animation
CodeTask (computing)OctaveMusical ensembleLevel (video gaming)Computer programmingLecture/ConferenceComputer animation
SequenceTupleVolumeRange (statistics)LengthChi-squared distributionComputer programmingRandomizationCalculationThread (computing)Multiplication signHarmonic analysis2 (number)Module (mathematics)ExpressionMusical ensembleMathematicsPressureFlow separationStreaming mediaSource code
EmailVolumeRange (statistics)Interior (topology)SequenceTupleAxiom of choiceRight angle2 (number)Task (computing)DebuggerGastropod shellReal numberSource codeComputer animation
SequenceConvex hullEmailVolumeLengthMathematicsExterior algebraRight angleMultiplication signCodeMusical ensembleProjective plane2 (number)Implementation
CodeMusical ensembleSequenceAxiom of choiceRange (statistics)Random numberInterior (topology)MIDILibrary (computing)CodeElectronic mailing listFile formatSource codeJSON
Continuous trackEmailMIDILambda calculusMessage passingTupleFingerprintMeta elementVelocityFraction (mathematics)Electronic signatureFormal languageMetadataMIDIType theoryVelocityVolume (thermodynamics)Message passingMultiplication signMereologyComputer fileKey (cryptography)Electronic signatureTrailCodeMusical ensembleSource code
SequenceTupleRange (statistics)LengthMathematicsEmailVolumeMessage passingMIDIReverse engineeringElectronic data interchangeMIDISequenceMusical ensembleVolume (thermodynamics)Multiplication signElectronic mailing listMessage passingSource code
Message passingFraction (mathematics)Meta elementMathematicsVelocityElectronic signatureVolumeSequenceMIDIElectronic data interchangeMathematicsMessage passingGame controllerExpressionNumerical analysisMultiplication signVelocityVolume (thermodynamics)Source code
Message passingMeta elementTrailVelocityElectronic signatureSequenceMIDIEmailMultiplication signSoftware bugOcean currentNumerical analysisSource code
SequenceMIDIMessage passingVelocityMusical ensembleTupleMusical ensembleJSONXMLUML
Maxima and minimaSequenceMessage passingMIDIVelocityMusical ensembleCodeSoftware repositoryLine (geometry)Reading (process)MIDIJSON
Multiplication signRow (database)Zoom lensArtificial lifeCodeComputer animation
SequenceMessage passingMIDIVelocityDifferent (Kate Ryan album)Text editorMultiplication signVector spaceStreaming mediaLevel (video gaming)PressureLoop (music)CalculationCodeLine (geometry)WindowCommitment schemePerfect groupSource codeComputer animationMeeting/Interview
GoogolConvex hullSoftware repositoryRight anglePerfect groupCoefficient of determination2 (number)Multiplication signSource codeComputer animationMeeting/Interview
Transcript: English(auto-generated)
Welcome to the second round of talks in EuroPython. I hope everyone is having fun. Oh, we have a very full room. So, this is Rem Ratcham. I'm really sorry I'm pronouncing your name wrong. That was close.
Welcome, welcome. So, tell us where you're streaming from. Hi, I'm coming from Tel Aviv, Israel. Cool. Cool. How's the weather there? It's as hot as always. So, Rem, please, the floor is yours. Take it away. Sure. Hi, everybody. Let me share my screen. Welcome to my talk. This is going to be a music-oriented talk. It's going to be a talk about live coding and music synthesizer.
So, this is going to be a live coding talk, meaning I'm going to write code live, I'm going to explain what I'm doing, and I'm going to show some things about music theory. I'll give you some backstory for this talk. When I was 17, I wanted to learn to play bass guitar. I got my bass guitar right here. I'm going to show some stuff on it later.
I got myself a teacher to teach me how to play bass guitar. He taught me, and he also taught me something interesting called overtones or harmonics. That was when I was 17. A couple of years back, I remembered what he taught me about overtones, and I thought,
can I take that and use Python to make sounds that sound like a musical instrument using math? I tried that a couple of years ago, and it worked, and it blew my mind. I figured I'm going to do the same thing in front of an audience, and I'm going to explain what I'm doing, and I'm going to blow your minds. That's the story of this talk.
All the code for this talk is in the GitHub repo you can see here, and every commit there is a step that I'm going to do here. A little bit about myself before I start. My name is Ram Rakhun. I'm a long-time Python developer. Many people know me by my projects, my open-source projects, PySnoper and Python
projects like CPython, Django, PyPy, Matplotlib, and a bunch of other projects. I organized the Israeli Python community, and I quit my job a few months ago. I'm looking to move to Europe, maybe Germany. If you have interesting job offers, please talk to me. Let's get started. The final goal for this talk would be to make a Python program
that plays a musical piece, and we're going to get there step by step. I'm going to explain each step as we go forward. The last goal is to play the musical piece. We're going to start with playing the simplest possible note. We're going to make it sound good. We're going to make the code elegant. We'll play a bunch of notes. We'll play different
notes. We'll play lots of notes. We'll play notes real fast, and the very last step would be to play a musical piece. The first step would be to play a note, and we're going to need some kind of sound library for Python. I found one called sound device. It's got a GitHub page. It has documentation, right? You import sound device and just run sound device.play,
and you give it a NumPy array with your sound data. First, I'll explain something about sound waves. Here is the simplest possible sound wave, right? This is a sine wave, air pressure
over time, right? Air pressure is oscillating over time, so that's what we're going to try to do in Python. Feel free to ask me questions during the talk. Just send them in chat, and our session chair is going to read them to me. I'm going to import math. I'm going to
need to do some math stuff, import sound device. I'm going to use NumPy, and I'm going to use to plot my wave. Okay. Here is the simplest possible sine function.
Now, I want to add music-related stuff to it, so I want to add the volume to it so I can control the volume, and I want to be able to determine the pitch, the frequency of the sound.
Let's write down numbers for these values. I'm going to use 440 hertz, which is an A note. I'm going to do a duration for the sound of two seconds, and I'm going to do a sample rate of 8,000. The sample rate is like a resolution for the sound. It determines how many sound
data points per second. I'm going to put all that in a nice sine function, and now I want to plot it and I want to play it, but before I can do that, I said that the wave is a wave of air pressure over time,
so I'm going to have to create a NumPy array for the time and a NumPy array for the air pressure. So, let's do that. The time array is just the simplest linear array,
and the pressure array is a bit more complicated. I'm going to go over each point in the time
array and I'm going to calculate the pressure for that time point, and I'm going to populate the pressure array that way. Let's plot it to see whether it looks good.
Okay, this is our sound wave. So far, so good. Let's try playing it.
We have the simplest possible note. Let's listen again. Okay, so we did task number one, play a note. The next task is to make it sound good, right? Right now, this kind of sounds
more like a dial tone than a musical instrument, right? Our goal is to make that sound sound just a little bit more like this, right? So, now we're comparing these two sounds. We want this
to sound like this. Okay, the first difference you might notice is that the volume for the computer-generated sound is constant, while the volume for the guitar starts off as loud and
then becomes gradually more quiet. So, we can implement that in Python. Let's call exponential decay. So, I'm just going to add a figure for the volume, and I'm going to use
the formula for exponential decay. It requires one constant, half-life. Half-life meaning how many seconds it takes for the volume to become half of what it was. So, I'm going to use 0.3 seconds.
Okay, let's listen to that. Okay, this is better. Now it's kind of sounding like a cheap organ,
and now I want to take it to the next level. Okay, still this sound doesn't sound as warm as this sound, right? So, what is the magic in this sound?
I'm going to try to explain that. I'm going to show you something about music theory,
something called overtones. But first, I'll give you a refresher on frequency and pitch of sounds. Let's say I'm playing a string. The string is making a sound with a frequency X or a pitch X, and that is determined by a few things. The density of the string, the tension of the string, which is determined by the tuning pegs, and the length of the
string, which is the only thing I can actually change. If I play an open note, I get X, but if I press on the frets, I'm making the effective length shorter, so I'm getting a higher frequency. If I'm pressing on this fret, this fret is just at the middle,
so I'm making the effective length half of what it was, so the frequency is 2X, so I'm getting a note that's one octave above the original note. Okay, so far that's what most people know about the strings and music. Now I'll show you something called overtones. So, I'm going to show you a trick I can do. I'm taking my finger
and I'm putting it on this string and I'm plucking it, and it's making an interesting sound. Now, I haven't pressed on the fret like I'm playing, I just really lightly touched it while I was plucking, and I can even let it go and it keeps on going. And I can do this trick only in a number of positions. I can't do it here. It won't work. I can do it here, and here,
and here, and here. I can only do it in a few special locations. So, what makes these locations special? What are these sounds, and what does that have to do with making a realistic sounding
sound? These sounds are overtones, and these special locations, this one divides the string into two equal parts. This spot divides the string into three equal parts, one, two, three. This spot divides the string into four equal parts, one, two, three, four, etc. And
when I'm putting my finger here, for example, I'm forcing the string, because my finger is chubby and fluffy, when I touch the string, it can't move at this location. So, when I pluck it, it's making one wave here and another wave here, and these are opposite waves. So,
the effective length of the string would be one half, so the frequency is 2x. And if I do the trick here at the third point, I'm dividing the string into three equal parts, getting three opposite waves, and the effective length is one third, so the pitch is 3x. So,
x, 2x, overtone number two, 3x, overtone number three, 4x, overtone number four, and so on. Five, six, seven, eight. Okay, so that's a nice trick, but what does that have to do with making a sound that sounds realistic? When I play these overtones now,
I isolated them, which means I played just them without anything else, because when you play any regular note like this note, you're not playing just x, you're not playing just the base frequency. All the overtones are actually in each and every note, so when I'm playing any note like
this, it has trace amounts of this, and this, and this, and this. They are all mixing together to one note. People who are more musically inclined, when I play this, they hear traces of this. Personally, I don't have that kind of hearing, I can't hear this inside of this,
but this cocktail of overtones is what gives the note its character. And it also explains why some notes sound good together and some don't. For example, let's say I take these two notes. Each of these come with their own set of overtones,
and so it just so happens that overtone number three of the first note is almost identical to over note number two of the second note. They're almost identical, so they sound really good together because their overtones kind of mesh together. And if I were to take two
notes that don't have meshing overtones, like these notes, they will sound terrible together. So, overtones are responsible for a lot of what we feel when we hear music. Okay, so far that's interesting. Now we can just take everything that I explained to you and
implement it in Python. These overtones, they are just sine waves, sine waves with different frequency, x, 2x, 3x, 4x. We can just have a Python loop that just goes over all of them, adds them together, and let's see what happens. I'm going to go on a loop from 1 to 8,
and I'm going to add a wave for each iteration. Okay, and I'm multiplying by i here, and the i has a job of being the 1x, 2x, 3x. So, the i is the overtone number.
Let's plot this wave. Okay, this is an interesting looking wave, right? I'm not sure what to do with this information, but let's listen to it. Okay, this is an interesting sounding sound.
Let's listen to it again. This to me kind of reminds me of a guitar on distortion, like an electric guitar with a distortion pedal. Why does this sound distorted? There was
something you might have noticed when I was playing the bass earlier, when I was showing the overtones, something I didn't account for in my Python code. So, I'm going to play the overtones again, and I'm going to see whether you notice. Okay, here are the overtones again.
So, yeah, they start off as loud, and they become more quiet as I go higher up, right?
This one's pretty loud, so is this one, but then they really get quiet, right? So, it seems that the volume should be lower. I mean, the higher we go with the overtone, the lower the volume should be. So, let's add that logic in Python. Instead of having just a range
for the overtones, I'm going to have a dict, and I found that this expression is a good one.
One over i to the power of one and a half. I found it gives the best sound. Okay, so the
change I made here is that from now on, every overtone has its own volume that I use to multiply. Okay, this is what the wave looks like. Kind of a steeper send. I don't know what to think about that. Let's listen to what it sounds like. Okay, this is much better, right? It kind of
sounds like a cheap piano. So, this is our sound, and I'm happy with it. So, we finished the task of making the sound sound good. Let's listen again. Now, you might be asking yourself,
why does this sound specifically like a piano and why doesn't it sound like a guitar or like I don't know, a violin or a saxophone or any other instrument? The answer is I have no idea. I just randomly tried stuff. It ended up sounding like a piano. I was happy with that.
One more thing I'm going to do, I'm going to lower the volume because we're going to play a bunch of notes. That's still audible, right? Yes. Cool. Next thing I want to do, we're going to do a lot more complicated stuff, but I want to make the code elegant so I could work with it. I want to take all of this code and put it in classes. I'm not going to write too much new code.
I'm just going to take the functions and put them in a class. I want the end result to look like this. I want to be able to create a note with a certain frequency and play it. So, I'm going to make a note class, and that's going to take a frequency,
a volume, and it's going to have a length. Let's say each note has a length of one and a half seconds, just to keep it simple. This sine function is just going to be the pressure
method for this note. The frequency wouldn't be a constant anymore and neither will the duration
or the sample rate. I'm going to take the code that plays the note and I'm just going to put
it in a play method. Okay, I've got my play method and I've got my get pressure method.
I've got my constructor. Let's see whether this code works. Of course it doesn't. I forgot to change from sine to get pressure. Let's try again. Okay, same sound as before, right?
Just now it's with classes, now it's easier to work with. So, our code is now more elegant. Next task, I want to play a bunch of notes. So far, we've played just one note. Our final goal would be to play a full musical piece, so we're going to have to play a sequence of notes one after the other. Let's say that the interface would look like this. I'm going to
create a sequence of notes. For each note, I have to include the note itself and the time offset.
Here's an example of a sequence I might make. Five notes, 0.2 seconds between each note, and it's the same note just over and over again. I'm going to have to create a class sequence, and it's going to take a list of members. I'm going to have to figure out the
length of the sequence. That's just going to be the very last member. That's just going to
be the very last note, the length of the very last note. I'm going to create a get pressure method for this sequence. I'm going to make them share a base class. They are both going to be subclasses of audio. I'm going to move the play method
to the base class. You could play both a note and a sequence. I've got my sequence, and how do I calculate the air pressure of the sequence? Just add up all the notes, taking the offset into account. It's going to look like this. Let's see whether that works. Great. I got five
notes playing in a row. I got a bunch of notes. Let's see how I am on time. Okay, I'm doing
great on time. If there are questions, feel free to send them. No questions just yet, but awesome talk. Thank you. My next task is to play different notes. So far, we've played the same note five times. I want to play different notes, different pitches. I'm going to show you
the formula for that. I'm going to play it, and then I'm going to explain it. Okay, so now we have lots of different pitches. Let's listen again.
You must be wondering, what is this? Why am I multiplying by two, raising to the power of something over 12? So I'm going to explain. The reason we're raising two to the power of something is because the musical scale is a logarithmic scale. What is it with a 12, right? Why do we have zero over 12 or four over 12 or seven over 12? That's because
this octave is divided to 12 semitones. There are 12 frets between x and 2x. So that explains this math, and now we have different notes. The next task is to play lots of notes. We're going to play a musical piece. It's going to have maybe a thousand notes.
We need to be sure that our program can handle a thousand notes. So let's start with just a hundred notes. I'm going to do a generator expression. I'm going to do random pitches. I'm going to use Python's random module. I'm going to choose a random note, and I'm going to play
a hundred of these notes in intervals of 0.3 seconds between them. Okay, let's listen to that.
Now we have a problem. I press play. I asked the program to start playing, but it's not playing. It's not playing because I gave it a hundred notes to play, and it needs to calculate all of that data before it can play it, because it's a lot of data. It's now going to wait a long time before it can play that. So we want to fix that. We want to be able to play
immediately, and the way we're going to do that is streaming. We're going to play while it is calculating. Let's go to the play method. We initialize the pressure array. We fill it up with data, and then we played it. So I'm going to make a small change. I'm going to initialize it, then I'm going to start playing it on a separate thread,
and then I'm going to calculate it. So the calculation is going to be going on while sound device is playing the music in a separate thread. So let's try that, and from now on I'll be using Python on the shell rather than my debugger.
Okay, that works. Now it's going to play a hundred notes. So I'm going to stop that. Okay, this task is over. We're almost done. Now we want to play notes real fast. Why is that a challenge? Let's see. Instead of 0.3 seconds between each two notes, I'm going to do
0.08 seconds. Okay, did you just hear it stop abruptly, right? I'm going to make it even faster. It stopped abruptly. Why did it stop abruptly? Because I was giving it so much work
to do. It can't calculate as fast as it plays. If I wanted to fix this, I would have to make the code more performant, faster. I would have to optimize it to go over the code five places where I could do things faster and then improve them. I don't have time for that at all. I want
a solution that's going to just make everything faster without me having to think about it at all. Can anyone guess what I'm going to do? I'm going to use PyPy instead of Python,
right? It didn't stop. PyPy is an alternative implementation of Python, second alternative to CPython. It is faster. They use alien technology from the future to make Python maybe three or four times faster than CPython. If you're not familiar with it,
it's an amazing project. Check it out. It can just magically make things faster. Now our code can play notes really fast. The last step would be to play a musical piece. So far, when we've given our code notes to play, we've just given them manually just a list of notes and offsets. There is already an established format for giving a list of notes
and offsets, and that is called MIDI. I got myself a MIDI file, and I got a library called MIDI for Python that can open MIDI files. Let's play around with that and see what it looks like. I'm importing MIDI, and I'm going to open my MIDI file. It's a MIDI file of type one,
whatever that is. It has two tracks, whatever these are, and 561 messages. I can put it in the tuple, and I can look at the messages. Let's look at the first 10 messages.
Okay, there seem to be all kinds of metadata messages here. There's a time signature, key signature, tempo, and track name. Let's look at the middle of the file. Here we see more interesting messages. There are note on and note off messages, and the messages, let's look at the note on messages. They give us a pitch of the sound,
which is the note equal 60 part. They give us the volume, which they call velocity in MIDI language, and they give the time, which is how long the note is playing. We're going to write code that goes over these messages, reads them one by one, and creates notes for them, and then plays them using our synthesizer.
So, I want the API to look like this. I want to create a MIDI sequence and then play it, and I'm going to do MIDI sequence as a subclass of sequence. It's getting a MIDI path,
and now we want to read this MIDI path, and we're going to go over the messages in this MIDI file, and we're going to add members. We're going to have a list of members.
We're going to add members. They're going to have a time offset, and there's going to be a note with a frequency and a volume, and when we're done creating these members, we're just going to initialize the sequence
with the members. Let's look at these messages again. We've got the note on and note off messages, and we've got all these control change messages, and I don't know what these do. So, I'm just going to ignore all the messages that aren't note on, and now my challenge is to
fill out these question marks. I've got to figure out the time offset. I've got to figure out the frequency. I've got to figure out the volume. The volume is easy. The message has what they
call a velocity, and the velocity is a number between 0 and 127. So, I'm just going to and the pitch. I'm going to do a similar expression to what we did earlier. They have a certain base note that they use, minus 621, if I remember correctly, and the last thing to figure out is
the time offset. So, they've got, for each note, they've got the amount of time that it takes, but we need to make an offset out of that. So, we have to make a tally of all the time offsets that we've had so far. We're going to initialize it at 0,
and we're going to add to it every time we see a time offset, and we're going to use that for the current time. I'm going to use first just the first five numbers to see whether this even works, and let's try playing it. Okay, I've got a bug.
Oh, right, I forgot to make a tuple. Now, let's play the entire piece.
Okay, this is the code. We have just 79 Python lines, including blank lines, and we have a full synthesizer that creates sounds and read MIDI files. All the code that I've written is in this repo, github.com, Python synthesizer, so check it out. If you have any questions, it looks like I
have around three minutes to spare, so feel free to ask any questions. I don't even know what to say. I wish I had my claps set up right now. This was incredible. When you get out of here at the Zoom room and you get into Discord, you're going to see we're talking all the way through it.
It was absolutely amazing. Thank you so much. Thank you. Well, I saved one question for you that seems like everyone wants to know. What are on those sheets of paper? All the code?
I mean, yeah, practice this like a hundred times. You can't do a 45-minute live recording session without practicing it a hundred times. So, that's the secret for everyone that was asking then. Wonderful. That was really, really, really cool. Like, everyone is that jaws are dropped everywhere. Thank you.
Thank you. You know, and I'll answer one question that I do get asked a lot when I give this talk. Lots of people ask me, what is this editor? Because most people don't know it, so this is called Wing ID. You know, most people are familiar with PyCharm, so that's like a different brand of PyCharm. It's a nice ID. Got lots of automation on it, so if you were wondering
how I'm moving so fast and doing all this automation, that's Wing ID. It's a really nice ID and I recommend it. Cool. Well, thank you for that. And then Matthew is saying, well, awesome talk, and then a minor comment. He's saying that he thinks you could vectorize the calculation of the pressure instead of doing it in a for loop.
Using map.vectorize, I used to do that. The problem is you can't stream when you're doing that because vectorize doesn't let you access the array as it is getting built. I was actually spending lots of time trying to find a good solution for that. Perfect. So, you thought about it beforehand. So, Vinayak is asking,
are there any gotchas to run all this on Linux? On Linux, I think there is like one more thing you have to add. You have to add a delay before it starts playing because the timing is different between Windows and Linux. You have to add one line for delay. I actually, in the code for this talk, I added it as an optional commit. I'm going to show it to you. The repo has a code commit by commit, so you can see all the
steps that I do. I did one commit that adds a delay that makes it work on Linux. This is the commit, and it just adds a delay just before it starts playing.
Perfect. Well, thank you for that. And, yeah, I have a question, actually, that we had like 30 seconds left. How long did it take for you to prepare this talk? I mean, I've given it in a couple of conferences before. I've spent way more time than I'd like to admit.
Okay. I will force you to tell me that. Perfect. Well, thank you. Thank you so much, Ram. It was incredible. It was one of the best talks I've ever seen. Thank you very much for coming, everybody, and enjoy the rest of the conference. Thank you, Lace, for sharing this session. My pleasure.