{"componentChunkName":"component---src-templates-blog-post-js","path":"/less-is-more-why-soundcloud-low-passes-its-aac-transcodings","result":{"data":{"site":{"siteMetadata":{"title":"SoundCloud Backstage Blog","author":"SoundCloud"}},"markdownRemark":{"id":"4cdff3d6-14b5-5d2e-ba4f-586685956f02","excerpt":"Last year, SoundCloud upgraded its AAC encoder for the first time in over a decade. The new one (Fraunhofer’s libfdk_aac) delivers higher perceptual audio quality across every metric we track. But if you look at a spectrogram, you may notice something unexpected. Here’s the scenario: you upload a lossless master. You download your track from SoundCloud and open it in a spectrum analyser. There’s a hard shelf at 17 kHz where there used to be energy all the way to 20 kHz. The old encoder kept…","html":"<p>Last year, SoundCloud upgraded its AAC encoder for the first time in over a decade. The new one (Fraunhofer’s libfdk_aac) delivers higher perceptual audio quality across every metric we track.</p>\n<p>But if you look at a spectrogram, you may notice something unexpected.</p>\n<p>Here’s the scenario: you upload a lossless master. You download your track from SoundCloud and open it in a spectrum analyser. There’s a hard shelf at 17 kHz where there used to be energy all the way to 20 kHz. The old encoder kept those frequencies. The new one removes them.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 800px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/blog/static/c3deaa707b26e3482cc95abb9bbd9e16/ede78/native_vs_fdk_256k.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 36.59090909090909%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAABcSAAAXEgFnn9JSAAAB40lEQVQoz2WO20uTYRyAX2dNm+1b6hQtt2q6yg6gjYVmsQ5MPNBJvZNgFTVC2ZR5mna4DOovEMRFtG9iUVA3Yn9CQUgN2+ozcWxr4baKLvTq6WUVBL3wXLw/Hp7fT8zMzCKE+MN2iSIpk5QXZqHQQxKJxD/O/3iuXAd+kk6uIdRwpDA0bavFbjqBXTlOvdLCoQo3RrGbyNwcqWQKvd6AfouCTTkmnTbqja0crDwtHRtDgXHIrJJNysXT0zOFYGXJHppNnTQpbo4oZ2mtuESVOEBYVUnKYLGujFKdmaOmbpwSh6mLNnMPFuHEHxhjI54gEdMQodlHMmigwejkfM1VOqv76ai+TO9OL/uKW2QwUriwdGsVZn0DF2uvSc/DBUlf3Q0cRe2MjE7wJZoh9TmFmA8/Z4fYz8nyc/gsAby7Bhm0+PFbx3Do3DwOqzKYxlLSzGGDC591mIE6H8PWIUb2jnOmqJeJ0dssvY6z/D6OWHi6SFdNH5NNflTXLdRTQV64gyx03GXM7uHJ/DMy6Qw9tn4GGm8Sdk1JJnnZHuRV9x3uN3q5N/WA7LccmcxXRH49T/TNB1bfrZCNa+Q+auQlP7QV0tEYuWyOzY1Nlt/G0JY01mMrv51PGt81+V+OkVpL8vf9AsADPluiqmWYAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Old encoder vs new encoder\"\n        title=\"Old encoder vs new encoder\"\n        src=\"/blog/static/c3deaa707b26e3482cc95abb9bbd9e16/8ff1e/native_vs_fdk_256k.png\"\n        srcset=\"/blog/static/c3deaa707b26e3482cc95abb9bbd9e16/9ec3c/native_vs_fdk_256k.png 200w,\n/blog/static/c3deaa707b26e3482cc95abb9bbd9e16/c7805/native_vs_fdk_256k.png 400w,\n/blog/static/c3deaa707b26e3482cc95abb9bbd9e16/8ff1e/native_vs_fdk_256k.png 800w,\n/blog/static/c3deaa707b26e3482cc95abb9bbd9e16/6ff5e/native_vs_fdk_256k.png 1200w,\n/blog/static/c3deaa707b26e3482cc95abb9bbd9e16/2f950/native_vs_fdk_256k.png 1600w,\n/blog/static/c3deaa707b26e3482cc95abb9bbd9e16/ede78/native_vs_fdk_256k.png 1760w\"\n        sizes=\"(max-width: 800px) 100vw, 800px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>It looks like a downgrade. It’s actually the opposite. Here’s why.</p>\n<h2>Lossless vs lossy</h2>\n<p>A lossless file (WAV, FLAC) keeps every sample intact. What goes in comes out, bit for bit.\nNo decisions, no compromises.</p>\n<p>Lossy compression (AAC, MP3, Ogg) is a different game.\nThe encoder has to throw something away to hit a target file size.\nThe question isn’t whether it loses information. It will. The question is what it chooses to lose.</p>\n<h2>Make Every Bit Count</h2>\n<p>When SoundCloud compresses your upload to AAC, the encoder gets a fixed number of bits per chunk of audio. It splits those across frequency bands. More bits per band means a more faithful reproduction. Fewer means more distortion.</p>\n<p>There are never enough bits for everything. The encoder has to pick where to spend them.</p>\n<div id=\"aac-demo\"></div>\n<p>Play with the sliders. As the bitrate drops, the quantized signal drifts further from the original frequency distribution. But pull the low-pass filter left and something interesting happens: the encoder gives up the top frequencies and everything else gets sharper.</p>\n<p><strong>That’s the tradeoff: drop what you can barely hear, get a cleaner signal where you can.</strong></p>\n<h2>Why the Upper Frequencies?</h2>\n<p>Human hearing isn’t flat. We’re most sensitive between 2 and 5 kHz. Sensitivity decreases significantly at higher frequencies, and most adults cannot reliably perceive tones above 17 kHz, even under ideal listening conditions.</p>\n<p>Because of this, the highest frequencies offer one of the most efficient opportunities for bitrate optimization. A small reduction at the very top of the spectrum allows the encoder to improve accuracy across a much broader range of audible content.</p>\n<p>While a spectrogram treats every frequency equally, our ears do not. The encoder is designed around how people hear, not how graphs look.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 800px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/blog/static/00b8653b049ce7ffd5c6ea12d0319014/d010d/hearing_curve.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 49.53703703703704%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABcSAAAXEgFnn9JSAAABRElEQVQoz31Ti26DMAzM///lOqkDpNIlJORF8O4MVFSii2SZOM75fA5mXVeptQr9lZ1XbU19Q3zIEZZ0r7k4W9sihhvnnDQGdhBekN0K4q4W+S1ZbClqfYryHYN8zV7PtipNGnKMtVZCCG+ABFqwJwgtLcvGjt3Ax6Uq0AR74lwLgu2KYmYYBpnnWQGOFgMkGHeg1zpJkBF/KuOMbpp4FHiAdc55A5ymSRnyEhk5VDpabic9DynSCXDZdS2444IX0/e9RDAkIJMCqr2EvhrSJ8A5SOh/NobUcExJtdn0bZdg/zGsaPk5dGIK+u7GUeYd7NM6P6O8d2MxjHY8LXiLweizsXg2KUYdToT33r/5BPY0fmd4h/gDeo1+koA77DDC+PwMwZlM6vQUlwmcGAHZ/v1+l9vtJl3X6U+g+WibuTQSUY97f27SEDWMYkz3AAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Relative hearing sensitivity by frequency\"\n        title=\"Relative hearing sensitivity by frequency\"\n        src=\"/blog/static/00b8653b049ce7ffd5c6ea12d0319014/8ff1e/hearing_curve.png\"\n        srcset=\"/blog/static/00b8653b049ce7ffd5c6ea12d0319014/9ec3c/hearing_curve.png 200w,\n/blog/static/00b8653b049ce7ffd5c6ea12d0319014/c7805/hearing_curve.png 400w,\n/blog/static/00b8653b049ce7ffd5c6ea12d0319014/8ff1e/hearing_curve.png 800w,\n/blog/static/00b8653b049ce7ffd5c6ea12d0319014/6ff5e/hearing_curve.png 1200w,\n/blog/static/00b8653b049ce7ffd5c6ea12d0319014/d010d/hearing_curve.png 1296w\"\n        sizes=\"(max-width: 800px) 100vw, 800px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>The encoder cuts where it costs the least.</p>\n<p>You could ask why it doesn’t cut bass instead. Low frequencies take very few bits to encode, and you feel them as much as hear them. The top of the spectrum is the cheapest sacrifice by far.</p>\n<h2>What this looks like on real audio</h2>\n<p>Here’s a pop mix run through the old and new encoders. This plot shows the difference between the encoded audio and the original. Red means energy was removed, blue means the encoder added something that wasn’t there (artifacts).</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 800px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/blog/static/157586be3598d5e2edca5a5064ddaa13/f0f5e/error_comparison.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 35.7976653696498%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAABcSAAAXEgFnn9JSAAABRklEQVQoz02Sy1KEMBBF+f9/0o0foGWVC1+DFMMMhHTeCQzgXDvBKV2cAjo3J02S6nK5IMSIKSWIU4fD+ytIDEhWwzuLbduwLAsij6cYIJoDDi/PoK5BogHBKCzrim/OXa9XVJFlRAQteqjjF2zflbBkiGs5nFhmjYYZB5j2E+7cQh9rUFvDygEuJDw8vsFbgyqxUHEwC+WxKVDXgvoT5CiwsnCaJlhFsDSWnJYChiQM17LEx4Sn+ly+KyEERikxjoykvVutC0rtv1OEWnGXpuCs5e1wO97x+AzBc/u+R2U40EuFMzMw6leW65m8f0Vod5ErEo9wIwRMvLe+qyFJocphYx3IWEhlWGhAWfpfOM9FcuNP5vfD4oU+7u8gOV+EnlfxIcI6D8vB/DT5nbtZ1wUzC/NNyAcYuJtC2InlhkzQpwHrtuIHCCoUvNDJG5YAAAAASUVORK5CYII='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Error comparison: old vs new encoder\"\n        title=\"Error comparison: old vs new encoder\"\n        src=\"/blog/static/157586be3598d5e2edca5a5064ddaa13/8ff1e/error_comparison.png\"\n        srcset=\"/blog/static/157586be3598d5e2edca5a5064ddaa13/9ec3c/error_comparison.png 200w,\n/blog/static/157586be3598d5e2edca5a5064ddaa13/c7805/error_comparison.png 400w,\n/blog/static/157586be3598d5e2edca5a5064ddaa13/8ff1e/error_comparison.png 800w,\n/blog/static/157586be3598d5e2edca5a5064ddaa13/6ff5e/error_comparison.png 1200w,\n/blog/static/157586be3598d5e2edca5a5064ddaa13/2f950/error_comparison.png 1600w,\n/blog/static/157586be3598d5e2edca5a5064ddaa13/f0f5e/error_comparison.png 1799w\"\n        sizes=\"(max-width: 800px) 100vw, 800px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>The new encoder (right) makes one clear sacrifice: a red band at the top where it deliberately cut. Below that, almost nothing. The old encoder (left) is a different story: speckled red through the upper mids (signal lost in the range you hear best) and blue patches in the low end (artifacts the encoder invented). It’s fighting everywhere at once.</p>\n<p>Here’s the same story as a bar chart, comparing the same encoder with and without its low-pass filter:</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 800px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/blog/static/52a47a37b8ec24261fe442b676b2c75a/a4662/error_by_band.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 39.65986394557823%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAABcSAAAXEgFnn9JSAAABhklEQVQoz22RaU/CQBCG+7/1k4FoNBijJuIRvPAsjdYoKvIB5UgQNSHGaIwhEgUPqLScpe3u6+7SGlAnmcx0dvbpuzOSZVkghIAbpRSe8Vx8ikjBO2i1Alp6Bdz+tlbDe/EFn6xeLpeh6zqkbrf7ByhgcGHuGewuCpED3Ic20UhnekDTQq1mwDAMFmswTRNSp9MZAPZDCenl5peOJ+UQe4EVKOMhRCeXYdw9sBOC3yZpmjYAo64qD9x+LuJsNgzFP4/diRUcBJYhjy0hNrOO+20VjUZb9BH3zr9P9uwte4Oj6TAiTBUHKYFVqEylyqGBNfaTIE7DUdiO4w2+B+wHEdtBq/SGzM4x5KEpbPgXIfvmIY/MYcu3gAhTKvuC2Gb1vdFFhIenkdhPoNmx4LARSXzLbTbHplGH9sG29VhAPp5GSo3j6jSJXCyN61hKOM9zJxfCsydJES+jCWSi58hf3kJvsaVwVQ6TbNs2OJzL9/RS1ytfVVS0KvS68VOjYiXUdcIYtnjpN7WvRwOLpPuUAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Error by frequency band\"\n        title=\"Error by frequency band\"\n        src=\"/blog/static/52a47a37b8ec24261fe442b676b2c75a/8ff1e/error_by_band.png\"\n        srcset=\"/blog/static/52a47a37b8ec24261fe442b676b2c75a/9ec3c/error_by_band.png 200w,\n/blog/static/52a47a37b8ec24261fe442b676b2c75a/c7805/error_by_band.png 400w,\n/blog/static/52a47a37b8ec24261fe442b676b2c75a/8ff1e/error_by_band.png 800w,\n/blog/static/52a47a37b8ec24261fe442b676b2c75a/6ff5e/error_by_band.png 1200w,\n/blog/static/52a47a37b8ec24261fe442b676b2c75a/a4662/error_by_band.png 1470w\"\n        sizes=\"(max-width: 800px) 100vw, 800px\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<p>With the filter off (red), error rate is higher across the mid-range, right where your ears are sharpest. With the filter on (blue), those bands get more bits and the error drops. The filter is doing exactly what it should: trading the indiscernible top for a cleaner middle.</p>\n<h2>But what about 256 kbps?</h2>\n<p>This is a fair question. At 256 kbps there are nearly enough bits for everything. You’d expect full bandwidth to work fine. And it almost does.</p>\n<p>But “almost” still leaves the encoder making hard choices in the mid-range on complex passages. The encoder we use (libfdk_aac, Fraunhofer’s implementation) is conservative: even at 256 kbps it applies a gentle rolloff around 17 kHz. The improvement is smaller than at lower bitrates, but it’s still measurable.</p>\n<p>Is this the right call at 256 kbps? Genuinely debatable. But it’s not arbitrary. Fraunhofer validated these cutoff points with extensive listening tests over decades. The threshold exists because trained listeners couldn’t reliably tell the difference, and the freed bits made the rest of the signal measurably better.</p>\n<h2>Listen and Decide</h2>\n<p>We can show you graphs all day. Here’s a blind test instead. Three clips of the same audio. The original and two encoded at 256 kbps: one with the low-pass filter, one without. Can you tell which is which? Which has the low-pass filter applied?</p>\n<div id=\"listening-test\"></div>\n<h2>The bottom line</h2>\n<p>Your track isn’t broken. It just sounds better than it looks.</p>","fields":{"teaserPlainText":null},"frontmatter":{"title":"Less Is More: Why Audio on SoundCloud Looks Different","date":"June 18th, 2026","categories":["Audio","Engineering","Transcodings","Streaming"],"authors":[{"name":"Joe Reid","link":null}],"image":null}}},"pageContext":{"isCreatedByStatefulCreatePages":false,"slug":"less-is-more-why-soundcloud-low-passes-its-aac-transcodings","previous":{"fields":{"slug":"api-credentials-cli-openapi-github"},"frontmatter":{"permalink":"api-credentials-cli-openapi-github","title":"API Credentials from Your Terminal, and OpenAPI on GitHub","categories":["API","Announcement"],"authors":[{"name":"Danny Preussler","link":null}]}},"next":null}}}