Generating and drawing sin wave using pygame

Viewed 147

I am trying to generate and draw a sin waves. I am using this formulae that I found online y = Amp * sin(2 * PI * frequency * time + shift)

import pygame
import math
import time

window = pygame.display.set_mode((600, 600))

class Point:
    def __init__(self):
        self.x = 0
        self.y = 0

class Line:
    def __init__(self):
        self.points = []

def generateLine(startX, nPoints, length, y):
    line = Line()
    for i in range(nPoints):
        p = Point()
        p.x = startX + ((i / nPoints) * length)
        p.y = y
        line.points.append(p)
    return line;

nPoints = 100
line = generateLine(10, nPoints, 590, 300)
start = time.time()
accNPoints = 0
frequency = 100
amplitude = 30
overallY = 300

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()

    window.fill((255, 255, 255))

    keys = pygame.key.get_pressed()
    
    if (keys[pygame.K_a]): frequency -= 0.002
    if (keys[pygame.K_d]): frequency += 0.002

    if (keys[pygame.K_s]): amplitude -= 0.05
    if (keys[pygame.K_w]): amplitude += 0.05

    if (keys[pygame.K_q]): overallY += 0.5
    if (keys[pygame.K_e]): overallY -= 0.5

    if (keys[pygame.K_p]): accNPoints += 0.5
    if (keys[pygame.K_o]): accNPoints -= 0.5

    if accNPoints > 50:
        line = generateLine(10, nPoints, 590, 300)
        accNPoints = 0
        nPoints += 1
    elif accNPoints < -50:
        line = generateLine(10, nPoints, 590, 300)
        accNPoints = 0
        nPoints -= 1

    for i in range(1, len(line.points)):
        #calculate y based on x
        #y = A * sin(2 * PI * f * t + shift)
        #yStart = (amplitude * math.sin(2 * math.pi * frequency * ((time.time() - start) * 0.01) + line.points[i].x))     + overallY
        #yEnd =   (amplitude * math.sin(2 * math.pi * frequency * ((time.time() - start) * 0.01) + line.points[i - 1].x)) + overallY
        yStart = (amplitude * math.sin(2 * math.pi * frequency + line.points[i].x))     + overallY
        yEnd =   (amplitude * math.sin(2 * math.pi * frequency + line.points[i - 1].x)) + overallY

        
        pygame.draw.circle(window, (255, 0, 0), (line.points[i].x, yStart), 1)
        pygame.draw.circle(window, (255, 0, 0), (line.points[i - 1].x, yEnd), 1)
            
        pygame.draw.aaline(
            window,
            (0, 0, 0),
            (line.points[i].x, yStart),
            (line.points[i - 1].x, yEnd)
            )

    
    pygame.display.flip()

There seems to be two problems. Changing frequency value does not really seem to change the frequency of the wave. Frequency seems to be dependent on the nPoints variable which is in the function that generates line i.e. def generateLine(startX, nPoints, length, y):.

1 Answers

The formula is wrong. The x-coordinate depends on the control variable of the loop (i). The y-coordinate needs to depend on the x-coordinate:

e.g.: Frequency 5 (5 waves)

frequency = 5
amplitude = 50
overallY = 300

while True:
    # [...]

    no_pts = window.get_width()
    for i in range(no_pts):
        x = i/no_pts * 2 * math.pi
        y = (amplitude * math.cos(x * frequency)) + overallY
        if i > 0:
            pygame.draw.aaline(window, (0, 0, 0),  prev_pt, (i, y))
        prev_pt = (i, y)

    # [...]

Related