Wishful Coding

Didn't you ever wish your computer understood you?

Bucket Brigade Delay

So far in my quest to build a synthesizer, I’ve controlled a Game Boy synth with a linear potentionmeter and made a pressure sensing circuit for the SoftPot. Today I want to make an analog delay using a bucket brigade device.

To do this, I used a BL3207 bucket brigade device, and a BL3102 clock generator, which are clones of the MN3207 and MN3102, respectively. The datasheets for the former are a single page and not of much use, but since they are clones, the original datasheets provide more useful information. Most importantly, this reference circuit.

MN3207 reference schematic

I did not build that exact circuit, but kind of used it as a hookup guide for the two chips. The MN3102 basically uses the RC filter to generate two opposing clock signals. It also generates a special voltage that’s 15/16 of Vdd for some reason. The MN3207 then takes an analog input, and with some pull-down resistors, produces a delayed output signal. In the above circuit there is a lot of filtering going on, while my circuit uses a simple first order RC filter for now. Both the delayed output and the input signal are fed into an opamp adder to make a nice feedback loop. In the above video I’m simply turning the feedback gain.

ball of wires

To be honest, the current circuit sounds quite bad and is not very flexible. It just adds a fixed delay and loops it back on itself, going from inaudible to metallic to oscillating in the blink of an eye. The best sound I got out of it is the click track when it’s almost oscillating and becomes this funny tone by itself. Maybe all of the filtering in the reference circuit make it a lot better, but I have some other ideas.

I have like 5 of these delay chips, so it’d be fun to chain them together for a longer delay. The other thing is the clock generator: You can disconnect the RC and drive the oscillator externally. I’m thinking I could create an external clock, and modulate that with an LFO to create a vibrato effect.

Update: Vibrato works like a charm. I simply drove the clock with an Arduino as follows. Then I played a sine wave and some acoustic guitar into it for demonstration.

void setup() {
}

void loop() {
  int i;
  for(i=0; i<2000; i+=30) {
    tone(2, 40000+i);
    delay(1);
  }
  for(i=2000; i>0; i-=30) {
    tone(2, 40000+i);
    delay(1);
  }
}
Pepijn de Vos

Sensing pressure with a SoftPot

In my previous post I connected a SoftPot to an Arduino and used a Game Boy as the synth. In this post I’m focusing more on the SoftPot, and specifically on reading pressure.

The SoftPot consists of a resistive bottom layer and a conductive top layer. When pressed together, the bottom resistor forms a voltage divider with the top conductor. When the conductive top side is pressed down, it shorts part of the bottom track, creating a lower total resistance. The harder you press down, the larger the area of the bottom track that is shorted, the lower the resistance.

So to measure both pressure and position, we’ll need to simultaneously read the voltage on the top track, and the resistance of the bottom track. To get an accurate position, we’d like to have the full voltage swing available, without any changes in voltage due to pressure. Meanwhile, we’d like to sense small DC variations in resistance of a large total resistance. This is my best attempt so far.

circuit

It uses a current mirror to maintain an almost fixed voltage on the pot (R1) and only lose 0.6V of the full swing. The current mirror then feeds into a biased transimpedance amplifier. The rightmost voltage divider is used to set the DC output voltage. (I later added a capacitor in parallel to the TIA feedback resistor to reject noise)

In reality the voltage divider on the positive TIA input is a trim pot. The changes in resistance of the SoftPot are smaller than the process variations. For example, this particular pot changes from 20.7k to 20.3k when pressed, so the bias voltage has to be adjusted for this.

sensing pressuer and pitch

In the above figure, the blue line is me sliding my finger up and down, while the yellow line is the pressure of my finger, with the green/red lines being the max/min. This seems to work just fine, except after letting it run for a while the pressure value starts to drift. Remember, we need the constant, absolute value, not some high-pass filtered version.

I was really confused, and tried various things to reproduce the problem and improve the situation. Then I blew on the circuit.

temperature sensitivity

OMG, look at that! The current mirror goes completely crazy when it gets warm. One solution is to add more degeneration, which adds voltage drop. Another is to use a Wilson current mirror, which also adds voltage drop. And finally, you could get two integrated transistors on the same die, which makes them the same temperature and improves matching. I guess that’s what I’ll have to do. To be continued.

