<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Soroor</title>
    <description>The latest articles on DEV Community by Soroor (@soroor_f1685d04da42cfc0fd).</description>
    <link>https://dev.to/soroor_f1685d04da42cfc0fd</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4223224%2F8c11b91a-a1b9-4410-af1f-7a6ce52c8d19.png</url>
      <title>DEV Community: Soroor</title>
      <link>https://dev.to/soroor_f1685d04da42cfc0fd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/soroor_f1685d04da42cfc0fd"/>
    <language>en</language>
    <item>
      <title>How I built a music companion that plays in your own culture</title>
      <dc:creator>Soroor</dc:creator>
      <pubDate>Tue, 03 Nov 2026 00:04:28 +0000</pubDate>
      <link>https://dev.to/soroor_f1685d04da42cfc0fd/how-i-built-a-music-companion-that-plays-in-your-own-culture-28pa</link>
      <guid>https://dev.to/soroor_f1685d04da42cfc0fd/how-i-built-a-music-companion-that-plays-in-your-own-culture-28pa</guid>
      <description>&lt;p&gt;&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://reach-6o5x.onrender.com" rel="noopener noreferrer"&gt;reach-6o5x.onrender.com&lt;/a&gt; (press &lt;em&gt;Guided tour&lt;/em&gt;, top right) · &lt;strong&gt;Code:&lt;/strong&gt; &lt;a href="https://github.com/soroorgh93/reach" rel="noopener noreferrer"&gt;github.com/soroorgh93/reach&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A grandmother may forget a name. She rarely forgets the song she fell in love to.&lt;/p&gt;

&lt;p&gt;That's the idea behind &lt;strong&gt;Reach&lt;/strong&gt;, a music companion I built for people living with dementia, autism or hearing loss. You tell it who someone loves and what they need (sleep, calm, focus or memory), and it plays a calm session made from &lt;em&gt;their&lt;/em&gt; music, in &lt;em&gt;their&lt;/em&gt; culture and language.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: everyone gets the same "calm playlist"
&lt;/h2&gt;

&lt;p&gt;Music measurably helps with anxiety, pain and sleep. Cochrane reviews have found it again and again. But in hospitals and sleep apps, everyone gets the same calm playlist: Enya, Max Richter, rain sounds.&lt;/p&gt;

&lt;p&gt;A Persian grandmother who loves Hayedeh, a student who loves Jay Chou and a dancer who loves David Guetta all get the same list. They switch it off. &lt;strong&gt;Music only works as medicine if people keep listening, and people keep listening to music that is theirs.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I also tried simply asking a chatbot. I asked a language model for Persian sleep songs. It named eight, and none of them could be found in the Deezer or iTunes catalogues. It invented them.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Reach works
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwhpvmggsjzt5aofdxsw1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwhpvmggsjzt5aofdxsw1.jpg" alt="Three things, one session" width="800" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A small council of agents builds each session:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Listener&lt;/strong&gt; understands what you typed or said&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Taste&lt;/strong&gt; asks Qloo's taste graph for the artists closest to your favourites&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clinician&lt;/strong&gt; picks an evidence-graded protocol (for sleep: a tempo that starts at your pace and slows down)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Composer&lt;/strong&gt; writes the timeline: tempo, a gentle pulse, a safe volume&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guardian&lt;/strong&gt; checks the safety rules (child limits, hearing, never while driving)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gate&lt;/strong&gt; refuses if the evidence or the Qloo data is missing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2ypbq24dpssx4rm4ug0a.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2ypbq24dpssx4rm4ug0a.jpg" alt="How a session is made" width="799" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Qloo is the heart of it, not a lookup at the end
&lt;/h2&gt;

&lt;p&gt;For a sleep session for someone who loves Hayedeh, the Taste agent asks Qloo for artists that fit both her taste &lt;em&gt;and&lt;/em&gt; the texture of sleep:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /v2/insights
  ?filter.type=urn:entity:artist
  &amp;amp;signal.interests.entities=&amp;lt;Hayedeh's Qloo id&amp;gt;
  &amp;amp;filter.tags=urn:tag:genre:music:ambient,...acoustic,...classical,...piano
  &amp;amp;filter.exclude.tags=...metal,...edm,...hip_hop,...punk
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A second call adds &lt;code&gt;signal.location.query=Tehran&lt;/code&gt;, the city MusicBrainz says Hayedeh comes from, to get a pool from her own culture.&lt;/p&gt;

