<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Solomon Weinstein on Medium]]></title>
        <description><![CDATA[Stories by Solomon Weinstein on Medium]]></description>
        <link>https://medium.com/@fruitandotherfruit?source=rss-66e38aa9b6e3------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*kugiHUPjRFIj6PdB</url>
            <title>Stories by Solomon Weinstein on Medium</title>
            <link>https://medium.com/@fruitandotherfruit?source=rss-66e38aa9b6e3------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 30 May 2026 17:33:59 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@fruitandotherfruit/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Image Processing 02]]></title>
            <link>https://medium.com/@fruitandotherfruit/image-processing-02-0a3631164350?source=rss-66e38aa9b6e3------2</link>
            <guid isPermaLink="false">https://medium.com/p/0a3631164350</guid>
            <dc:creator><![CDATA[Solomon Weinstein]]></dc:creator>
            <pubDate>Tue, 21 Apr 2026 15:22:47 GMT</pubDate>
            <atom:updated>2026-04-21T15:22:47.956Z</atom:updated>
            <content:encoded><![CDATA[<p>This is absolutely working. Here’s my Processing sketch that sends images:</p><pre>import oscP5.*;<br>import netP5.*;<br>import java.io.File;<br><br>OscP5 oscP5;<br>NetAddress wekinator;<br><br>PImage img;<br><br>int w = 10;<br>int h = 10;<br><br>void setup() <br>{<br>  size(400, 400);<br><br>  oscP5 = new OscP5(this, 12000);<br>  wekinator = new NetAddress(&quot;127.0.0.1&quot;, 6448);<br><br>  colorMode(RGB, 255);<br>}<br><br>void draw() <br>{<br>  background(0);<br><br>  if (img != null) <br>  {<br>    image(img, 0, 0, width, height);<br>  }<br>}<br><br>void keyPressed() <br>{<br>  if (key == &#39;l&#39;) <br>  {<br>    selectInput(&quot;Select an image&quot;, &quot;FileSelected&quot;);<br>  }<br><br>  if (key == &#39;s&#39; &amp;&amp; img != null) <br>  {<br>    sendImageToWekinator(img);<br>  }<br>}<br><br>void FileSelected(File selection) <br>{<br>  if (selection != null) <br>  {<br>    img = loadImage(selection.getAbsolutePath());<br>  }<br>}<br><br>void sendImageToWekinator(PImage source) <br>{<br><br>  source.loadPixels();<br><br>  float total = 0;<br>  for (int i = 0; i &lt; source.pixels.length; i++) <br>  {<br>    float r = red(source.pixels[i]);<br>    float g = green(source.pixels[i]);<br>    float b = blue(source.pixels[i]);<br>    total += (r + g + b) / 3.0;<br>  }<br>  float avgBrightness = (total / source.pixels.length) / 255.0;<br><br>  PImage small = source.copy();<br>  small.resize(w, h);<br>  small.loadPixels();<br><br>  OscMessage msg = new OscMessage(&quot;/wek/inputs&quot;);<br><br>  msg.add(avgBrightness);<br><br>  for (int i = 0; i &lt; small.pixels.length; i++) <br>  {<br><br>    float r = red(small.pixels[i]) / 255.0;<br>    float g = green(small.pixels[i]) / 255.0;<br>    float b = blue(small.pixels[i]) / 255.0;<br><br>    msg.add(r);<br>    msg.add(g);<br>    msg.add(b);<br>  }<br><br>  oscP5.send(msg, wekinator);<br>}</pre><p>I load images by pressing the L key then send them to Wekinator by pressing S. I trained Wekinator on just four images for now, all of trees. The first is a bright image of one tree, the second a dark image of one tree, the third a bright image of lots of trees, and the fourth a dark image of lots of trees. I trained it so that brighter corresponds to a higher cutoff frequency of my lowpass filter, and more trees corresponds to a higher pitch.</p><p>It seems to be working relatively well. Because I only trained it on four images, the neural network is picking up on some factors that I didn’t intent it to. Generally, though, images with lots of trees give me a higher pitch, and brighter images give me a higher cutoff frequency. When I train it on more images, these extraneous factors should stop influencing it as much.</p><p>Next up is adding more information. I’ll train it to recognize a few more object types and image parameters, and I’ll add a few more sound output parameters as well.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=0a3631164350" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Image Processing 01]]></title>
            <link>https://medium.com/@fruitandotherfruit/image-processing-01-207e6e1d4bc4?source=rss-66e38aa9b6e3------2</link>
            <guid isPermaLink="false">https://medium.com/p/207e6e1d4bc4</guid>
            <dc:creator><![CDATA[Solomon Weinstein]]></dc:creator>
            <pubDate>Tue, 14 Apr 2026 14:58:13 GMT</pubDate>
            <atom:updated>2026-04-14T15:00:36.517Z</atom:updated>
            <content:encoded><![CDATA[<p>I’ve moved on to image processing. I’m starting out with just two different things: object classification and a brightness value. I’ll add more once I get this working, but I’ll never know if it’s functioning how I want if I start out with 10 parameters.</p><p>I’m writing this as another Processing sketch. For now, I’m going to send a 301 element vector to Wekinator. The first element is the average brightness of the image, and the other 300 are color information for each pixel. I’m going to deal with square images scaled down to 10 by 10 pixels for the time being. It’s not very precise, but it’s less to deal with right now. The actual process is no different once I scale it up. So, each OSC message is one brightness value and RGB values for each of 100 pixels.</p><p>My understanding is that it doesn’t matter if Wekinator receives a message where every 3 values (R, G, and B) correspond to just one pixel. It will recognize patterns equally well regardless of whether it “knows” that these value aren’t all separate.</p><p>No finished code to show right now but it’s all in the works. I’ll aim to have it done by next class.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=207e6e1d4bc4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Another Update]]></title>
            <link>https://medium.com/@fruitandotherfruit/another-update-e5ae911ae750?source=rss-66e38aa9b6e3------2</link>
            <guid isPermaLink="false">https://medium.com/p/e5ae911ae750</guid>
            <dc:creator><![CDATA[Solomon Weinstein]]></dc:creator>
            <pubDate>Fri, 10 Apr 2026 15:05:07 GMT</pubDate>
            <atom:updated>2026-04-10T17:41:56.544Z</atom:updated>
            <content:encoded><![CDATA[<p>I wrote a Chuck script to take Wekinator’s outputs and convert them to the frequency and lowpass cutoff frequency of a sine oscillator. I’m not getting any sound out of Chuck, though. Wekinator is outputting fine, but that doesn’t necessarily mean that Chuck is listening. I’m going to try using that Chuck script that checks if it it receiving OSC messages.</p><p>Chuck isn’t receiving OSC messages. I’m getting an “unable to create server instance” error. Not sure what’s up.</p><p>Ah, I think this is exactly the issue we talked about a few days ago. I closed my old Chuck script but it’s still sitting on port 12000. Let me try a different port.</p><p>That worked. Chuck is receiving OSC messages now. There’s probably something wrong with my original script.</p><p>I’m getting this error:</p><pre>&lt;compiled.code&gt;:7:22: error: ugen&#39;s of type &#39;DAC&#39; have no input - cannot =&gt; from another ugen<br>[7] SinOsc p0 =&gt; LPF lpf =&gt; dac;<br>                         ^</pre><p>The internet seems to think that Chuck is misinterpreting “dac” as something that can’t take input, and that replacing it with dac.left to specify channel 0 will fix it.</p><p>Now it can’t bind to port 12000. I think there’s a ghost Chuck running in the background. I checked and there isn’t. Gonna call it for now and see if I can figure it out later.</p><p>Update: I got it working. Just an audio driver issue I think. I also moved over to port 12001; something must have been sitting on port 12000.</p><p>Here’s the Chuck code:</p><pre>OscRecv recv;<br>12000 =&gt; recv.port;<br>recv.listen();<br><br>recv.event(&quot;/wek/outputs, f f&quot;) @=&gt; OscEvent osc;<br><br>SawOsc p0 =&gt; LPF lpf =&gt; dac;<br><br>0.2 =&gt; p0.gain;<br>300 =&gt; p0.freq;<br>1000 =&gt; lpf.freq;<br><br>fun float map(float mapme, float low1, float high1, float low2, float high2) {<br>    return (mapme - low1) / (high1 - low1) * (high2 - low2) + low2;<br>}<br><br>while (true) {<br>    osc =&gt; now; <br><br>    while (osc.nextMsg() != 0) {<br>        osc.getFloat() =&gt; float x;<br>        osc.getFloat() =&gt; float y;<br><br>        map(x, 0.0, 1.0, 100.0, 1000.0) =&gt; p0.freq;<br><br>        map(y, 0.0, 1.0, 200.0, 5000.0) =&gt; lpf.freq;<br>    }<br>}</pre><p>It’s all working when integrated too. I can set the audio parameters manually in Wekinator and move my cursor to a location that I like in the Processing sketch, train the model a few times, and run it. When I move my cursor in the Processing sketch, the audio coming out of Chuck changes in real-time.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e5ae911ae750" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Update]]></title>
            <link>https://medium.com/@fruitandotherfruit/update-045b1e4083dd?source=rss-66e38aa9b6e3------2</link>
            <guid isPermaLink="false">https://medium.com/p/045b1e4083dd</guid>
            <dc:creator><![CDATA[Solomon Weinstein]]></dc:creator>
            <pubDate>Tue, 07 Apr 2026 15:02:37 GMT</pubDate>
            <atom:updated>2026-04-07T15:05:43.783Z</atom:updated>
            <content:encoded><![CDATA[<p>(This is all written in real-time as I work through this)</p><p>I’m making my way through the detailed walkthrough section of the Wekinator documentation.</p><p>I’m trying to write a basic program in Processing that takes mouse position as input and sends it to Wekinator (essentially just mimicking the first half of the example project that I played with a little while ago). I don’t know Java and I’ve never used Processing.</p><p>I’ve been looking through the <a href="https://sojamo.de/libraries/oscp5/reference/index.html">documentation</a> for the oscP5 library for a thousand years and I think I can figure it all out.</p><p>Pretty sure I wrote a sketch that will work. The visual component is working fine on the Processing end, at least. Just have to see if Wekinator likes it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/330/1*HCmZwirIQvPoCm5ep0eVyQ.png" /><figcaption>The sketch</figcaption></figure><p>Wekinator is not receiving any OSC messages. I don’t know why. My input port is set to 6448, the input types match the type Wekinator is expecting to receive, I have the correct number of inputs, and the input message format is correct. This is probably because I am learning Java completely on the fly. Still troubleshooting.</p><p>Alright, I’m getting somewhere. I downloaded the WekiInputHelper program that acts as an intermediate step between the inputs themselves and Wekinator receiving them. If I manually send an output from WekiInputHelper to Wekinator (on any port), then Wekinator receives it. I also confirmed that no other program is using port 6448, because WekiInputHelper throws an error when it tries to listen to a port that’s already in use. So the problem isn’t with Wekinator receiving inputs, it’s that my mouse movement isn’t actually sending them.</p><p>It started working. Don’t know why. Moving on.</p><p>I don’t really remember changing anything between it not working and working but here’s the final sketch:</p><pre>import oscP5.*;<br>import netP5.*;<br><br>OscP5 oscobject; //makes new OscP5 object<br>NetAddress destination; // likewise<br><br>void setup() {<br>  size(200, 200); //mouse region<br>  oscobject = new OscP5(this, 12000); //listens to port 12000<br>  destination = new NetAddress(&quot;127.0.0.1&quot;, 6448); //sends to port 6448<br>}<br><br>void draw() {<br>  background(0);<br>  float x = map(mouseX, 0, width, 0, 1); //maps my mouse position from position in the window to 0-1 range<br>  float y = map(mouseY, 0, height, 0, 1);<br>  <br>  OscMessage msg = new OscMessage(&quot;/wek/inputs&quot;);<br>  msg.add(x); <br>  msg.add(y);<br>  <br>  oscobject.send(msg, destination);<br>  <br>  fill(255);<br>  ellipse(mouseX, mouseY, 10, 10); //little bubble for my cursor<br>}</pre><p>All the commenting is much more for me than for anyone reading it. It’s way easier to write what each line does here than reference the documentation every time I forget.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=045b1e4083dd" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Wekinator is Cool]]></title>
            <link>https://medium.com/@fruitandotherfruit/wekinator-is-cool-b0449a17e43e?source=rss-66e38aa9b6e3------2</link>
            <guid isPermaLink="false">https://medium.com/p/b0449a17e43e</guid>
            <dc:creator><![CDATA[Solomon Weinstein]]></dc:creator>
            <pubDate>Fri, 27 Mar 2026 04:25:32 GMT</pubDate>
            <atom:updated>2026-03-27T04:25:32.233Z</atom:updated>
            <content:encoded><![CDATA[<p>Wekinator is definitely the way to go here. I don’t see myself successfully writing an ML algorithm from scratch in any reasonable amount of time, and Wekinator solves that.</p><p>I downloaded Wekinator and started playing around with some of the test programs to get a sense of how it works. I paired a mouse location input with continuous sound generation output and trained it a number of times on various data.</p><p>What I’m aiming to do is basically a more complicated version of this. This takes a two-number array as an input, and I can write my parameters such that they fit as a series of numbers into an array as well. There are only so many objects that an image of the outdoors can contain, so I can assign each of these a number. Perhaps a second dimension of the array can indicate relative frequency of objects. Other image parameters, like brightness, general color composition, saturation, and depth of the scene, can be assigned a 0-n (n tbd) value and sit in the array as well. It is a much more complicated process to derive this input from an image than it is to derive an x-y pair from mouse location, but an array is an array. Once I have it, I can train Wekinator to map these parameters to parameters of sound synthesis.</p><p>I’m going to start looking into the exact machine learning process that the sound synthesis program I ran uses and compare it to others. I’ll decide which to use and figure out how to do it next.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b0449a17e43e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Initial Project Overview]]></title>
            <link>https://medium.com/@fruitandotherfruit/initial-project-overview-4df8a1505206?source=rss-66e38aa9b6e3------2</link>
            <guid isPermaLink="false">https://medium.com/p/4df8a1505206</guid>
            <dc:creator><![CDATA[Solomon Weinstein]]></dc:creator>
            <pubDate>Fri, 13 Mar 2026 23:11:35 GMT</pubDate>
            <atom:updated>2026-05-04T21:05:01.554Z</atom:updated>
            <content:encoded><![CDATA[<p>As a brief re-summary: I aim to make a keyboard that can take image input of what’s around me (specifically focusing on outdoor scenes) and, based on the image content, synthesize a set of sounds that I can use on the keyboard.</p><p>I imagine integrating this into a physical keyboard will be the last step, and relatively easier than the rest of the project. The majority of the work will involve writing a program that can analyze images and synthesize sounds.</p><p>My hope is for the image analysis to be fairly comprehensive. It would note objects, colors, textures, depth, spatial layout, and other qualities of images. Objects and textures (and most other qualities, in an implicit way) can be classified by a convolutional neural network (CNN). CNNs find objects and textures in images by detecting edges with convolutions and recognizing patterns in these edges to classify things. <a href="https://www.pnas.org/doi/full/10.1073/pnas.1715832114">This paper</a> from 2017 discusses the math and theory behind an image analysis CNN that is easily trainable, widely applicable, and requires very few parameters relative to other models that perform similarly. Writing this sort of model on my own would require a lot of learning, but it’s a saturated focus area and I’m confident that there are enough resources available for me to do it.</p><p>To create sounds, I want to create some sort of mapping from the parameters in the image to parameters of sound synthesis. Different image parameters could decide synthesis type; waveform shape; number of oscillators; filter types and parameter values; volume, spatialization, and filter envelopes; and force input interpretation. This approach would require a lot of fine-tuning on my part to ensure that the sounds the program outputs fit the proper mood in the image. These papers (<a href="https://ieeexplore.ieee.org/document/1287636">a</a> and <a href="https://pmc.ncbi.nlm.nih.gov/articles/PMC3866150/">b</a>) discuss different strategies for sonification of images and other non-sound data forms. They both suffer from being reasonably old — 2004 and 2013, respectively. Or rather, this field is actively developing and a lot has changed in the past 13–22 years (if it makes <em>me</em> wince to call 2013 old, I’d better tread lightly). There are still useful tools in both papers, though.</p><p>The hardware implementation will happen later in the project. I have a Novation Launchkey 37 that I can use (it has aftertouch, and that adds an extra layer of expressiveness that I can map to), but the specific keyboard won’t matter too much.</p><p>Much farther in the future, I hope to integrate everything into a keyboard. It would have the computer inside and automatically push the sounds it synthesizes to different tracks on the keyboard. I would have to decide whether the keyboard should have a small detachable camera, or just take wireless input from a phone camera.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4df8a1505206" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[NIME and ICMA Papers]]></title>
            <link>https://medium.com/@fruitandotherfruit/nime-and-icma-papers-a9136779aec6?source=rss-66e38aa9b6e3------2</link>
            <guid isPermaLink="false">https://medium.com/p/a9136779aec6</guid>
            <dc:creator><![CDATA[Solomon Weinstein]]></dc:creator>
            <pubDate>Fri, 13 Feb 2026 02:23:29 GMT</pubDate>
            <atom:updated>2026-02-13T02:23:29.816Z</atom:updated>
            <content:encoded><![CDATA[<p>Papers I found interesting:</p><p><a href="https://nime.org/proceedings/2025/nime2025_12.pdf">Synthetic Ornithology: Machine learning, simulations and hyper-real soundscapes</a></p><p><a href="https://nime.org/proceedings/2025/nime2025_43.pdf">The Shadow Harvester: Sonifying the Body Through Light</a></p><p><a href="https://quod.lib.umich.edu/cgi/p/pod/dod-idx/emotional-characteristics-of-rain-sound-effects.pdf?c=icmc;idno=bbp2372.2018.065;format=pdf">The Emotional Characteristics of Rain Sound Effects</a></p><p>Brief exploration of the second paper above:</p><p>This paper interested me because of its relation to what I am considering creating as my project. The basic concept is the same: visual data is transformed into auditory output.</p><p>In this case, the visual data is the shadow of a violinist playing their instrument. The violinist is backlit by a bright light and their shadow is projected onto a field of sensors that detect the presence and intensity of the light. As the violinist plays, their physical movement, as picked up by what sensors are and are not blocked by their shadow, also controls different parameters in a Max patch, so the acoustic (violin) sounds are accompanied by changes to the digital sound.</p><p>The fact that it is the shadow specifically that controls these parameters is interesting, because it means not all changes in the violinist’s position will affect the digital sound. The shadow is a two-dimensional projection of a three-dimensional thing, so not all information is captured.</p><p>The goal of the project was for this to be a form of performance art. The shadow would be visible to audience members on a cloth screen, and the violinist would have to pay attention to both the sound they are producing on their instrument and the sound their movement is making.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a9136779aec6" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Project?]]></title>
            <link>https://medium.com/@fruitandotherfruit/project-89caa925a5c2?source=rss-66e38aa9b6e3------2</link>
            <guid isPermaLink="false">https://medium.com/p/89caa925a5c2</guid>
            <dc:creator><![CDATA[Solomon Weinstein]]></dc:creator>
            <pubDate>Fri, 06 Feb 2026 16:32:51 GMT</pubDate>
            <atom:updated>2026-02-06T16:32:51.817Z</atom:updated>
            <content:encoded><![CDATA[<p>I am a lover of all things outdoors. In the last few years, that has meant rock climbing, caving, white water kayaking, and much more, but the one thing that I’ve always done is hike.</p><p>I take hiking loosely. Recently it has skewed much more toward trail running, but I am equally happy running a trail in one day or backpacking it in five.</p><p>When I’m out there, I don’t tend to listen to music. But occasionally, upon stopping to take a rest, I get the urge to make music myself. Once or twice I’ve brought a little MIDI keyboard out and gotten frustrated at the mobile version of Garage Band. Part of the difficulty, too, is that I want to use different sounds depending on where I am and what is around me (the vibe, so to speak). That can take a long time to dial in.</p><p>So here’s the grand idea: I want to be able to take a picture or, perhaps, a short video of what’s around me, have a program that I create analyze colors, shapes, and overall trends based on parameters that I give it, and generate a series of sounds that it synthesizes. I don’t want to instruct a generative AI system to do this for me; I want to program it myself.</p><p>Initially, this can be a photo that I take with my phone, feed into a program manually, and then send to a keyboard, but down the line I think it would be very cool for it all to be integrated in the board. Camera, analysis, and all.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=89caa925a5c2" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>