Hacker Public Radio

Hacker Public Radio

Hacker Public Radio is an podcast that releases shows every weekday Monday through Friday. Our shows are produced by the community (you) and can be on any topic that are of interest to hackers and hobbyists.

Episodes

  1. Oct 16

    HPR4750: Playing Civilization VI Part 2

    This show has been flagged as Clean by the host. Civilization VI brought in one new Victory type, Religious, and made modifications to the other familiar types. So in thie episode we do a survey of different ways you can win this game. Playing Civilization VI, Part 2 Victory Types Another area with some changes from previous versions is Victory Types. Of course, some things stay the same. You can always win by building a big military and going on a rampage and wiping out all opposition. This never changes, and it can be a lot of fun. But the existing Victory types have received some modifications, and one brand new one, Religious victory, has been added. In this discussion I will assume you are at least up to the Gathering Storm expansion, since that has the latest Victory rules. Science Victory This is still basedon getting out to the stars, but the details have changed, Up to Civ V it was based on building or launching a spaceship, with Building being the major part of it. But in Civ 6 it is more based on achieving certain projects before anyone else. It all starts with researching Rocketry, then building a Spaceport, and then completing the Launch Earth Satellite project. But that is only Phase 1. You then need to research Satellites. And you might wonder why that isn’t necessary to research before you do the Launch Earth Satellite project. Well, the answer is they did it this way, so deal with it. Think of it as the difference between simply achieving a launch, like Sputnik, and developing the advanced satellite technologies like Remote Sensing, Communications, GPS, etc. In any case, once you have researched Satellites, you can do the Launch Moon Landing project. Then you research Nanotechnology, which lets you complete the Launch Mars Colony project. From there you research Smart Materials, and that lets you finish the Exoplanet Expedition project. This expedition then needs to travel 50 light years, and normally it travels one light year per turn, so you would need to wait 50 turns to win. Meanwhile, any other player could win while you are waiting. But you can speed up your expedition by building Laser facilities, some in orbit, others on Earth. While you obviously need to do a lot of research to get to these technologies, you also need a lot of Production to build the projects. So make sure you have a high production city and place your Spaceport there for maximum benefit. And make sure your enemies cannot take out your Spaceport. Culture Victory Although it is called a Culture victory, it is more technically a Tourism victory in terms of the mechanics. This is a fun Victory type to go after. What you want to do is make all of your cultural offerings so compelling that your own people would stay home rather than travel abroad, and so that you attract tourists from other players. Keeping your tourists home is your defense against other players, and attracting their tourists is your offense. If your number of tourists attracted from other players exceeds any other player’s domestic tourists, you become culturally dominant over them. And when you are culturally dominant over all other players you win a Culture victory. So how do you do this? Mainly by focusing on things tourists like to visit. This can be great works of Art, Writing, and Music, but it can also be things like National Parks and Seaside Resorts. And there are Policy cards that can increase your Tourism. Domination This should be simple, just build a lot military units and start laying waste, right? Well, of course isn’t that simple. While you are doing this you don’t want your future victims to gang up on you. The basic criterion for a Domination victory is that you control all of the original capitals of the original players, whether or not they are still in the game. Original capitals cannot be destroyed or plundered, but they can be captured. Now, capturing someone’s original capital is likely to cause harsh feelings on their part. But if Player A has captured player B’s original capital you can then conquer it without the same level of penalties. And there are penalties built in to the process. If you are viewed as a warmonger other players wil start to gang up on you. So what you want to do is never fight a 2-front war, to begin with. Only have one war going on at any time, and ideally allow a cooling off period after you capture the original capital. You want to keep the other empires on your side as much as possible. and a good way to do that is wait until you have a Casus Belli with them. This means they have done something to you that entitles you to righteous reaction. There are a number of them, but one my favorites is when they steal one of your technologies and are identified as the thief. That will give you a Casus Belli. If I would rather be at peace, I will usually ignore that, but if I wanted to go to war I would gratefully sieze the excuse. Also note, your objective is to get original capitals, not to wipe them out totally. Conquering the last city of another empire will give you major warmonger penalties. Religion This is another major change in Civilization VI. The whole Religion thing is completely new, and there is a Religion victory you can win. This is another fun victory type to experiment with. The victory condition is simple to state, you just need to have your religion be the majority religion in every empire still in the game. It is how you get there that makes this very interesting. Some of your religion spreads naturally from your cities to other cities nearby, but you can also create Missionary and Apostle units to speed up the process. But there is a defense to this as well. The other empire can create their own Missionary and Apostle units to evangelize against you. And they can engage in Theological Combat. This can only be initiated by Apostles and Inquisitors, but it can result in the losing unit being killed. Think of it as if they are calling on God to smite the devilish heathens and it actually happens. And in some circumstances when an Apostle is killed in theological combat a Holy Relic is created, and this can add to your Culture and Tourism. We’ll talk more about Religion and Theological Combat in a more detailed look at Religion in this game. Diplomatic This is a bit different from the Civ V Diplomatic victory. Instead of winning a vote in the World Congress/United Nations, you accumulate Diplomatic Victory Points. If you accumulate 20 Diplomatic Vicgtory Points you win the game. So where are these to be gathered? The first is that being on the winning side of a vote to Target or to cause an Outcome in the World Congress is worth 1 Diplomatic Victory Point for each such vote. Building certain Wonders. The Mahabohdi Temple is worth 2 points, the Potala Palace is worth 1 point, and the Statue of Liberty is worth 4! Since machinations in the World Congress can take away points, a good strategy is to get within 2-3 points of Victory and then complete the Statue of Liberty. Seasteads, a Future Era Tech, and Global Warming mitigation, a Future Era Civic, each are worth 1 point. Periodically you will get a chance to respond to an aid request from another player in the World Congress. If you provide the most aid, you get 2 points. Having a big Treaasury makes it a lot easier to pull this off. Score Should no player win by any of the above Victory types, the winner will be the person with the highest score. This doesn’t happen often, but it can happen. Changing Horses You should also be flexible. Circumstances can change as the game goes on, and the original Victory type you were aiming for is looking like bad bet. When that happens you should re-evaluate your options and perhaps pursue a different Victory type. And I have played games where a different Victory type just kind of happened. But any decision you make should be an informed decision, and the game interface is helpful here. In the upper right there are a few buttons, and one of them is called World Rankings. Clicking this button will tell you where you are versus your competitors for each of the Victory types. This is is a popup window that you should consult periodically as the game gets going. One thing you need to watch out for is that you might be leading for your planned Victory, but another player may be moving quickly to a different Victory. It is nice to be heading toward your Diplomatic Victory, but if one of your competitors is doing Space projects for a Science Victory that can be a bad thing for you. Of course, you can just play it for fun and not worry about who is winning, but I suspect most people would like to win a game after they have put in something like 10-12 hours playing Links https://civilization.fandom.com/wiki/Casus_Belli_(Civ6) https://civilization.fandom.com/wiki/Theological_combat_(Civ6) https://www.palain.com/gaming/civilization-vi/playing-civilization-vi-part-2/ Provide feedback on this episode.

  2. Oct 14

    HPR4748: Programmable Logic Controls - Episode 5

    This show has been flagged as Clean by the host. -------------------- 01 Introduction This is the fifth episode in an 8 part series. 02 In the previous two episodes we looked at the Allen Bradley PLC 2 and the Siemens S5 series of PLCs. In those episodes we mentioned I/O modules, but didn't really go into any detail on them. Instead we looked at the CPU units and focused on things from the programmer's perspective. 03 In this episode we will look at the I/O modules, what they are, how they work, and the purpose that they serve in the system. In addition to this, I will discuss machine safety systems and also claims made by certain people about cyber security and industrial safety. -------------------- 04 What is I/O? First though, we must address the question of what I/O is. While the CPU module may run the program, in order for the program to do anything useful it must interact with the real world outside the PLC. It must sense the state of the machine it is controlling through inputs, and it must affect the operation of the machine through outputs. 05 A Simple Example Let's take a very simple example to try to make the above a bit more tangible. Assume that we wish to press two parts together, such as pressing a bearing into a housing. This is a very common industrial process. 06 Let us assume we have the following items which connect to the inputs. * An emergency stop circuit. * A safety system to protect the operator. * A part presence sensor used to detect that the housing was correctly placed in the tooling. * Another part presence sensor used to detect that the bearing was correctly placed in the tooling. 07 * A sensor which indicates the hydraulic cylinder is fully retracted. * Another sensor which indicates the hydraulic cylinder is fully extended and the part was fully pressed home. * A button which the operator uses to initiate the press cycle. * Another button which the operator can use to abort the press cycle in the event of a fault. 08 We also have the following items which connect to the outputs * A hydraulic valve with two solenoids (down and up). * A pilot light which tells the operator that the cycle was completed successfully and the part is good. * A pilot light which tells the operator that the cycle was not completed successfully and the part is bad. This gives us a total of 8 inputs and 4 outputs. 09 A typical very small PLC would be suitable for this application. The PLC program would look at the state of the inputs, and apply the necessary logic to turn the outputs on or off at the appropriate time. As you can see, what makes a PLC useful is its ability to control I/O. 10 Small PLCs typically have a limited amount of I/O built into the same package as the CPU and can be used as is right out of the box. Medium to large PLCs will interface to racks of I/O, and the number of I/O points can be in the dozens to hundreds and even the thousands. -------------------- 11 Types of I/O The above example is very simple. There are in fact many types of I/O. I will outline the most common ones here. 12 Digital I/O The first is "digital" I/O. This is overwhelmingly the most common type. Digital I/O are basic on-off signals. A digital input will detect if a switch is on or off. A digital output will turn a relay or valve on or off. 13 Digital I/O comes in three main types categorized by the type of electronic device used. These are * AC * Relay * DC 14 AC AC I/O was the earliest type, but has largely faded away by now. This works with 100 to120 VAC or 230 VAC. Inputs detect the presence or absence of these voltages, and outputs output these voltages when turned on. The relay logic that PLCs replaced was largely driven by these voltages, so being able to interface with existing systems was an important design consideration for early PLCs. 15 Relay Relay outputs were an alternative to triac devices used for solid state AC outputs. These were very small relays built into the output modules. Their main attraction was they were usually somewhat cheaper than solid state outputs. However, they suffered from being much less durable and had a shorter life. 16 DC By the 1980s and 1990s, AC and relay I/O had been largely replaced in new applications by 24VDC. This allowed for more compact and less expensive control wiring, and fewer electrical safety concerns. Both inputs and outputs worked with 24VDC. All of the standard sensors, solenoid valves, relays, push buttons, lights, and pretty much all other devices were designed to be compatible with 24VDC. In cases where you had large motor contactors or relays, or large solenoid valves which required higher voltages for practical reasons, an additional interposing relay could be used to amplify the control signal. 17 I/O modules or cards came in 8, 16, 32 point sizes, and there were modules which combined both inputs and outputs in a single module. -------------------- 18 Analogue I/O As well as simple on-off voltages, PLCs could also work with variable voltages, where the actual voltage or current represents a measurable value, such as temperature or dimension. These are known as analogue values. These can be inputs or outputs and are known as analogue inputs or analogue outputs. 19 The simplest is voltage. The most common standard voltage ranges are * 0 to 10V. * Plus or minus 10V. * 0 to 5V. * 1 to 5V. 20 Another type is current. This is where the amount of current rather than the level of the voltage is what is significant. Current has an advantage over voltage in that it is less affected by resistance losses in long wiring runs and is also less prone to being influenced by electrical noise due to the lower impedance. 21 The most common standard current ranges are 4 to 20 mA. 0 to 20 mA. 22 Another common type is thermocouple inputs. These have special circuitry built into them to interface with thermocouple devices, which are a common device used to measure temperature by measuring the voltage generated when two dissimilar metals are heated in contact with each other. -------------------- 23 Serial Communications A number of PLCs have serial communications ports, mainly used to interface with things like label printers or bar code readers. Some of these have even had basic interpreters built into them, mainly to allow for better string formatting or parsing. 24 Servo and Stepper Another category of I/O are servo and stepper motor controllers. 25 High Speed Counter Timer Another type are counter/timer modules, which allow for high speed counting of events, or very precise timing of events in hardware, or interfacing with rotary or linear encoders. Encoders are measuring devices which have a series of very small but precise marks which interrupt beams of light when they move, allowing measurements to be made. 26 Networking Many PLCs also support some sort of networking. I won't go into any detail on that here, but will instead address this area in another episode. However, network ports may be built into the CPU, or may reside in separate network I/O modules. 27 Specialty As well as the preceding there are many other specialty modules which I won't bother to describe here. -------------------- 28 Operator Panels The original operator panels were arrays of push buttons, pilot lights, and other basic operator controls mounted in boxes for an operator to interact with the machine. Later on these were replaced by specialty electronic devices which were also known as operator panels as they served the same function. 29 Modern operator panels are screens and keypads which are used to display information to an operator or to allow data to be entered into the PLC. While not strictly speaking a type of I/O, operator panels typically look like I/O to the PLC CPU. Buttons on a touch screen may be effectively the same thing as actual hardware buttons from the PLC's perspective, and analogue values output to the operator panel for display are like hardware analogue devices. 30 All of these data are mapped to memory locations in the PLC, with the details of how this is done varying according to the make and model of PLC. 31 I won't go into any detail on this as this could be a separate subject on its own. Generally though, you would use software to create screens to display on the operator panel. The indicators and buttons defined in your screens would be mapped to addresses in the PLC, either directly or indirectly. This configuration would then be downloaded into the operator panel. Your PLC program could then interact with the operator panel using ordinary ladder logic. -------------------- 32 Safety Systems Up to now I have mentioned only PLCs in any detail. There is however more to a complete machine control system than just a PLC. One of these is safety systems. 33 I will leave out historical safety systems and just focus on modern ones. I will also leave out large process industries involving things like boilers or chemical reactors and just focus on assembly operations in industries such as automobiles, appliances, and other similar things. This won't be a tutorial on safety design, just a very brief overview. 34 An industrial machine must be designed with safety as one of its fundamental design principles. If the machine cannot be operated safely, then it cannot be put into

  3. Oct 13

    HPR4747: UNIX Curio #13 - Replacements for cat

    This show has been flagged as Clean by the host. This series is dedicated to exploring little-known—and occasionally useful—trinkets lurking in the dusty corners of UNIX-like operating systems. Thirteen is one of my favorite numbers, so I am going to use this episode to indulge myself. As part of UNIX Curio #8 ( HPR episode 4657 ), I went on a little flight of fancy and suggested that the comm utility could be used in place of cat . On further reflection, I realized that there are quite a few utilities that can do that job, almost. This episode is the result of me investigating how many possible ways there are to replace that functionality with standard utilities. Imagine that some prankster has deleted the cat utility from your machine, and you need a way to restore that capability without re-installing it. I should warn you that as opposed to the rest of the series, this episode will not focus heavily on obscure tools, and it is unlikely the examples given will be very useful. Also, I am not going to dive into the history of any of these commands. However, you might still learn something, and it could be a little entertaining to hear about the ways some utilities can be twisted to this purpose. Let's start by reviewing what the functionality of cat [1] is. Under POSIX, all it does is read the data provided on standard input or from each file named as an argument, and writes it to standard output. Briefly, it con cat enates all of the entries. The only option required by the standard is -u , which causes cat to write data without any delay (if that option were not given, the program could choose to buffer the data). While many implementations offer additional options that modify the output, I am going to completely ignore them and just focus on that one job. The files named as arguments are processed in the order in which they are named. One or more of these can be - , in which case cat will use the data provided on standard input and then continue to the next file in the argument list. I will actually narrow things even further and allow discussion of cases where only one file is involved, or where cat is reading from standard input via redirection from a file. I will start off with the TL;DR conclusion—none of the standard utilities are able to fully duplicate its functionality on their own. Some of them come close, but can't quite be relied on in all respects. One important reason for this lies with the POSIX definition of a text file [2]. This is a file treated as being separated into lines, divided by newline characters. There are three limitations: none of the lines can contain a NUL byte (value 0), the lines cannot exceed the maximum line length defined by the system (required to be at least 4096 bytes including the trailing newline), and the file must end with a newline character. (The last rule is implied by the definition of "line" , which states a newline must appear at the end of a line.) It might seem strange, but a text file may contain non-ASCII data; the only restriction on the values of bytes is that they cannot be NUL. Many of the standard utilities are only required to operate on text files and therefore cannot necessarily be relied on to handle arbitrary data. While a particular implementation might not have these limitations, there is no guarantee of that. I should note that both cut and paste are only required by POSIX to operate on text files, but with the exception that the lines can be of any length. In addition to cat , the only utilities covered in this episode that are required by POSIX to handle any arbitrary file are dd , tail (when used with the -c option), tee , tr , and uuencode . The wording for the compress utility does not specifically say it must handle any file, but in practice I think this is true. However, all of these utilities have at least one limitation of their own: they cannot handle more than one file or they can only operate on standard input. Some other utilities are able to deal with multiple files, standard input, or both, but those are only required to operate on text files. In practice, this typically means that if an input file does not end with a newline character, the program will add one to the output, destroying the idea that the output of cat should be identical to the input. Let's start with the least-capable options and work our way towards those that could serve as closer drop-in replacements. The first candidate is a utility that I thought might be persuaded to work, but it doesn't quite. This is nl , a command used to number lines of files or standard input [3]. It normally prints the content of this input and, on the left, prints the number of each line. It is possible to turn off the numbering, and to set the separator between the numbers and the text to a null string. However, it does not seem to be possible to have absolutely nothing appear in front of each line. The POSIX specification states that the -w option can be given to define how many characters to the left of each line will be reserved for the line numbers—while the default value is six, it says nothing about what values must be accepted. I tested several implementations (specifically, from GNU, FreeBSD, NetBSD, and OpenIndiana, which is an open-source derivative of System V) and none of them allow setting the width of the space for line numbers to be less than one. Even if it were possible to remove the preceding space entirely, POSIX only requires nl to accept one file argument and to operate on text files, so it would still be limited. In the examples for this episode, myfile is used to represent the name of the file being operated on. The text myfile ... means a filename possibly followed by other filenames (with no limitation on the number). The nl example below prints a single space in front of each line. nl -b n -s "" -w 1 myfile Next up are methods that actually work, but are only usable with standard input. When combined with input redirection from a file, they can accept a single file and send it to standard output. The read utility [4] takes a line of input and assigns it to a shell variable. It requires a little help, however—it can't output what it reads, so it has to be paired with something like echo or printf . Because it reads input one line at a time, it needs to be used in a loop to read the entirety of the data. In addition, the IFS shell variable must be set to a null string to prevent read from doing field splitting; we don't want it to modify the data being read at all. The shell loop while IFS="" read -r foo; do echo "$foo"; done /dev/null would be the command to use. The compress [14] and uuencode [15] utilities are in the same category, but do a lot more processing on the data along the way. The purpose of these is described respectively in UNIX Curios #7 ( HPR 4647 ) and #1 ( HPR 4587 ). Their output can be piped into a corresponding uncompress or uudecode utility to get back the original data and send it to standard output. The two commands would be compress -c myfile | uncompress -c and uuencode myfile /dev/stdout | uudecode —if you wanted to use standard input instead, just omit the filename arguments. I should point out that when I tested the uuencode method on FreeBSD 15.0, it didn't work; however, it did work on NetBSD 10.1 and OpenIndiana 2025.10. Next, we have two possibilities that come very close, but don't quite behave exactly like cat . They send to standard output either the files named as arguments in order, or, if there are none, standard input. However, POSIX does not require them to take a hyphen as an argument, representing standard input. First up, we have sed [16]; when called with an empty script (as in sed "" myfile ... or sed :a myfile ... ), it just prints out the contents without any transformations. The grep utility [17] works the same way—when given an empty regular expression (as in grep "" myfile ... ), it treats that as matching anything and prints each line of input to standard output. Finally, we have arrived at the utilities that can fully replace cat , albeit only for text files. They can be given one or more files, including a hyphen representing standard input, and will output them in the order they are given as arguments. If no filename arguments are given, they just use standard input instead. Starting out, we have awk [18]. While an empty pattern matches every line of input and an empty action prints the entire line, POSIX states that if both the pattern and action are empty, the utility is to simply exit without reading or writing anything. Therefore, we need to at least provide a pattern or an action—a pattern, as in awk "/.*/" myfile ... , can be shorter. Another one that has the capabilities is cut -b 1- myfile ... [19]. However, as noted earlier, these will add a newline character if the input doesn't already end with one, so they aren't exact replacements. I was hoping that a simple invocation of one of the standard utilities could be used in place of the cat program that our prankster has deleted; however, I think I've demonstrated that isn't possible. Let's return to those utilities that can handle arbitrary files, but can't take more than one at a time. It would be possible to write a shell script to manage any options and arguments, then use the utility to do the actual work of sending through the data file by file. In my view, tail would be the best fit because it can take a bare filename as an argument and, unlike dd , uses the standard syntax for UNIX utilities. The following script does just that—unfortunately, it is not really something simple that could be typed in from memory. So probably it would be easier in most situations to just re-install cat on your sys

  4. Oct 12

    HPR4746: Monotone

    This show has been flagged as Clean by the host. Python and its libraries 1. librosa — loading and resampling audio def load_audio(path): y, sr = librosa.load(path, sr=SR, mono=True) return y, sr Every episode, regardless of its original sample rate or channel count, gets loaded down to a single mono stream at 16kHz (SR = 16000). That's one line of librosa, resampling, and folding stereo to mono. It made every downstream tool (VAD, pitch tracking, MFCC extraction) operate on a consistent, predictable input regardless of what an MP3 encoder or podcast host originally used. 2. parselmouth (Praat bindings) — pitch and voice-quality tracking def pitch_and_hnr(y, sr): snd = parselmouth.Sound(y, sampling_frequency=sr) pitch = snd.to_pitch(time_step=PITCH_TIME_STEP, pitch_floor=PITCH_FLOOR, pitch_ceiling=PITCH_CEILING) f0 = pitch.selected_array["frequency"] times = pitch.xs() try: harmonicity = snd.to_harmonicity_cc(time_step=PITCH_TIME_STEP) hnr = np.array([harmonicity.get_value(t) for t in times]) hnr = np.nan_to_num(hnr, nan=-999.0) exceptException: hnr = np.full_like(f0, 999.0) # fail open if HNR extraction errors return f0, hnr, times parselmouth is a Python wrapper around Praat, the standard tool in phonetics research. This is the heart of the whole vocal-monotony measurement: to_pitch() gives fundamental frequency (F0, roughly "pitch") every 20ms, and to_harmonicity_cc() gives harmonics-to-noise ratio (HNR) at the same timestamps — a signal-quality score used later to throw out pitch estimates taken from noisy or badly-compressed audio rather than let bad audio masquerade as "flat" pitch. 3. webrtcvad — deciding which frames are actually speech def vad_speech_mask(y, sr, aggressiveness=2): vad = webrtcvad.Vad(aggressiveness) pcm16 = (np.clip(y, -1.0, 1.0) *32767).astype(np.int16) n_frames =len(pcm16) // VAD_FRAME_LEN mask = np.zeros(n_frames, dtype=bool) for i inrange(n_frames): chunk = pcm16[i * VAD_FRAME_LEN:(i +1) * VAD_FRAME_LEN] raw = struct.pack("%dh"%len(chunk), *chunk) try: mask[i] = vad.is_speech(raw, sr) exceptException: mask[i] =False return mask, times webrtcvad is the voice-activity detector out of Google's WebRTC project — a frame-by-frame classifier ("is this 30ms chunk speech or not"). It needs raw 16-bit PCM bytes, not floats, hence the np.clip and struct.pack conversion. 4. librosa.feature — telling music apart from speech flatness = librosa.feature.spectral_flatness(y=y, hop_length=hop)[0] chroma = librosa.feature.chroma_stft(y=y, sr=sr, hop_length=hop) onset_env = librosa.onset.onset_strength(y=y, sr=sr, hop_length=hop) ... chroma_diff = np.mean(np.linalg.norm(np.diff(chroma_win, axis=1), axis=0)) chroma_stability =1.0/ (1.0+ chroma_diff) ... scores[w] =0.4* chroma_stability +0.35* periodicity +0.25*min(flat_mean *3, 1.0) Podcast intros/outros are often music, and music has a very different pitch profile than speech — including it would bias the "monotone" measurement. Rather than train a classifier, three librosa features were combined with hand-tuned weights: spectral flatness (music tends to have more tonal structure, less noise-like spectrum), chroma stability (sustained harmony vs. constantly-changing speech formants), and onset periodicity (a regular beat vs. speech's irregular rhythm). 5. librosa.feature.mfcc + sklearn.cluster.KMeans + sklearn.metrics.silhouette_score — an unsupervised speaker-count attempt mfcc = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13, hop_length=hop) ... chunk_vecs.append(np.concatenate([seg.mean(axis=1), seg.std(axis=1)])) ... X = np.array(chunk_vecs) X = (X - X.mean(axis=0)) / (X.std(axis=0) +1e-9) best_k, best_score =1, -1.0 for k inrange(2, min(MAX_SPEAKERS, len(X) -1) +1): labels = KMeans(n_clusters=k, n_init=10, random_state=0).fit_predict(X) iflen(set(labels)) best_score: best_k, best_score = k, score estimated = best_k if best_score >= SILHOUETTE_MIN else1 MFCCs (Mel-frequency cepstral coefficients) summarize the shape of a short audio window's spectrum — a rough "voice fingerprint" widely used in speech tasks. The idea: chop each episode into 2-second chunks, turn each into a fingerprint vector, standardize (z-score) the features, then use KMeans to see if the chunks naturally split into 2+ clusters (different voices) rather than 1 (a single voice throughout). silhouette_score scores how well-separated the clusters are, and picks the best k — or falls back to "1 speaker" if no clustering clears a minimum quality bar. This part of the investigation did not work, as it picked up noise as another host. 6. scipy.stats.mannwhitneyu + a hand-written Cliff's delta — comparing two groups without assuming a normal distribution def cliffs_delta(a, b): a, b = np.asarray(a), np.asarray(b) gt =sum((x > y) for x in a for y in b) lt =sum((x 1e-6: chunk_vecs.append(v / norm) ... adj_sims = [float(np.dot(V[i], V[i +1])) for i inrange(n -1)] Each ~130-word chunk of a transcript is embedded as a single vector using spaCy's medium English model (en_core_web_md, which has built-in word vectors), then L2-normalized so a dot product between two vectors is their cosine similarity. Comparing consecutive chunks' similarity gives a "does the topic barely move between one chunk and the next" score. 10. lexicalrichness — vocabulary diversity that doesn't cheat on transcript length lr = LexicalRichness(text) try: mtld = lr.mtld(threshold=0.72) exceptException: mtld =None A naive vocabulary-diversity score (unique words ÷ total words) gets worse the longer a text runs, because of how the metric is defined — not because the speaker is actually repeating themselves more. MTLD (Measure of Textual Lexical Diversity) avoids that by sweeping through the text and counting how many words it takes before diversity drops below a threshold, then averaging — a metric designed specifically to stay comparable between a 10-minute and a 40-minute episode. 11. vaderSentiment — a lexicon-based sentiment score vader = get_vader() # SentimentIntensityAnalyzer() sentiments = [vader.polarity_scores(c)["compound"] for c in chunks] ... "sentiment_std": float(np.std(sentiments)) iflen(sentiments) >1elseNone, VADER scores each chunk's sentiment from -1 to +1 using a hand-built lexicon and rule set (not a neural network) — chosen for being fast, deterministic, and cheap enough to run per-chunk across hundreds of episodes. The value then used isn't the average sentiment — it's the standard deviation of sentiment across an episode's chunks: does the emotional tone ever move, or does it stay flat throughout? 12. zlib (standard library) — compression ratio as a gauge for entropy def compression_ratio(text): raw = text.encode("utf-8") iflen(raw) 1, } Rather than the acoustic speaker-clustering attempt (item 5, which turned out to be unreliable), a more trustworthy stat came from plain text: HPR's own episode metadata (pulled from a local knowledge-base repo) has host-written summaries, and a short list of regex patterns ("guest", "interview", "joins me", etc.) plus counting linked correspondent profiles was enough to flag likely multi-presenter episodes. 14. multiprocessing.Pool — running the same analysis over hundreds of files without waiting hundreds of times over work = [(r, local_paths[r["id"]]) for r in batch] with mp.Pool(args.workers) as pool, open(args.out, "a") as out_f: for result in pool.imap_unordered(_worker, work): out_f.write(json.dumps(result) +"\n") out_f.flush() Every batch pipeline (acoustic pitch analysis, speaker-count pass) used the same shape: Pool(workers).imap_unordered(...) to run the per-episode function across multiple CPU cores at once, streaming results out to a JSON-lines file as each one finishes rather than waiting for the whole batch. imap_unordered was chosen over map so a single slow episode couldn't hold up writing out the results that had already finished. 15. subprocess + a resumable batch loop — working within a disk-space limit def load_done_ids(results_path): ifnot os.path.exists(results_path): returnset() done =set() withopen(results_path) as f: for line in f: ... done.add(json.loads(line)["id"]) return done ... rows = [r for r in rows if r["id"] notin done] ... for batch_start inrange(0, len(rows), args.batch_size): batch = rows[batch_start:batch_start + args.batch_size] local_paths = fetch_batch(batch, args.scratch) # scp from the remote host ... for p in local_paths.values(): os.remove(p) # delete before next batch All the podcasts (~220GB) didn't fit on local disk (~54GB free). The fix was a loop: scp (via subprocess) one batch of audio in, analyze it, delete it, move to the next batch. load_done_ids() makes the whole pipeline resumable by reading back what's already in the output file, so a crash or a deliberate stop partway doesn't lose completed stuff. Links https://news.ycombinator.com/item?id=49110547 https://mastodon.social/@ngate/117009495478432200 Ah yes, the riveting world of Hacker Public Radio: a quaint little corner where tech wizards ✨️ divulge their magical secrets ✨️ to each other in the most riveting monotone known to man. Who knew endless "community" podcasts could be so... utterly riveting? 📻️🎙️ Apparently, everyone is just dying to contribute to this cacophony once a year—what a privilege! 😂 https://hackerpublicradio.org/ #HackerPublicRadio #techCommunity #podcasting #MonotoneMagic #rivetingContent #HackerNews #ngated Provide feedback on this episode.

4.3
out of 5
33 Ratings

About

Hacker Public Radio is an podcast that releases shows every weekday Monday through Friday. Our shows are produced by the community (you) and can be on any topic that are of interest to hackers and hobbyists.

You Might Also Like