&lt;p&gt;Reach uses eight Qloo surfaces in total: entity search, artist insights, the location signal, tag insights, demographics, podcasts, movies and TV (the visual mode for deaf users), and places and books (a gentle next step "after the music"). &lt;strong&gt;Without Qloo, Reach refuses to make a session.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Only entity ids, tag ids, an age bucket and a city are ever sent to Qloo. Never the words "I can't sleep."&lt;/p&gt;

&lt;h2&gt;
  
  
  The hardest part: culture, not country
&lt;/h2&gt;

&lt;p&gt;My first version put Turkish pop singers in a Persian listener's sleep playlist, because Qloo ranked them higher. One early reply even said "from Iran", which felt wrong to the person testing it.&lt;/p&gt;

&lt;p&gt;So I removed country labels entirely and replaced them with measurement:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;the language of each artist's own song titles&lt;/li&gt;
&lt;li&gt;where MusicBrainz says the artist is from&lt;/li&gt;
&lt;li&gt;slots shared out per favourite, so a Shakira + Aznavour fan gets both Latin and French picks&lt;/li&gt;
&lt;li&gt;diversity, so it isn't ten songs by one singer&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There's no country table anywhere in the code. The same logic now serves Persian, Mandarin, Afrobeats, K-pop and Mexican listeners.&lt;/p&gt;

&lt;h2&gt;
  
  
  A sand plate in three.js
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkudpp19b24vserxfx4t6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkudpp19b24vserxfx4t6.gif" alt="A 3D sand plate drawing a new pattern for each frequency" width="480" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My favourite part: a 3D plate where each frequency (2 Hz deep sleep up to 40 Hz) draws its own figure in sand, like a Chladni plate. The sand gathers where the plate stays still. Each band also shows its evidence grade, and the experimental ones (like 40 Hz) say so clearly.&lt;/p&gt;

&lt;h2&gt;
  
  
  It listens back
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fulxzouzl7gqa6pfwsm9s.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fulxzouzl7gqa6pfwsm9s.gif" alt="One hand, one face" width="600" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the camera turned on, Reach reads a face and one hand &lt;strong&gt;on the device&lt;/strong&gt; with face-api.js and MediaPipe. Nothing is uploaded. Two fingers play the next song, a thumbs-down changes it, and a smile moves the mood dial.&lt;/p&gt;

&lt;p&gt;For people who can't hear, Reach switches to a visual protocol: a breathing light at six breaths a minute, vibration on the beat, and captioned films that Qloo picks from their taste.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does it beat a plain chatbot?
&lt;/h2&gt;

&lt;p&gt;I gave the same ten listeners to three systems: a generic playlist, a language model (llama 3.1 8B) and Reach, all using live Qloo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg33l0agkh077293pb7nq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg33l0agkh077293pb7nq.jpg" alt="Reach vs a chatbot" width="799" height="363"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Reach&lt;/th&gt;
&lt;th&gt;Plain chatbot&lt;/th&gt;
&lt;th&gt;Generic playlist&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Songs that really exist&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;60%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;From the person's own culture&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;92%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;89%&lt;/td&gt;
&lt;td&gt;36%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Calm when they need calm&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;96%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;70%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The chatbot invented four songs in ten. The generic playlist was real and calm, but the same for everyone. Ten people is a small test: it shows a pattern, not a clinical result.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;Cultural intelligence isn't a nice extra for health; it's what makes people keep listening. And only real taste data, not a model's guess, can tell you what that music is.&lt;/p&gt;

&lt;p&gt;Reach is a wellbeing tool, not a medical device. Every claim in the app shows its evidence grade and source.&lt;/p&gt;

&lt;h2&gt;
  
  
  Built with
&lt;/h2&gt;

&lt;p&gt;Python and Starlette on the server, three.js and Web Audio in the browser, Qloo, MusicBrainz, Deezer and iTunes previews, face-api.js, MediaPipe, and fourteen languages (Persian and Arabic right to left). It's one Docker container on Render, with no account and no database.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Try it:&lt;/strong&gt; &lt;a href="https://reach-6o5x.onrender.com" rel="noopener noreferrer"&gt;reach-6o5x.onrender.com&lt;/a&gt;. Start with the &lt;em&gt;Guided tour&lt;/em&gt;.&lt;br&gt;
&lt;strong&gt;Code (MIT):&lt;/strong&gt; &lt;a href="https://github.com/soroorgh93/reach" rel="noopener noreferrer"&gt;github.com/soroorgh93/reach&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd love your feedback, especially if you work in care or music therapy. 💛&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>javascript</category>
      <category>threejs</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