const int pitchPin = A0;
const int pressurePin = A1;
const int pwmPin = 12;

const int pressureThreshold = 20;

int pitchValue = 0;        // value from SoftPot
int pressureValue = 0;        // value from TIA
int minPressureValue = INT16_MAX;
int maxPressureValue = 0;
int pressure = 0;
int frequency = 0;
int polarity = 1;

void setup() {
  Serial.begin(9600);
}

void loop() {
  delay(1);
  pitchValue = analogRead(pitchPin);
  delay(1);
  pressureValue = analogRead(pressurePin);
  delay(1);
  minPressureValue = min(pressureValue, minPressureValue);
  maxPressureValue = max(pressureValue, maxPressureValue);
  pressure = map(pressureValue, minPressureValue, maxPressureValue, 0, 10);
  frequency = map(pitchValue, 0, 1023, 440, 1320);
  if (pressureValue < minPressureValue+pressureThreshold) {
    pitchValue = 0;
    noTone(pwmPin);
  } else if (pressure > 6) {
    tone(pwmPin, frequency+pressure*polarity);
    polarity *= -1;
  } else {
    tone(pwmPin, frequency);
  }
  Serial.print(pitchValue);
  Serial.print(", ");
  Serial.print(minPressureValue);
  Serial.print(", ");
  Serial.print(maxPressureValue);
  Serial.print(", ");
  Serial.println(pressureValue);
  delay(50);
}
Pepijn de Vos

Visualising your WhatsApp conversations

I was curious how much I chat with my friends, so I decided to find out. It’s pretty easy and fun, I can promise.

My first thought was to go after the message database, but it turns out this is encrypted with a key that can only be obtained by rooting your device or performing some downgrade attack. Not sure what the security model is here, as the key is obviously on my device and on their servers. (Else you could not restore a backup on another phone)

Instead I went for the chat export feature that is hidden in Menu > Settings > Chats > Chat history > Export chat. This is per chat, so a bit tedious. But I have a rough idea who I talk to a lot, so it’s not too bad.

From there you can do whatever you want. Look at file sizes, grep for random things, or write a simple Python script. I stole a regex from SO, fixed it for Python, put everything in a Pandas DataFrame, and from there you can just play with the df and then call plot on it.

Most of what I did so far is count the messages/characters per month. Very interesting to see how things change over time and in response to real life events. Picture omitted as a reminder how much you can tell about someone by meta-data alone.

import re
import sys
import pandas as pd
import matplotlib.pyplot as plt

regex = """(?P<datetime>\d{1,2}\/\d{1,2}\/\d{1,4}, \d{1,2}:\d{1,2}( (?i)[ap]m)*) - (?P<name>.*(?::\s*\w+)*|[\w\s]+?)(?:\s+(?P<action>joined|left|was removed|changed the (?:subject to "\w+"|group's icon))|:\s(?P<message>(?:.+|\n(?!\d{1,2}\/\d{1,2}\/\d{1,4}, \d{1,2}:\d{1,2}( (?i)[ap]m)*))+))"""

files = sys.argv[1:]

for fname in files:
    with open(fname) as f:
        text = f.read()
    matches = re.findall(regex, text)
    messages = []
    for match in matches:
        messages.append(match[::2])

    df = pd.DataFrame(messages, columns=['datetime', 'name', 'message'])
    df.datetime = pd.to_datetime(df.datetime, dayfirst=True)
    df.set_index('datetime', inplace=True)
    lengths = df.message.str.len()
    monthly = lengths.groupby(pd.Grouper(freq='M')).sum()
    #monthly = lengths.groupby(pd.Grouper(freq='D')).count().rolling('30d', min_periods=1).sum()
    #plt.figure()
    #ax = monthly.plot(title=fname[19:-4])
    ax = monthly.plot()

ax.legend([fname[19:-4] for fname in files])
plt.ylabel("bytes/month")
#plt.ylabel("messages/month")
plt.show()
Pepijn de Vos