A few thingz
Joseph Basquin
21/11/2024
#programming
An attempt to generate random data with audio (and your computer's built-in microphone)
You probably know that generating some real random data is not so easy to do with a computer. How to design a good Random Number Generator (or a pseudo-random one) is a math topic that you can work years on ; it's also something very important for real-life applications such as security/cryptography, for example when you need to generate strong passwords.
Usually (and this is true in general in cryptography), designing your own algorithm is bad, because unless you're a professional in this subject and your algorithm has been approved by peers, you're guaranteed to have flaws in it, that could be exploited.
But here, for fun (don't use it for critical applications!), let's try to generate 100 MB of good random data.
1) Record 20 minutes of audio in 96khz 16bit mono with your computer's built-in microphone. Try to set the mic input level so that the average volume is neither 0 dB (saturation) nor -60 dB (too quiet). Something around -10 dB looks good. What kind of audio should you record? Nothing special, just the noise in your room is ok. You will get around 20*60*96000*2 ~ 220 MB of data. In these 220 MB, only the half will be really useful (because many values in the signal - an array of 16-bit integers - won't use the full 16-bit amplitude: many integers "encoding" the signal might be for example of absolute value < 1024, i.e. will provide only 10 bits)
2) Now let's shuffle these millions of bits of data with some Python code:
from scipy.io import wavfile
import numpy as np
import functools
sr, x = wavfile.read('sound.wav') # read a mono audio file, recorded with your computer's built-in microphone
#### GET A LIST OF ALL THE BITS
L = [] # list of bits
for i in range(len(x)):
bits = format(abs(x[i]), "b") # get binary representation of the data
# don't use "016b" format because it would create a bias: small integers (those not using
# the full bit 16-bit amplitude) would have many leading 0s!
L += map(int, bits)[1:] # discard the first bit, which is always 1!
print L.count(1)
print L.count(0) # check if it's equidistributed in 0s and 1s
n = 2 ** int(np.log2(len(L)))
L = L[:n] # crop the array of bits so that the length is a power of 2; well the only requirement is that len(L) is coprime with p (see below)
### RECREATE A NEW BINARY FILE WITH ALL THESE BITS (SHUFFLED)
# The trick is: don't use **consecutive bits**, as it would recreate something close to the input audio data.
# Let's take one bit every 96263 bits instead! Why 96263? Because it's a prime number, then we are guaranteed that
# 0 * 96263 mod n, 1 * 96263 mod n, 2 * 96263 mod n, ..., (n-1) * 96263 mod n will cover [0, 1, ..., n-1]. (**)
# This is true since 96263 is coprime with n. In math language: 96253 is a "generator" of (Z/nZ, +).
p = 96263 # The higher this prime number, the better the shuffling of the bits!
# If you have at least one minute of audio, you have at least 45 millions of useful bits already,
# so you could take p = 41716139 (just a random prime number I like around 40M)
M = set()
with open('random.raw', 'wb') as f:
for i in range(0, n, 8):
M.update(set([(k * p) % n for k in range(i, i+8)])) # this is optional, here just to prove that our math claim (**) is true
c = [L[(k * p) % n] for k in range(i, i+8)] # take 8 bits, in shuffled order
char = chr(functools.reduce(lambda a, b: a * 2 + b, c)) # create a char with it
f.write(char)
print M == set(range(n)) # True, this shows that the assertion (**) before is true. Math rulez!
Done, your random.raw
file is filled with random data!
Notes:
-
The only issue I can see happen right now is if the ADC (analog-to-digital-converter) electronic component of your soundchip is highly biased (please drop me a message if you have such a device).
-
This code here is unoptimized, it took 2 minutes for 1 minute of audio. There's surely a better way to work with arrays of bits in Python, comments/improvements are welcome!
- How to test the randomness quality of this file? This is a complicated task, and here are some references to do that. This is very far from being a rigorous way to do it, but it can be a first step (quote from the linked page): I've seen winzip used as a tool to measure the randomness of a file of values before (obviously, the smaller it can compress the file the less random it is). If you do it on the file generated here, you get exactly the same size (or even a bit more) after zip-compressing the file! Idem with rar, 7z (which usually yield a far better compression ratio, especially for audio data), the compression ratio is 1:1.
How to create symbolic links with Windows Explorer?
Quick tip: here is how to create symlinks in Windows without using any command line tool.
1) If you have Python installed, create mklinkgui.py
:
import win32clipboard # pip install pywin32 if you haven't installed it already
import sys, os, subprocess
fname = sys.argv[1]
win32clipboard.OpenClipboard()
filenames = win32clipboard.GetClipboardData(win32clipboard.CF_HDROP)
win32clipboard.CloseClipboard()
for filename in filenames:
base = os.path.basename(filename)
link = os.path.join(fname, base)
subprocess.Popen('mklink %s "%s" "%s"' % ('/d' if os.path.isdir(filename) else '', link, filename), shell=True)
2) Open regedit
and
-
Create a key named
Mklink here
inHKEY_CLASSES_ROOT\Directory\shell
. In this key create a subkeycommand
containing the string"C:\Python27\pythonw.exe" "C:\pathto\mklinkgui.py" "%1"
. - Create a key named
Mklink here
inHKEY_CLASSES_ROOT\Directory\Background\shell
. In this key create a subkeycommand
containing the string"C:\Python27\pythonw.exe" "C:\pathto\mklinkgui.py" "%v"
(please note the%v
here).
How to use it?
-
First click on the file(s) or folder(s) that you want to create a symbolic link to. Do
CTRL+C
orCopy
. (It works with multiple files!) - Right click on the folder where you want to drop a link, choose
Mklink here
, done!
Working with audio files in Python, advanced use cases (24-bit, 32-bit, cue and loop markers, etc.)
Python comes with the built-in wave
module and for most use cases, it's enough to read and write .wav audio files.
But in some cases, you need to be able to work with 24 or 32-bit audio files, to read cue markers, loop markers or other metadata (required for example when designing a sampler software). As I needed this for various projects such as SamplerBox, here are some contributions I made:
-
The Python standard library's wave module doesn't read cue markers and doesn't support 24-bit files. Here is an updated module:
that adds some little useful things. (See Revision #1 to see diff with the original stdlib code).
Usage example:
from wave import open f = open('Take1.wav') print(f.getmarkers())
If you're familiar with main Python repositery contributions (I'm not), feel free to include these additions there.
-
The module scipy.io.wavfile is very useful too. So here is an enhanced version:
Among other things, it adds 24-bit and 32-bit IEEE support, cue marker & cue marker labels support, pitch metadata, etc.
Usage example:
from wavfile import read, write sr, samples, br, cue, cuelabels, cuelist, loops, f0 = read('Take1.wav', readmarkers=True, readmarkerlabels=True, readmarkerslist=True, readpitch=True, readloops=True) write('Take2.wav', sr, samples, bitrate=br, markers=cue, loops=loops, pitch=130.82)
Here is a Github post and pull-request about a hypothetical merge to Scipy.
Here is how loop markers look like in the good old (non open-source but soooo useful) SoundForge:
Lastly, this is how to convert a WAV to MP3 with pydub, for future reference. As usual, do pip install pydub
and make sure ffmpeg
is in the system path. Then:
from pydub import AudioSegment
song = AudioSegment.from_wav("test.wav")
song.export("test.mp3", format="mp3", bitrate="256k")
will convert a WAV file to MP3.
Interested for future evolutions and other audio programming tools?
Make a zooming + panning user interface work on mobile devices (in progress)
What's cool with Zooming User Interfaces is that you have always free space available anywhere (either by zooming or panning) to write new ideas.
That was the key idea in 2014 when creating BigPicture (ready-to-use infinite notepad in-the-cloud) and the open-source JavaScript library bigpicture.js powering it:
It works as expected on desktop browsers. Now, the next big challenge is: how to make it work on mobile devices?
It's funny to even have to ask this question, since touch devices are natively made to do panning (slide finger on screen) and zooming (pinch with 2 fingers). So it should be straightforward to adapt BigPicture to mobile devices.
However here are the difficulties:
-
The
transform/scale
from CSS has limitations (probably max 10x or 100x factor when I started this project a few years ago), so we can't only use this to do a (nearly) infinite zooming user interface -
It requires to be able to zoom on a particular part of the viewport and not zoom the other parts of the HTML document (e.g. a top navigation header). Here are many potential solutions:
-
Prevent that a fixed element resizes when zooming on touchscreen: 5 answers, 3 of them are non-working, 1 suggests to use the jQuery TouchSwipe plugin (looks promising), 1 of them is "half-working": the supposedly "fixed" element doesn't stay fixed while pinch-zooming (it is zoomed/enlarged), but its position/zooming factor will be reset, after a few hundreds of milliseconds when the pinch-zooming is finished, thus the UI is not really good.
-
Disable zoom on a div, but allow zoom on the page (an alternate div): 4 answers, none of them gave a useful solution; accepted solution not working
-
How to prevent (bootstrap) fixed top navigation from zooming on mobile: 2 answers, none of them really working on modern touch devices. The main one is using the following code, but it's not really usable (during zoom-pinching on mobile devices, the supposedly fixed top navbar does resize, then when you stop pinching it restores the normal size. But the navbar doesn't stay sticky at the top of the viewport like it should):
$(window).on('load scroll', function() { var ds = window.innerWidth / screen.width; $('.device-fixed-height').css('transform','scale(1,' + ds + ')').css('transform-origin', '0 0'); $('.device-fixed-width').css('transform', 'scale(' + ds + ',1)').css('transform-origin', '0 0'); });
-
Zoom specific element on webcontent (HTML,CSS,JavaScript): 1 answer about Hammer.js, 1 answer about Zoomooz
-
Pinch/zoom within a div but not whole page: closed, 1 answer (use Zoomooz library)
- Pinch-to-zoom, but only in a specific div (not full page): closed, duplicate
-
-
Possible useful tools for this:
-
Zoomooz(however, I read in comments: Zoomooz does not support multi-touch pinching events. Its only a library for zooming into elements on a page, but has no support for pinching behavior, so far as I can see in the documentation.) - TouchSwipe, a jQuery plugin for touch devices
-
Work in progress!
By the way, here is how to simulate touch events on Chrome for desktop computer: open the Developer console (F12), then there's a top-left button "Toggle device toolbar" (CTRL+SHIFT+M), here you go! For pinch-zoom events, use SHIFT + click + mouse up.
Your tests / pull requests / help to build a mobile version are welcome on this branch!
If you really like that open-source project, you can donate here: 1NkhiexP8NgKadN7yPrKg26Y4DN4hTsXbz.
Writing, a text-editor in the browser
Since I've started using StackOverflow, I've always loved their text editor (the one you use when writing a question/answer), because it supports Markdown syntax (a very elegant markup language to add bold, italic, titles, links, itemization, etc.), and even MathJax (which is more or less LaTeX syntax in the browser). I've always wanted to use such an editor for my own documents.
After some research, I found a few existing tools, but:
- half of them don't support LaTeX / MathJax (for math formulas)
- some of them do, but have a 1-sec delay between keypress and display, and I find this annoying, see e.g. StackEdit
- some of them have annoying flickering each time you write new text, once math is present on the page
- most of them are not minimalist / distraction-free enough for me
Let's go and actual build one! Here is the result, Writing:
Here's the source: https://github.com/josephernest/writing
For sure you'll like it!
If you really like that, you can donate here: 1NkhiexP8NgKadN7yPrKg26Y4DN4hTsXbz
Yopp — an easy way to send a file from phone to computer
Have you ever spent more than 1 second wondering:
"How do I get on my computer this photo I just made with my phone?"
or
"How do I get this PDF from my computer to my phone?"
Then you probably thought "Let's use Dropbox! ... oh no I'm not logged in on my phone, but what is my password again? Well, let's send the file to myself via email! Maybe I should just use a USB cable... but where is my USB cable again?"
Yopp is a solution for this problem, that you can easily install on your web server.
Thoughts about user experience & user interface design
This tool - Yopp - requires a total number of 7 actions to get the work done:
Open browser on phone [1 tap], Open Yopp page [1 tap if it's in the bookmarks], UPLOAD [1 tap], Choose file [1 action]
Open browser on computer [1 double click], Open Yopp page [1 click if in bookmarks], DOWNLOAD [1 click]
I'll be happy to switch to another tool if one requiring less actions exists.
I noticed that my likelihood/probability to use any tool (all other things being equal) is more or less proportional to P = 1 / a^2
(*) where a
is the number of required actions/user inputs. If the number of required actions is doubled, the likelihood to use the tool is divided by 4.
Thus, even if it might sound obvious, one key element for a good user interface is to minimize the number of user actions to get a task done. If not, the user might unconsciously remember that the interface is unnecessarily complicated to use. He will then forget about the product, and look for another solution. (OK this is probably what will happen for you with Yopp if you don't have a web server already!)
As an example, I'm sure I'd use my city's bicycle sharing system Velo+ much more if I could take a bike by just swiping my card on the bike station's card reader (this is technically possible). Instead we have to: Tap on a screen (1), Choose "Subscribed user" (2), Swipe the card (3), Choose "Rent a bike" (4) (this one is particularly unuseful), Accept conditions already accepted many times before (5), etc. at the end it requires at least 12 actions! Any user who has done it at least once will process this data (required amount of inputs) and will probably make the choice of not using it for short distance trips.
It would be interesting to get more statistical data about the empirical result (*), this will be discussed in a future post.
See the BigPicture — a zooming user interface
This topic has been present in my thoughts for a long time, probably years:
“How to be able to think/write about lots of unrelated various topics, and still have a way to look at the big picture of what you’re doing?”
Here is my contribution about this:
- bigpictu.re, a ready-to-use infinite notepad (infinite zooming and panning)
- bigpicture.js, a JavaScript open-source library that you can use in various projects
- A standalone version of 1. (so you can take notes offline) is also available here: bigpicture-editor
- AReallyBigPage, an infinite collaborative notepad. It has been a real chaos once hundreds of people joined in. Probably internet’s deepest page ;)
Such an interface is called a Zooming User Interface (interesting reading: The humane interface by Jef Raskin, one of the creators of the Apple Macintosh), and strangely, ZUI has been very few used in modern interfaces.
As of 2017, nearly every software interface uses a 2D, or even a 1D navigation process: a web page only offers two scrolling directions: north and south. Even nowadays's apps famous for their "new kind of interface" still use a 1-axis navigation: "Swipe left or right".
Is there a future made of new interfaces?
TinyAnalytics
After having tested many open-source website analytics tool, and haven't found exactly what I was looking for, I started a minimalist project (coded in PHP) that only does this:
-
number of visits per day
- display the referrers (i.e. the people who have a link to your website)
If you're looking for a tool lighter than Piwik, Open Web Analytics or Google Analytics, then TinyAnalytics might be what you're looking for.
Get the reverb impulse response of a church
I recently recorded an impulse response of the reverb of a 14th-century church (more or less the footprint of the sound ambiance of the building). Here is how I did it.
- First I installed a loudspeaker (a studio monitor Yamaha HS-80M) in the church, quite high from the ground. I played, rather loud, a sound called a frequency sweep, that contains frequencies from 20Hz to 20000Hz, i.e. the entire human hearing range.
- Then, in the middle of the church, I recorded this with 2 microphones. Here is what I got:
Quite a lot of reverb, that's exactly what we want to catch with an IR!
-
Now, let's use some Digital Signal Processing to get the IR. All the source code in Python is here. If you're into math, here is the idea:
a
is the input sweep signal,h
the impulse response, andb
the microphone-recorded signal. We havea * h = b
(convolution here!). Let's take the discrete Fourier transform, we havefft(a) * fft(h) = fft(b)
, thenh = ifft(fft(b) / fft(a))
. - Here is the result, the Impulse Response of the church:
Then, of course, we can do some cleaning, fade out, etc.
But what is this useful for? You can use this Impulse Response in any music production software (the VST SIR1 is quite good and freeware) , and make any of your recordings (voice, instrument, etc.) sound like if they were recorded in this church. This is the magic of convolution reverb!
Useful trick when you record your own IR: play sweep0.wav
in the building instead of sweep.wav
. The initial "beep" is helpful to see exactly where things begin. If you don't do that, as the sweep begins with very low frequencies (starting from 20 Hz), you won't know exactly where is the beginning of your microphone-recording. Once your recording is done, you can trim the soundfile by making it begin exactly 10 seconds after the short beep.
Browsers, please don't kill HTTP
I don't share Jeff Atwood's enthusiasm about HTTPS / encryption. What will happen if HTTPS becomes the standard and if HTTP is considered by browsers as "unsafe"?
It seems to me that then, the web will be separated in 2 worlds: professional websites who can afford SSL certificates and a dedicated team to maintain the certification process ... and the average small webmaster who just has a shared hosting and a Wordpress. The latter will be slowly "pushed out of internet" with the threatening notice Not secure
.
Even with the free Let's Encrypt initiative, maintaining HTTPS requires technicity, much more than what the average webmaster has.
Result: if HTTPS becomes the standard and normal HTTP is alerted by browsers as unsafe by default, this will slowly kill amateur content, citizen-powered content.
Welcome to even-more centralized internet. Be sure Facebook and other big content providers will like this.
Edit (2018): I'm finally using LetsEncrypt too... In short, a2enmod ssl ; wget https://dl.eff.org/certbot-auto ; chmod a+x certbot-auto ; ./certbot-auto
does most of the work. More to read here.
Bloggggg...
Many things begin with
Let's start a new notebook!
(Well sometimes the notebook is abandoned after 3 pages, but hmm, let's not think about it). Writing helps to know what you want, what you don't want, and what you've done so far. So I decided
Let's start a blog!
Then I looked at many blog generator tools, and noticed it would be faster to actually write it myself in PHP, rather than downloading every existing solution and pick the best (so hard to make a choice). So I started yesterday evening, and today it's done:
bloggggg, a blogging platform.
Here is how it looks like:
Editor interface: