<?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"><channel><title><![CDATA[M5Sound 😎]]></title><description><![CDATA[<p dir="auto">I just wrote a simple polyphonic background synthesizer library for the Core2:</p>
<pre><code class="language-c++">#include &lt;M5Core2.h&gt;

Synth a;

void setup() {
  M5.begin();
  a.freq = 1000;
  a.gain = 0.4;
}

void loop() {
  M5.update();
  if (M5.Buttons.event == E_TOUCH) a.start();
  if (M5.Buttons.event == E_RELEASE) a.stop();
}
</code></pre>
<p dir="auto">You can have multiple Synth instances, their output is mixed. Every synth has attack, decay, sustain release envelope, and the <code>waveform</code> member can be set to <code>SINE</code>, <code>SQUARE</code>, <code>SAWTOOTH</code>, <code>TRIANGLE</code> or <code>NOISE</code>. Sound will continue as long as M5.update() is called. Default attack and release at 5 ms, so no ugly clicks.</p>
<p dir="auto">Under 200 lines in the cpp file...</p>
<p dir="auto">A few more convenience features coming, buffering to improve a bit still, but this is the core.</p>
<p dir="auto">Do play with the <a href="https://github.com/ropg/M5Core2/blob/M5Sound/examples/Sound/DTMF_dialer/DTMF_dialer.ino" target="_blank" rel="noopener noreferrer nofollow ugc"><code>DTMF_dialer</code> example</a>, and try holding it sideways...</p>
<p dir="auto">It's all on the <a href="https://github.com/ropg/M5Core2/tree/M5Sound" target="_blank" rel="noopener noreferrer nofollow ugc"><code>M5Sound</code> branch</a> of <a href="https://github.com.ropg/M5Core2" target="_blank" rel="noopener noreferrer nofollow ugc">my fork</a>.</p>
]]></description><link>https://community.m5stack.com/topic/2381/m5sound</link><generator>RSS for Node</generator><lastBuildDate>Wed, 29 Apr 2026 06:30:00 GMT</lastBuildDate><atom:link href="https://community.m5stack.com/topic/2381.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 16 Oct 2020 19:39:21 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to M5Sound 😎 on Sun, 18 Oct 2020 21:59:32 GMT]]></title><description><![CDATA[<p dir="auto">Rop, all the included examples run fine.<br />
I found that the problem is that Button::_hidden is uninitialized. I will open an issue.</p>
<p dir="auto">Now I can easily add hit and miss sounds to my button testing app. Will update soon.</p>
]]></description><link>https://community.m5stack.com/post/10394</link><guid isPermaLink="true">https://community.m5stack.com/post/10394</guid><dc:creator><![CDATA[vkichline]]></dc:creator><pubDate>Sun, 18 Oct 2020 21:59:32 GMT</pubDate></item><item><title><![CDATA[Reply to M5Sound 😎 on Sun, 18 Oct 2020 15:31:56 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/vkichline" aria-label="Profile: vkichline">@<bdi>vkichline</bdi></a> Yes I have been making a few changes, just what I needed for M5Sound. Which did include pianoMode, which by necessity changes a bit of a voodoo state-machine. My examples all still work I think, no?</p>
]]></description><link>https://community.m5stack.com/post/10388</link><guid isPermaLink="true">https://community.m5stack.com/post/10388</guid><dc:creator><![CDATA[Rop]]></dc:creator><pubDate>Sun, 18 Oct 2020 15:31:56 GMT</pubDate></item><item><title><![CDATA[Reply to M5Sound 😎 on Sat, 17 Oct 2020 22:42:15 GMT]]></title><description><![CDATA[<p dir="auto">Thanks for the <code>checkRotation</code> function!<br />
I've just glanced at the Sound stuff (very nice!) but am still working on Touch.<br />
I wrote a test to determine what the minimal effective touch button size is (<a href="https://github.com/vkichline/ButtonSizeTest" target="_blank" rel="noopener noreferrer nofollow ugc">https://github.com/vkichline/ButtonSizeTest</a>).<br />
When I moved it from PlatformIO (for development) to Arduino (for publishing) I moved from your master branch to the M5Sound branch. The app built, but did not run in M5Sound. (It drew one button and stopped. I haven't looked into it yet.)</p>
<p dir="auto">Are you making touch changes in M5Sound as well?</p>
]]></description><link>https://community.m5stack.com/post/10371</link><guid isPermaLink="true">https://community.m5stack.com/post/10371</guid><dc:creator><![CDATA[vkichline]]></dc:creator><pubDate>Sat, 17 Oct 2020 22:42:15 GMT</pubDate></item><item><title><![CDATA[Reply to M5Sound 😎 on Sat, 17 Oct 2020 19:52:42 GMT]]></title><description><![CDATA[<p dir="auto">Just checked in the new improvements. There is now a polyphonic piano demo. Only two notes can be sustained – if you touch at different screen heights – because of the touch-sensor limitation, but keys that were hit before keep sounding for a bit. Shows M5Sound has no problem with 14 concurrent Synth instances.</p>
<p dir="auto">To make this satisfying, I needed to be able to move my finger from key to key (glissando), which M5Button didn't let me do. Enter <code>M5.Buttons.pianoMode = true</code>. Now you can slip off one button and onto the next. The price to pay is that gesture recognition is switched off in pianoMode.</p>
<p dir="auto">(The DTMF dialer is also cooler in pianoMode, so changed that too.)</p>
<p dir="auto">Also there's now <code>1000_hz</code>and <code>C_major</code> examples, just so that not all examples are somewhat advanced bits of code. But <code>Piano</code>, like the <code>DTMF_dialer</code>, is still pretty small and quite readable for a stylish polyphonic piano:</p>
<pre><code class="language-c++">/*

Polyphonic synthesizer. Lingering notes will continue to sound as new notes
are played. If you place one finger high on the screen and another low, you
can even play two notes at the same time. As you can see you can have many
synths going at the same time.

*/

#include &lt;M5Core2.h&gt;

#define WKW         40
#define WKH        240
#define BKW         30
#define BKH        160
#define WHITE_KEY  {WHITE, NODRAW, BLACK}
#define BLACK_KEY  {BLACK, NODRAW, NODRAW}
#define NUM_KEYS    14

float notes[NUM_KEYS] = { NOTE_F4 , NOTE_G4 , NOTE_A4 , NOTE_B4 , NOTE_C5,
                          NOTE_D5 , NOTE_E5 , NOTE_F5 , NOTE_Gb4, NOTE_Ab4,
                          NOTE_Bb4, NOTE_Db5, NOTE_Eb5, NOTE_Gb5 };

// (waveform, freq, attack, decay, sustain, release)
Synth synth[NUM_KEYS] = Synth(TRIANGLE, 0, 50, 300, 0.7, 1000);

Button f_(   0, 0, WKW, WKH, false, "f" , WHITE_KEY);
Button g_(  40, 0, WKW, WKH, false, "g" , WHITE_KEY);
Button A_(  80, 0, WKW, WKH, false, "A" , WHITE_KEY);
Button B_( 120, 0, WKW, WKH, false, "B" , WHITE_KEY);
Button C_( 160, 0, WKW, WKH, false, "C" , WHITE_KEY);
Button D_( 200, 0, WKW, WKH, false, "D" , WHITE_KEY);
Button E_( 240, 0, WKW, WKH, false, "E" , WHITE_KEY);
Button F_( 280, 0, WKW, WKH, false, "F" , WHITE_KEY);
Button gb(  25, 0, BKW, BKH, false, "gb", BLACK_KEY);
Button Ab(  65, 0, BKW, BKH, false, "Ab", BLACK_KEY);
Button Bb( 105, 0, BKW, BKH, false, "Bb", BLACK_KEY);
Button Db( 185, 0, BKW, BKH, false, "Db", BLACK_KEY);
Button Eb( 225, 0, BKW, BKH, false, "Eb", BLACK_KEY);
Button Gb( 305, 0,  15, BKH, false, "Gb", BLACK_KEY);

void setup() {
  M5.begin();
  M5.Buttons.draw();

  // Prettier with top of keys as straight line
  M5.Lcd.fillRect(0, 0, 320, 5, BLACK);

  // Trick to make sure buttons do not draw over eachother anymore
  M5.Buttons.drawFn = nullptr;

  // So that you can swipe from one button to another
  M5.Buttons.pianoMode = true;

  // Set up syths with their notes
  for (uint8_t n = 0; n &lt; 14; n++) {
    synth[n].freq = notes[n];
  }

  M5.Buttons.addHandler(pressKey  , E_TOUCH);
  M5.Buttons.addHandler(releaseKey, E_RELEASE);
}

void loop() {
  M5.update();
}

void pressKey(Event&amp; e) {
  // instanceIndex() -4 because of background, BtnA, BtnB and BtnC.
  uint8_t key = e.button-&gt;instanceIndex() - 4;
  synth[key].start();
}


