7
\$\begingroup\$

The Challenge

Generate 1 sec of an 8 bit tone sampled at 256 samples per second. The tone will be made up of a number of sine waves. The frequency of each sine wave will be determined from the input data.

These are deep tones, too low for a human to perceive, but I've chosen 8 bit numbers here since it's code-golf.

The Input

You will receive an array (or a list) of (non-negative) 8 bit signed integer values (0-127), each number will represent a frequency. An empty list is allowed and numbers may appear more than once in the list. All input frequencies must be assumed to be equal in amplitude.

The Output

Your program or function must output an array (or list) of 8 bit signed integer values that represents the signal generated.

Some graphical examples follow, but the actual output of your program is to be a list of integers. Not a graph and not a stream of bytes.

Also, your output must be normalized. That is, it must fill the window of possible values from -128 to 127. In other words, if you calculate a signal and its [min,max] is [-64,63], then you must amplify (multiply) the entire signal ×2. A flat signal will be all zeros. There should be no DC component in any output signal (ie. the average value should be 0). Since most (practically all) generated signals will be symmetrical then most likely your normalized signal will never contain a -128.

enter image description here

The actual expected output of these datasets are as follows:

[]                                    => [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
[2]                                   => [0,6,12,18,24,30,36,42,48,54,59,65,70,75,80,85,89,94,98,102,105,108,112,114,117,119,121,123,124,125,126,126,127,126,126,125,124,123,121,119,117,114,112,108,105,102,98,94,89,85,80,75,70,65,59,54,48,42,36,30,24,18,12,6,0,-6,-12,-18,-24,-30,-36,-42,-48,-54,-59,-65,-70,-75,-80,-85,-89,-94,-98,-102,-105,-108,-112,-114,-117,-119,-121,-123,-124,-125,-126,-126,-127,-126,-126,-125,-124,-123,-121,-119,-117,-114,-112,-108,-105,-102,-98,-94,-89,-85,-80,-75,-70,-65,-59,-54,-48,-42,-36,-30,-24,-18,-12,-6,0,6,12,18,24,30,36,42,48,54,59,65,70,75,80,85,89,94,98,102,105,108,112,114,117,119,121,123,124,125,126,126,127,126,126,125,124,123,121,119,117,114,112,108,105,102,98,94,89,85,80,75,70,65,59,54,48,42,36,30,24,18,12,6,0,-6,-12,-18,-24,-30,-36,-42,-48,-54,-59,-65,-70,-75,-80,-85,-89,-94,-98,-102,-105,-108,-112,-114,-117,-119,-121,-123,-124,-125,-126,-126,-127,-126,-126,-125,-124,-123,-121,-119,-117,-114,-112,-108,-105,-102,-98,-94,-89,-85,-80,-75,-70,-65,-59,-54,-48,-42,-36,-30,-24,-18,-12,-6]
[1,3]                                 => [0,8,16,24,32,39,47,54,61,68,75,81,87,93,98,103,107,111,115,118,120,123,124,126,126,126,126,126,125,123,121,119,116,113,110,106,102,98,94,89,84,79,74,69,64,59,54,49,44,39,35,30,26,22,18,15,12,9,7,4,3,1,0,0,0,0,0,1,3,4,7,9,12,15,18,22,26,30,35,39,44,49,54,59,64,69,74,79,84,89,94,98,102,106,110,113,116,119,121,123,125,126,126,127,126,126,124,123,120,118,115,111,107,103,98,93,87,81,75,68,61,54,47,39,32,24,16,8,0,-8,-16,-24,-32,-39,-47,-54,-61,-68,-75,-81,-87,-93,-98,-103,-107,-111,-115,-118,-120,-123,-124,-126,-126,-127,-126,-126,-125,-123,-121,-119,-116,-113,-110,-106,-102,-98,-94,-89,-84,-79,-74,-69,-64,-59,-54,-49,-44,-39,-35,-30,-26,-22,-18,-15,-12,-9,-7,-4,-3,-1,0,0,0,0,0,-1,-3,-4,-7,-9,-12,-15,-18,-22,-26,-30,-35,-39,-44,-49,-54,-59,-64,-69,-74,-79,-84,-89,-94,-98,-102,-106,-110,-113,-116,-119,-121,-123,-125,-126,-126,-126,-126,-126,-124,-123,-120,-118,-115,-111,-107,-103,-98,-93,-87,-81,-75,-68,-61,-54,-47,-39,-32,-24,-16,-8]
[15,14,13,12,11,10,9,8,7,6,5,4,3,2,1] => [0,32,63,89,109,122,126,124,114,100,82,62,43,26,13,4,0,0,3,9,16,24,30,35,37,36,33,27,21,14,8,3,0,-1,0,2,6,10,15,18,21,21,21,18,15,10,6,2,0,-1,-1,0,1,5,8,11,13,15,15,14,11,8,5,2,0,-1,-2,-1,0,1,4,6,9,10,11,11,9,7,5,2,0,-1,-2,-3,-2,0,1,3,6,7,8,9,8,6,4,2,0,-1,-3,-3,-3,-2,0,1,3,5,6,7,7,6,4,2,0,-2,-3,-4,-4,-4,-2,0,1,3,4,5,5,5,4,2,0,-2,-4,-5,-5,-5,-4,-3,-1,0,2,4,4,4,3,2,0,-2,-4,-6,-7,-7,-6,-5,-3,-1,0,2,3,3,3,1,0,-2,-4,-6,-8,-9,-8,-7,-6,-3,-1,0,2,3,2,1,0,-2,-5,-7,-9,-11,-11,-10,-9,-6,-4,-1,0,1,2,1,0,-2,-5,-8,-11,-14,-15,-15,-13,-11,-8,-5,-1,0,1,1,0,-2,-6,-10,-15,-18,-21,-21,-21,-18,-15,-10,-6,-2,0,1,0,-3,-8,-14,-21,-27,-33,-36,-37,-35,-30,-24,-16,-9,-3,0,0,-4,-13,-26,-43,-62,-82,-100,-114,-124,-127,-122,-109,-89,-63,-32]
[3,5,7,11,13,17,23]                   => [0,47,88,115,126,123,107,86,65,48,38,35,36,38,38,35,29,21,14,12,14,22,32,40,45,43,34,20,3,-10,-19,-22,-17,-10,-2,0,-3,-14,-30,-48,-60,-64,-56,-36,-7,22,49,66,70,60,40,14,-11,-31,-42,-44,-38,-29,-20,-14,-12,-14,-19,-23,-25,-23,-19,-14,-12,-14,-20,-29,-38,-44,-42,-31,-11,14,40,60,70,66,49,22,-7,-36,-56,-64,-60,-48,-30,-14,-3,0,-2,-10,-17,-22,-19,-10,3,20,34,43,45,40,32,22,14,12,14,21,29,35,38,38,36,35,38,48,65,86,107,123,126,115,88,47,0,-47,-88,-115,-126,-123,-107,-86,-65,-48,-38,-35,-36,-38,-38,-35,-29,-21,-14,-12,-14,-22,-32,-40,-45,-43,-34,-20,-3,10,19,22,17,10,2,0,3,14,30,48,60,64,56,36,7,-22,-49,-66,-70,-60,-40,-14,11,31,42,44,38,29,20,14,12,14,19,23,25,23,19,14,12,14,20,29,38,44,42,31,11,-14,-40,-60,-70,-66,-49,-22,7,36,56,64,60,48,30,14,3,0,2,10,17,22,19,10,-3,-20,-34,-43,-45,-40,-32,-22,-14,-12,-14,-21,-29,-35,-38,-38,-36,-35,-38,-48,-65,-86,-107,-123,-127,-115,-88,-47]
[1,1,2,3,5,8,13,21,34]                => [0,52,88,99,90,75,68,73,84,92,88,74,60,56,67,87,104,104,85,55,30,25,43,73,101,112,105,85,66,57,58,59,51,34,14,4,15,46,87,118,127,112,84,60,50,56,68,73,64,45,27,18,23,32,36,24,1,-21,-28,-11,26,70,103,114,103,83,66,61,63,63,53,34,13,4,13,36,59,68,54,23,-8,-27,-24,-6,14,23,15,-2,-20,-28,-25,-19,-21,-34,-52,-62,-51,-17,31,77,103,104,88,68,57,60,69,74,67,49,32,24,31,45,54,47,23,-7,-29,-29,-6,26,55,64,54,32,12,1,0,-1,-12,-32,-54,-64,-55,-26,6,29,29,7,-23,-47,-54,-45,-31,-24,-32,-49,-67,-74,-69,-60,-57,-68,-88,-104,-103,-77,-31,17,51,62,52,34,21,19,25,28,20,2,-15,-23,-14,6,24,27,8,-23,-54,-68,-59,-36,-13,-4,-13,-34,-53,-63,-63,-61,-66,-83,-103,-114,-103,-70,-26,11,28,21,-1,-24,-36,-32,-23,-18,-27,-45,-64,-73,-68,-56,-50,-60,-84,-112,-126,-118,-87,-46,-15,-4,-14,-34,-51,-59,-58,-57,-66,-85,-105,-112,-101,-73,-43,-25,-30,-55,-85,-104,-104,-87,-67,-56,-60,-74,-88,-92,-84,-73,-68,-75,-90,-99,-88,-52]

Additional Rules

All component frequencies are to begin at 0° phase. Basically, that means that they should start at 0 proceed to +127 at 90°, 0 again at 180°, -127 at 270° and then back to 0 at 360°.

It is acceptable if your outputs are slightly different due to rounding, from the examples posted here. They should be normalized to fill (or nearly fill) the range of possible signed ints (-128..127).

The usual loopholes are prohibited.

This is , shortest code wins.

IMPORTANT!

Practically everybody has made the same mistake in this challenge. 128 is NOT a valid signed 8 bit integer. You should not have output that contains this number or any number over 128.

\$\endgroup\$
15
  • 2
    \$\begingroup\$ I recall one of my Physics teachers saying, on many occasion, that sec is not an abbreviation of second and to use the correct abbreviation, s. \$\endgroup\$ Jun 2, 2017 at 3:38
  • 1
    \$\begingroup\$ an array of 8 bit signed integers vs. not a stream of bytes. In some languages (e.g. c) an array of 8 bit signed integers is exactly the same as a stream of bytes. Can that be resolved? \$\endgroup\$ Jun 2, 2017 at 3:53
  • 1
    \$\begingroup\$ The statements "...must fill the window of possible values from -128 to 127" and "...at 0 proceed to +127 at 90°, 0 again at 180°, -127 at 270° and then back to 0 at 360°." are in conflict. I imagine it would be kindest to the developers to allow -128 to be left out if they wish. \$\endgroup\$ Jun 2, 2017 at 4:06
  • 1
    \$\begingroup\$ @Jonathan, well, almost all of these generated signals will be (nearly) symmetrical so I don't see -128 appearing very often if at all. normalization should not normally add a dc component, but I'll clarify \$\endgroup\$
    – Octopus
    Jun 2, 2017 at 4:33
  • 1
    \$\begingroup\$ your output must be normalized. That is, it must fill the window of possible values from -128 to 127 This contradicts the result for empty input. Can you clarify? Or maybe not consider empty input at all? \$\endgroup\$
    – Luis Mendo
    Jun 2, 2017 at 8:54

7 Answers 7

3
\$\begingroup\$

Python 3, 119 bytes

from math import*
def f(a):b=[sum(sin(m*i*pi/128)for m in a)for i in range(256)];return[127*x//(max(*b)or 1)for x in b]

Try it online!

\$\endgroup\$
8
  • 1
    \$\begingroup\$ 2*pi/256 -> pi/128 \$\endgroup\$ Jun 2, 2017 at 4:48
  • \$\begingroup\$ instead of m*i*2*pi/256, why not m*i*pi/128? \$\endgroup\$
    – Octopus
    Jun 2, 2017 at 4:48
  • \$\begingroup\$ Save four bytes by writing the function on a single line. \$\endgroup\$ Jun 2, 2017 at 5:01
  • \$\begingroup\$ Save five more more using c=max(*b)or 1 and 127*x//c \$\endgroup\$ Jun 2, 2017 at 5:07
  • \$\begingroup\$ @JonathanAllan how to write the function on a single line? The return statement cannot start at the middle, and I cannot convert the function into a lambda. \$\endgroup\$
    – Leaky Nun
    Jun 2, 2017 at 5:18
3
\$\begingroup\$

Jelly, 23 28 bytes

Ṁ1Ṁ?
⁹Ḷµ×³×ØP÷⁹ḤÆSSµ€µ×127:Ç

Try it online!

+5 bytes for handling input []

All rounding errors are within +/- 2.

How it works

Ṁ1Ṁ?  - helper link, returns the maximum of a list unless the maximum is 0, where it returns 1                  
  Ṁ?  - if the maximum is truthy:
Ṁ     - return the maximum. Else:
 1    - return 1.

⁹Ḷµ×³×ØP÷⁹ḤÆSSµ€µ×127:Ṁ - main link, nilad
⁹Ḷ                      - the literal [0,1,2,3,...,254,255]
  µ           µ€        - compute the relative amplitude for each using the chain:
   ׳                   - multiply each element frequency by x
     רP÷⁹Ḥ             - scale because the sine function uses degrees.
           ÆS           - take the sine
             S          - return the sum of the list of sines of component waves.
                µ×127:Ç - scale to 127, with divison by 0 handled by the helper link
\$\endgroup\$
2
  • 2
    \$\begingroup\$ This does not give the desired result for empty input \$\endgroup\$
    – Luis Mendo
    Jun 2, 2017 at 8:39
  • \$\begingroup\$ 26 bytes Ṁ1Ṁ? doesn't need it's own line \$\endgroup\$
    – dylnan
    Apr 6, 2018 at 17:08
2
\$\begingroup\$

MATL, 34 bytes

Oh!8W:q7W/YP**Y,XstX:X>|a?1M/127*k

Try at MATL online!. Or add code XG to see a plot.

\$\endgroup\$
2
  • \$\begingroup\$ This is good, but see the IMPORTANT! addendum I added. \$\endgroup\$
    – Octopus
    Jun 2, 2017 at 17:00
  • \$\begingroup\$ @Octopus Thanks, corrected now \$\endgroup\$
    – Luis Mendo
    Jun 2, 2017 at 19:15
1
\$\begingroup\$

TI-BASIC, 47 41 48 bytes

-6 thanks to @Octopus

+7 for handling 0

:Prompt Y                         //Get list of inputs, 3 bytes
:"sum(sin(XʟY→Y₁                  //Store sum of sines function to Y₁, 10 bytes
:Y₁(128ֿ¹πseq(B,B,0,255           //Use the function to compute the values at 256 points, 20 bytes
:iPart(127Ans/max({1ᴇ~9,max(Ans   //Normalize values and round, 8 bytes

This will not work for empty input, since TI-BASIC will never accept empty input (see here).

GIF:

enter image description here

\$\endgroup\$
5
  • \$\begingroup\$ How does this take input then? What if I give it [] or 0? \$\endgroup\$
    – Octopus
    Jun 2, 2017 at 18:27
  • \$\begingroup\$ I'll add a .gif. \$\endgroup\$ Jun 2, 2017 at 18:27
  • \$\begingroup\$ If you give it a list with with a zero {0}, it'll work... \$\endgroup\$ Jun 2, 2017 at 18:28
  • \$\begingroup\$ I think you'll find that since the signals are always symmetrical, finding just the max is sufficient in the last line \$\endgroup\$
    – Octopus
    Jun 2, 2017 at 18:28
  • \$\begingroup\$ @Octopus K, thanks. \$\endgroup\$ Jun 2, 2017 at 18:32
1
\$\begingroup\$

Perl 6, 101 bytes

{my @w=[Z+] |(0 xx 256 xx 2),|.map:
(^256 »/»(128/π/*))».sin;(@w »*»(127/(@w.max||1)))».floor}

The frequencies are taken from the single list passed to this anonymous function.

\$\endgroup\$
1
\$\begingroup\$

Mathematica, 75 bytes

(m=MaxValue[f=Tr[Sin[x/128Pi#]&/@#],x]+.1^9;Round[127f/m]~Table~{x,0,255})&

Try the code online at https://sandbox.open.wolframcloud.com.

Explanation:

            f=Tr[Sin[x/128Pi#]&/@#]                                         Define expression f contains variable x equal to the frequency
                                                                               as x runs from 0 to 256 (x/128Pi runs from 0 to 2Pi)
 m=MaxValue[                       ,x]                                      Find the maximum of f
                                      +.1^9                                 Avoid case of empty list when m=0
                                            Round[127f/m]                   Normalize value of f to correct range
                                                         ~Table~{x,0,255}   and make a table of the value.

Notes:

  1. Using MaxValue instead of NMaxValue may have some symbolic issues, which is displayed as warning.
  2. It can be proved that the function have MaxValue + MinValue == 0, so it is not necessary to calculate MinValue.
  3. To run the code, put [{1,3}] for example after the code for input {1,3} and press Shift+Enter on Wolfram Sandbox.
  4. Although the code produce exact result, it is not mathematically correct due to the bad way of handle empty input case. This version (78 bytes) is better.

(m=MaxValue[f=Tr[Sin[x/128Pi#]&/@#],x];Round[127f/m]~Table~{x,0,255}/.0/0->0)&

or (80 bytes)

(m=MaxValue[f=Tr[Sin[x/128Pi#]&/@#],x];If[m<1,0,Round[127f/m]]~Table~{x,0,255})&

This works because it can be proven that the maximum is at least 1 for all non-empty input.

\$\endgroup\$
11
  • \$\begingroup\$ Please do post an online IDE link \$\endgroup\$ Jun 2, 2017 at 4:08
  • \$\begingroup\$ ...how do we call the function? \$\endgroup\$ Jun 2, 2017 at 4:39
  • \$\begingroup\$ I'm with John. I can't figure out how to use the wolfram sandbox. Please tell us what to paste in (including an input sample) and what to do to make it go. \$\endgroup\$
    – Octopus
    Jun 2, 2017 at 4:59
  • \$\begingroup\$ Does this handle empty input correctly? It should produce an array of zeros \$\endgroup\$
    – Luis Mendo
    Jun 2, 2017 at 16:28
  • \$\begingroup\$ The format I see output in the sandbox isn't the format asked for in the challenge, unless I did something wrong? \$\endgroup\$
    – Octopus
    Jun 2, 2017 at 17:03
1
\$\begingroup\$

Ruby, 102 bytes

->r{(o=(0..255).map{|i|r.sum{|n|Math::sin(0.024544*i*n)}}).map{|f|(f*127/[1,*o].map(&:abs).max).to_i}}

Try it online!

I know this is a slightly old one, but it looked like fun. The margin of error (for the given tests, anyway) is within ±1.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.