void releaseKey(Event&amp; e) {
  uint8_t key = e.button-&gt;instanceIndex() - 4;
  synth[key].stop();
}
</code></pre>
]]></description><link>https://community.m5stack.com/post/10369</link><guid isPermaLink="true">https://community.m5stack.com/post/10369</guid><dc:creator><![CDATA[Rop]]></dc:creator><pubDate>Sat, 17 Oct 2020 19:52:42 GMT</pubDate></item><item><title><![CDATA[Reply to M5Sound 😎 on Sat, 17 Oct 2020 10:12:06 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/vkichline" aria-label="Profile: vkichline">@<bdi>vkichline</bdi></a> Made checkRotation more generic:</p>
<pre><code class="language-c++">bool checkRotation(uint16_t msec) {
  if (millis() - rotationLastChecked &lt; msec) return false;
  rotationLastChecked = millis();
  const float threshold = 0.85;
  float ax, ay, az;
  M5.IMU.getAccelData(&amp;ax, &amp;ay, &amp;az);
  uint8_t newRotation;
  if      (ay &gt;  threshold) newRotation = 1;
  else if (ay &lt; -threshold) newRotation = 3;
  else if (ax &gt;  threshold) newRotation = 2;
  else if (ax &lt; -threshold) newRotation = 0;
  else return false;
  if (M5.Lcd.rotation == newRotation) return false;
  columns = newRotation % 2 ? 4 : 3;
  M5.Lcd.clearDisplay();
  M5.Lcd.setRotation(newRotation);
  return true;
}
</code></pre>
<p dir="auto">All it needs is a global <code>uint32_t rotationLastChecked</code> and for you to have ran <code>M5.IMU.Init()</code> (which seems to set power things on the MPU, so there's probably a reason it's not in <code>M5.begin()</code>, haven't read the datasheet.)</p>
<p dir="auto"><code>checkRotation</code> returns a <code>bool</code> and takes the number of milliseconds between checks. It returns <code>true</code> if it has already rotated and cleared the display for you and needs you to set things up again. So my <code>loop()</code> now does <code>if (checkRotation(1000)) doButtons()</code></p>
]]></description><link>https://community.m5stack.com/post/10364</link><guid isPermaLink="true">https://community.m5stack.com/post/10364</guid><dc:creator><![CDATA[Rop]]></dc:creator><pubDate>Sat, 17 Oct 2020 10:12:06 GMT</pubDate></item><item><title><![CDATA[Reply to M5Sound 😎 on Sat, 17 Oct 2020 08:28:31 GMT]]></title><description><![CDATA[<p dir="auto">I'm pretty sure it can do other tones as well. I chose blue for a reason... :)</p>
]]></description><link>https://community.m5stack.com/post/10363</link><guid isPermaLink="true">https://community.m5stack.com/post/10363</guid><dc:creator><![CDATA[Rop]]></dc:creator><pubDate>Sat, 17 Oct 2020 08:28:31 GMT</pubDate></item><item><title><![CDATA[Reply to M5Sound 😎 on Sat, 17 Oct 2020 07:05:20 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/felmue" aria-label="Profile: felmue">@<bdi>felmue</bdi></a></p>
<p dir="auto">☑ Valid DTMF. (Didn't have an easy means of testing...)</p>
]]></description><link>https://community.m5stack.com/post/10362</link><guid isPermaLink="true">https://community.m5stack.com/post/10362</guid><dc:creator><![CDATA[Rop]]></dc:creator><pubDate>Sat, 17 Oct 2020 07:05:20 GMT</pubDate></item><item><title><![CDATA[Reply to M5Sound 😎 on Fri, 16 Oct 2020 21:13:43 GMT]]></title><description><![CDATA[<p dir="auto">Hey Rop</p>
<p dir="auto">never resting - it seems. Very nice! Just tried it successfully with my old rotary phone.</p>
<p dir="auto">Cheers<br />
Felix</p>
]]></description><link>https://community.m5stack.com/post/10360</link><guid isPermaLink="true">https://community.m5stack.com/post/10360</guid><dc:creator><![CDATA[felmue]]></dc:creator><pubDate>Fri, 16 Oct 2020 21:13:43 GMT</pubDate></item><item><title><![CDATA[Reply to M5Sound 😎 on Fri, 16 Oct 2020 21:01:03 GMT]]></title><description><![CDATA[<p dir="auto">Nice, efficient implementation of the dtmf sample. I see <code>btn.userData</code> came in handy!<br />
The audio quality is great, completely free of pops and clicks.<br />
I think I'll add <code>checkRotation()</code> to my system library!</p>
]]></description><link>https://community.m5stack.com/post/10357</link><guid isPermaLink="true">https://community.m5stack.com/post/10357</guid><dc:creator><![CDATA[vkichline]]></dc:creator><pubDate>Fri, 16 Oct 2020 21:01:03 GMT</pubDate></item></channel></rss>